Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Extending the theme custom menu: Difference between revisions

From MoodleDocs
(New page: {{Template:Themes}}{{Moodle 2.0}}This is a quick tutorial that will quickly run you through extending the custom menu by overriding your theme's renderer. This tutorial is primarily PHP co...)
(No difference)

Revision as of 02:55, 9 September 2010

Moodle 2.0

This is a quick tutorial that will quickly run you through extending the custom menu by overriding your theme's renderer. This tutorial is primarily PHP coding, and is a moderate difficulty.

Before we begin

First things first you need to know a little something about the custom menu. As you are undoubtedly aware the custom menu is populated from a specially crafted lines that you enter within the custommenu admin setting on the theme settings page under appearance in the settings block. Once the admin has entered the custom menu items into the setting and saved them the following steps are what they go through in order to be displayed:

  1. The theme calls $OUTPUT->custom_menu() which is the core_renderers method responsible for producing the custom menu.
  2. core_renderer::custom_menu() does the following:
    1. Checks to make sure the admin has added custom menu items.
    2. Creates a new custom_menu object. When the custom menu object is created it turns what ever the admin entered into a structured array of information.
    3. Calls core_renderer::render_custom_menu and gives it the custom_menu object.
  3. core_renderer::render_custom_menu is where the magic happens, it does the following.
    1. First it checks to make sure custom menu contains items.
    2. Initialises the JavaScript for the custom menu, this is the YUI3 menunode component.
    3. Creates the HTML base of the custom menu
    4. Then iterates through all of the items and calls the custom menu and passes them to another function that will turn them into HTML correctly.

I'm going to stop there, as there is no need at this point to go into any more detail. Don't worry if you are a little lost, it will get clearer as we start working through code.

In this tutorial will we look at how to extend the theme's renderer in two different way.

  1. Add a dynamic My Courses branch to the custom menu that will display all of the courses a user is enrolled in.
  2. Get the custom menu to fetch strings from the language files rather than just static strings you type, allowing for a translatable custom menu.

Before you start into this tutorial you should have read the following tutorials I have written, or at least have a good knowledge of the the Moodle 2.0 theme engine and Moodle development.

As this is a quick tutorial I am going to assume you have created a theme, tested it and got it all working, and are already well on your way to becoming a theme guru.

Because the pressure is on to get Moodle 2.0 out the door this will be a quick tutorial, please if you have any questions or need a hand ask in the theme's forum.

Getting started

Alright, as you have already have your theme ready to go preparation is pretty simple, we are going to go through and create (if you haven't already) the following files:

  • theme/themename/lib.php
  • theme/themename/renderers.php
  • theme/themename/lang/en/themename.php

Next step open up your themes config.php file and add the following configuration option to it (at the bottom): $THEME->rendererfactory = 'theme_overridden_renderer_factory';

If you've already got a custom renderer you will already have this line.

And thats it! now we move on to extending the custom menu.

Adding the My Courses branch

So the point of this extension is to add a My Courses branch to the end of the custom menu.

The plan is to have the my courses branch and then within that branch have an entry for every course the user is enrolled in, much the same as the my courses branch of the navigation.

In order to achieve this we need to add some items to the custom menu, the my courses branch and all of the courses within it. We can do this overriding the core_renderers render_custom_menu method, of more accuratly create our own render_custom_menu method that adds our items and then calls the original. Remember we only need to add items, we don't need to change what is being produced.

So within our renderer.php file add the following code: class theme_themename_core_renderer extends core_renderer {

   protected function render_custom_menu(custom_menu $menu) {
       // Our code will go here shortly
   }

}

So that is pretty simple right?!

Here we are defining our core_renderer which will contain our overridden method render_custom_menu which we have also defined there. Note the definition of the render_custom_menu must be the same as the original, this means it must be protected and it must take one argument custom_menu $menu.

Next step is to write the code for our render_custom_menu method. As stated above we want to add a branch and courses to the end of it which we can do with the following bit of code:

$mycourses = $this->page->navigation->get('mycourses');

if (isloggedin() && $mycourses && $mycourses->has_children()) {

   $branchlabel = get_string('mycourses');
   $branchurl   = new moodle_url('/course/index.php');
   $branchtitle = $branchlabel;
   $branchsort  = 10000;
   $branch = $menu->add($branchlabel, $branchurl, $branchtitle, $branchsort);
   foreach ($mycourses->children as $coursenode) {
       $branch->add($coursenode->get_content(), $coursenode->action, $coursenode->get_title());
   }

}

return parent::render_custom_menu($menu);

So how this all works.... $mycourses = $this->page->navigation->get('mycourses'); This line is a little bit of smarts, what we are doing is getting the mycourses branch from the navigation. We could make all of the database calls and work it all out ourselves but this will be much better for performance and is easier!

The next line of code is an if statement that checks three things

  1. The user is logged in, you must be logged in to see your courses.
  2. That we have a mycourses object, if the user isn't enrolled in anything they won't have a mycourses object.
  3. The the mycourses object has children, if it exists it should but it is better to be safe than get errors.

Within the if statement we are doing two main things happening, the first is to add the branch to the menu: $branchlabel = get_string('mycourses'); $branchurl = new moodle_url('/course/index.php'); $branchtitle = $branchlabel; $branchsort = 10000;

$branch = $menu->add($branchlabel, $branchurl, $branchtitle, $branchsort); When adding a new branch we need to give it three things:

  1. A label $branchlabel.
  2. A URL $branchurl.
  3. A title $branchtitle in this case I have just set it to the same as $branchlabel because I am lazy, you can make it anything you want.
  4. A sort order $branchsort this just needs to be high enough that it ends up on last place where we want it. Make it small to put it at the front.

The final line of code from above simply adds it to the menu and collects a reference to it so that we can add courses to it.

The second thing being done in the if statement is iterate through all of the courses in the mycourses object and add them to the branch. That is done with the following bit of code: foreach ($mycourses->children as $coursenode) {

   $branch->add($coursenode->get_content(), $coursenode->action, $coursenode->get_title());

} So here we go through all of the mycourses objects children (which we know will be courses) and for each one we add an item to the branch. When adding items here, like above, we need to give it the following:

  1. A label $coursenode->get_content() returns us the text in the navigation node.
  2. A url $coursenode->action which is the URL for the node.
  3. A title $coursenode->get_title().

In this case we don't need to set a sort order because the navigation has already ordered them correctly!

So now we are through the if statement and there is only one line of code left: return parent::render_custom_menu($menu);

This line of code simply calls the original core_renderer::render_custom_menu method to do all of the remaining work. Because we don't need to change the display at all we don't need to redo what it does, we can just use it!.

How easy way that?! it's all done, if you open you site in your browser and log in the custom menu should now contain a my courses branch (providing you are enrolled in courses).

// Complete Code class theme_moodleofficial_core_renderer extends core_renderer {

   protected function render_custom_menu(custom_menu $menu) {
       global $USER;
       $mycourses = $this->page->navigation->get('mycourses');
       $courses = $this->page->navigation->get('courses');
       $navnode = ($mycourses)?$mycourses:($courses)?$courses:false;
       if (isloggedin() && $navnode && $navnode->has_children()) {
           $menunode = $menu->add(get_string('mycourses'), new moodle_url('http://moodle.org/forums/my/'), 'overviewmy', 10000);
           foreach ($navnode->children as $coursenode) {
               $menunode->add($coursenode->get_content(), $coursenode->action, $coursenode->get_title());
           }
       }
       return parent::render_custom_menu($menu);
   }

}