Moodle Theme Development : “Logged in as” Breadcrumbs

Moodle Theme Development : “Logged in as” Breadcrumbs

This post is part of a series documenting the work I did while developing a new Moodle Theme for Dumfries and Galloway College’s VLE. There will be further posts to follow. Watch this space!

As part of the design I wanted to display the “logged in as” information in a visually appealing way. For anyone not familiar with the log in as option, in Moodle certain user roles can preview courses as a different role e.g. as a Student. I settled on displaying it as a set of arrows across the top of the footer (see screenshot) rather than an un-styled block of text which was buried in the footer of the default theme boost.

Screenshot of the VLE footer

For the style of the breadcrumb arrows I reused my SVG clip-path Breadcrumb SCSS and HTML that I wrote earlier in the year for another project. See the link below for an overview of the SCSS.

Modifying the Footer Mustache File and Theme Renderers

To achieve this I needed to modify the mustache template file footer.mustache as well as write a renderer override in our theme. I based the new theme as a child version of the default Boost theme.

To override the footer.mustache file in boost I had to create a new footer.mustache file in our theme templates folder. This started out as a copy of the boost theme’s footer.mustache.

To figure out what renderer function I needed to find I ran a grep on my copy of moodle and discovered that the “Logged in as” information was being pulled into the footer.mustache file by the following line of code

{{{ output.login_info }}}

I tracked this down to coming from the login_info function in /lib/outputrenderers.php

/**
* Return the standard string that says whether you are logged in (and switched
* roles/logged in as another user).
* @param bool $withlinks if false, then don't include any links in the HTML produced.
* If not set, the default is the nologinlinks option from the theme config.php file,
* and if that is not set, then links are included.
* @return string HTML fragment.
*/
public function login_info($withlinks = null) {

    //...

}

This function also included a lot of information that also appeared in the footer which meant I needed to write an override renderer for login_info in our theme as well as an extra renderer to separate out the “Logged in as” information and display it separately.

I added the override and the new renderer to my theme renderers files ( theme_name/renderers.php ).

defined('MOODLE_INTERNAL') || die();

class theme_name_core_renderer extends core_renderer {

     /* ... */

}

The override of login_info was to start with a straight copy of the original function with the “Logged in as” part removed from it. To differentiate it from the original (and to make it easy to swap out if there were any issues) I renamed the override “footer_logininfo” and commented out any information I didn’t want to include in the footer itself. I also added in a few html elements to accommodate the breadcrumb styling. You may notice I have also changed some of the styling – this is due to another change to the footer that I may explain in a later post.

/**
     * Based on the login_info Function in /lib/outputrenderers.php 
     * The following changes have been made:
     *		$string['loggedinas'] changed in language package
			Logout link taken out of logged in link.
			Logged in as taken out to move into a new section
     *
     * Construct a user menu, returning HTML that can be echoed out by a
     * layout file.
     *
     * @param stdClass $user A user object, usually $USER.
     * @param bool $withlinks true if a dropdown should be built.
     * @return string HTML fragment.
     */
    public function footer_logininfo($withlinks = null) {
        global $USER, $CFG, $DB, $SESSION;

        if (during_initial_install()) {
            return '';
        }

        if (is_null($withlinks)) {
            $withlinks = empty($this->page->layout_options['nologinlinks']);
        }

        $course = $this->page->course;
        if (\core\session\manager::is_loggedinas()) {
            $realuser = \core\session\manager::get_realuser();
            $fullname = fullname($realuser, true);
            if ($withlinks) {
                $loginastitle = get_string('loginas');
                $realuserinfo = " [<a href=\"$CFG->wwwroot/course/loginas.php?id=$course->id&amp;sesskey=".sesskey()."\"";
                $realuserinfo .= "title =\"".$loginastitle."\">$fullname</a>] ";
                $realuserinfo = '';
            } else {
                $realuserinfo = " [$fullname] ";
                $realuserinfo = '';
            }
        } else {
            $realuserinfo = '';
        }

        $loginpage = $this->is_login_page();
        $loginurl = get_login_url();

        if (empty($course->id)) {
            // $course->id is not defined during installation
            return '';
        } else if (isloggedin()) {
            $context = context_course::instance($course->id);

            $fullname = fullname($USER, true);
            // Since Moodle 2.0 this link always goes to the public profile page (not the course profile page)
            if ($withlinks) {
                $linktitle = get_string('viewprofile');
                $username = "<a href=\"$CFG->wwwroot/user/profile.php?id=$USER->id\" title=\"$linktitle\"><span>$fullname</span></a>";
            } else {
                $username = $fullname;
            }
            
            if (is_mnet_remote_user($USER) and $idprovider = $DB->get_record('mnet_host', array('id'=>$USER->mnethostid))) {
                if ($withlinks) {
                    $username .= " from <a href=\"{$idprovider->wwwroot}\"><span>{$idprovider->name}</span></a>";
                } else {
                    $username .= " from {$idprovider->name}";
                }
            }
            
            if (isguestuser()) {
                $loggedinas = $realuserinfo.get_string('loggedinasguest');
                if (!$loginpage && $withlinks) {
                    $loggedinas .= " (<a href=\"$loginurl\">".get_string('login').'</a>)';
                }
            } else if (is_role_switched($course->id)) { // Has switched roles
                /*$rolename = '';
                if ($role = $DB->get_record('role', array('id'=>$USER->access['rsw'][$context->path]))) {
                    $rolename = ': '.role_get_name($role, $context);
                } */
                $loggedinas = get_string('loggedinas', 'moodle', $username).$rolename;
                /*if ($withlinks) {
                    $url = new moodle_url('/course/switchrole.php', array('id'=>$course->id,'sesskey'=>sesskey(), 'switchrole'=>0, 'returnurl'=>$this->page->url->out_as_local_url(false)));
                    $loggedinas .= ' ('.html_writer::tag('a', get_string('switchrolereturn'), array('href' => $url)).')';
                } */ // Going to move this to a seperate section.
            } else {
                $loggedinas = $realuserinfo.get_string('loggedinas', 'moodle', $username);
                /*if ($withlinks) {
                    $loggedinas .= " (<a href=\"$CFG->wwwroot/login/logout.php?sesskey=".sesskey()."\">".get_string('logout').'</a>)';
                } */
            }
        } else {
            $loggedinas = get_string('loggedinnot', 'moodle');
            if (!$loginpage && $withlinks) {
                $loggedinas .= " (<a href=\"$loginurl\">".get_string('login').'</a>)';
            }
        }

        //$loggedinas = '<div class="logininfo">'.$loggedinas.'</div>';

        if (isset($SESSION->justloggedin)) {
            unset($SESSION->justloggedin);
            if (!empty($CFG->displayloginfailures)) {
                if (!isguestuser()) {
                    // Include this file only when required.
                    require_once($CFG->dirroot . '/user/lib.php');
                    if ($count = user_count_login_failures($USER)) {
                        $loggedinas .= '<div class="loginfailures">';
                        $a = new stdClass();
                        $a->attempts = $count;
                        $loggedinas .= get_string('failedloginattempts', '', $a);
                        if (file_exists("$CFG->dirroot/report/log/index.php") and has_capability('report/log:view', context_system::instance())) {
                            $loggedinas .= ' ('.html_writer::link(new moodle_url('/report/log/index.php', array('chooselog' => 1,
                                    'id' => 0 , 'modid' => 'site_errors')), get_string('logs')).')';
                        }
                       $loggedinas .= '</div>';
                    }
                }
            }
        }

        return '<li>'.$loggedinas.'</li>';
    }

I then added a new renderer function called “footer_signedinas” which is where I moved the “logged in as” information to and added the necessary breadcrumb elements so I could use my clip path styling.

public function footer_signedinas($withlinks = null) {
        global $USER, $CFG, $DB, $SESSION;

        if (during_initial_install()) {
            return '';
        }
        
        if (is_null($withlinks)) {
            $withlinks = empty($this->page->layout_options['nologinlinks']);
        }
        
        if (\core\session\manager::is_loggedinas()) {
            $realuser = \core\session\manager::get_realuser();
            $fullname = fullname($realuser, true);
            if ($withlinks) {
                $loginastitle = get_string('loginas');
                $realuserinfo = '<li><a href="'.$CFG->wwwroot.'/course/loginas.php?id='.$course->id.'&amp;sesskey='.sesskey().'"';
                $realuserinfo .= ' title ="'.$loginastitle.'">'.$fullname.'</a></li>';
            } else {
                $realuserinfo = '<li><span>['.$fullname.']</span></li>';
            }
        } else {
            $realuserinfo = '';
        }
        
        $loggedinas = '';
		$course = $this->page->course; 
         
		if (isloggedin()) {
		
			$context = context_course::instance($course->id);
            $fullname = fullname($USER, true);
            //$linktitle = '';
            
            // Since Moodle 2.0 this link always goes to the public profile page (not the course profile page)
            if ($withlinks) {
                //$linktitle = get_string('viewprofile');
                $profilelink = $CFG->wwwroot.'/user/profile.php?id='.$USER->id;
                //$username = '<a href="'.$CFG->wwwroot.'/user/profile.php?id='.$USER->id.'" title="'.$linktitle.'">'.$fullname.'</a>';
                $username = $fullname;
            } else {
				
				$profilelink = '';
                $username = $fullname;
            }
            
            if (is_mnet_remote_user($USER) and $idprovider = $DB->get_record('mnet_host', array('id'=>$USER->mnethostid))) {
                if ($withlinks) {
					$profilelink = $idprovider->wwwroot;
                    $username .= " from {$idprovider->name}";
                } else {
					$profilelink = '';
                    $username .= " from {$idprovider->name}";
                }
            }
            
			if (is_role_switched($course->id)) { // Has switched roles
                $rolename = '';
                if ($role = $DB->get_record('role', array('id'=>$USER->access['rsw'][$context->path]))) {
                    $rolename = '<li><span>'.get_string('viewingasrole', 'theme_dgcollege2020', role_get_name($role, $context)).'</span></li>';
                    //viewingasrole
                }
                
                $loggedinas  = '<div class="switchedrole breadcrumb-wrapper bg-dorange-5" role="complementary" aria-label="Switch User Role Information">'.
									'<ul class="breadcrumbs">';
									
                $loggedinas .= (!empty($profilelink) ? '<li><a href="'.$profilelink.'">' : '<li><span>').get_string('loggedinas', 'moodle', $username).(!empty($profilelink) ? '</a></li>' : '</span></li>').$rolename;
                
                // signedinaslinktext
                
                if ($withlinks) {
                    $url = new moodle_url('/course/switchrole.php', array('id'=>$course->id,'sesskey'=>sesskey(), 'switchrole'=>0, 'returnurl'=>$this->page->url->out_as_local_url(false)));
                    $loggedinas .= '<li>'.html_writer::tag('a', get_string('switchrolereturn'), array('href' => $url, 'class' => '')).'</li>';
                } 
                
                $loggedinas .= '</ul></div>';
            } else if(\core\session\manager::is_loggedinas()) {
            
                $loggedinas  = '<div class="switchedrole bg-dorange-5" role="complementary" aria-label="Logged in as Information">'.
									'<ul class="breadcrumbs">';
                $loggedinas .= $realuserinfo.'<li><span>'.get_string('loggedinas', 'moodle', $username).'</span></li>';
                
                if ($withlinks) {
                    $loggedinas .= '<li><a href="'.$CFG->wwwroot.'/login/logout.php?sesskey='.sesskey().'">'.get_string('logout').'</a></li>';
                } 
                
                $loggedinas .= '</ul></div>';
            }
		}
		
		 return $loggedinas;
    
    }

Finally I needed to reference these new overrides in our theme’s footer.mustache file. This is done by adding {{{ output.function_name }}} this will fetch the output of those renderers.

{{{ output.footer_signedinas }}}
<footer id="page-footer" class="py-3 bg-dark text-light">
    <div class="container">
        /* ... */

        {{{ output.footer_logininfo }}}

       /* ... */
    </div>
</footer>

References

For more information on how to write a renderer override or modifying mustache template files check out these Moodle documentation pages.

Comments are closed.