Create CSS classes based on user role

Create CSS classes based on user role

by orion rush -
Number of replies: 7

Working with Moodle 3.9 and a fork of the current Academi theme.

I am trying to create a css classes on the <body> element based on named user role(s). I understand that a user's role(s) are context-driven, (maybe a student in one course, and something else in another), so I would like to output all the roles as classes in a given context.

Based on some extensive digging on the forum I have the following:

content_copy
// User role based CSS classes
global $USER, $PAGE;
$context = context_system::instance();
$roles = get_user_roles($context, $USER->id, true);
if(is_array($roles)) {
    foreach($roles as $role) {
        $PAGE->add_body_class('role-'.$role->shortname);
    }
} else {
        $PAGE->add_body_class('role-none');
}

Preferably I'd like this to run on every page. From within the theme, I've tried just placing this in just about every location/function I thought could be executed early enough to modify the body element. Either I get no output at all or a warning indicating that it is too late to run add_body_class().

I've had read of the docs on the Page and Output APIs, as well as the Themes overview and RolesRoles FAQ and I still don't have a sense of how to effectively fetch get_user_roles and hook into add_body_class.

I've also had a bit of difficulty as a lot of the search results on these topics, here on the moodle forum, and Sackoverflow are quite dated, so Im not sure what current best practice is.

Could someone give me a nudge in the right direction?


Average of ratings: -
In reply to orion rush

Re: Create CSS classes based on user role

by Richard Oelmann -
Picture of Core developers Picture of Plugin developers Picture of Testers
If you're adding php like that to the theme, you almost certainly need to add it to your layout files - in the example linked below, you'd need to adjust your code to add the new classes to the $extraclasses array, somewhere between L35-36 or L38-39 - and similarly in the other layout files.
https://github.com/moodle/moodle/blob/master/theme/boost/layout/columns2.php#L35-L39
Average of ratings: Useful (1)
In reply to Richard Oelmann

Re: Create CSS classes based on user role

by orion rush -
Thanks, Richard, I will look into this, but editing this to every layout file seems a bit fragile, and isn't how I would imagine that add_body_class() would ideally work. I've been looking at Mark's response more deeply, as it seems to have the potential to get the job done, once I better understand how to hook into the correct context.
In reply to orion rush

Re: Create CSS classes based on user role

by Richard Oelmann -
Picture of Core developers Picture of Plugin developers Picture of Testers
I don't think I'd describe it as fragile at all. After all, it is exactly how Boost does it for the NavDrawer body classes and I've been using it in themes for quite a few years and none have ever broken on this.
But Mark's page init solution is also valid, so it's essentially upto you and how you prefer to work.
In reply to orion rush

Re: Create CSS classes based on user role

by Mark Sharp -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers

You add the code to a _page_init() function which, if it isn't already there can be put in your theme's lib.php

For example, for theme Academi, there's probably a lib.php file with the function theme_academi_page_init($page)

Put your code in there, you don't need to global the $PAGE variable, as that should be passed in to the function. Moodle will automatically call this function at the right time.

Average of ratings: Useful (1)
In reply to Mark Sharp

Re: Create CSS classes based on user role

by orion rush -
Hi Mark, thanks for the reply. In retrospect, I had played extensively with theme_academi_ppp_page_init(), however, I could not ever seem to retrieve any roles via get_user_roles(), it would only return an empty array. I've realized that this more had to do with my (mis)understanding of `context` than anything else.

The following doesn't work in all the contexts I'd envisioned, but it does work from within courses, which was my primary use case:

    function XXXXXX_page_init(moodle_page $page) {
      ...
      // Add user role name as CSS class 
      global $USER, $COURSE;
      $context = context_course::instance($COURSE->id);
      $roles = get_user_roles($context, $USER->id, true);
      if(is_array($roles)) {
          foreach($roles as $role) {
              $page->add_body_class('role-'.$role->shortname);
          }
      } else {
          $page->add_body_class('role-none');
      } 
    }



In reply to orion rush

Re: Create CSS classes based on user role

by orion rush -

Of course, once I posted, I discovered user_has_role_assignment(), which so long as you are using stock user roles, '5' equates to 'student'. There is a third param for context, but if it is left blank it applies to all contexts.

    function XXXXXX_page_init(moodle_page $page) {
      ...
      global $USER, $COURSE;

      if (user_has_role_assignment($USER->id,5)) {
          $page->add_body_class('role-student');
      }    
    }
ref: https://moodle.org/mod/forum/discuss.php?d=144704#p1117393

In reply to orion rush

Re: Create CSS classes based on user role

by Mark Sharp -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers

Yeah, so you need to decide where you are (the context) to decide if someone has a role in that context.

One way to do that is to query the $page->pagetype e.g.

if (strpos($page->pagetype, 'course-view') === 0) { }

In my version of this, the class name identifies the context:
$page->add_body_class('courserole-' . $role->shortname);
You can use other functions to get useful information:
  • isloggedin()
  • is_siteadmin()
  • is_enrolled()
  • is_viewing()
  • is_guest()
have fun.