Renderer best practices

Jump to: navigation, search
Renderer consistency
Project state Specification
Tracker issue https://tracker.moodle.org/browse/MDL-45853
Discussion https://moodle.org/mod/forum/discuss.php?d=261202
Assignee Damyon, Sam

Note: This page is a work-in-progress. Feedback and suggested improvements are welcome. Please join the discussion on moodle.org or use the page comments.


This page documents renderer best practices.

Notes

  • This document will be made obsolete by support for mustache templates instead of renderer methods. Everything becomes more natural because what you can and can't do in a renderer is dictated by the features of the template language.


  • Must mention atomic design and how the concept of "templates" should be applied. Relates to the next note. A forth method type for renderers?
  • Within a component or plugin that has a renderer use the renderer for EVERYTHING within that area. forum post that ignited this
  • Reference and probably copy the three render methods from [Guide to creating output elements]

Renderer best practices

This document discusses the recommended practises to follow when writing renderers for Moodle. It was created in Moodle 2.8 as part of the element library specification that took place.

Renderers provide an abstraction of logic and display. They serve Moodle to both encourage us to properly structure our code and to provide a means by which themes can take control of output to completely customise the look of Moodle. Elements and the element library provide us a set of building blocks to use when creating output. These provide us a consistent and manageable look that also minimising the amount of customisation required by a theme to change the look and feel of Moodle. Here we make a recommendation on how to write renderers to maximise the benefits to both yourself as a developer and to designers who have to customise the interfaces you create.

Goals

Its important to understand the goals for output before you start looking at renderers as they are just one part of the output plan.

Output in Moodle is designed to:

  • Aid developers in properly abstracting output from logic.
  • Allow designers to take complete control of output from within a theme if they wish.
  • Provide a consisten look and feel for Moodle user.
  • Allow developers to more rapidly create interfaces by having a set of elements at their finger tips.
  • Minimise the efforts designers must extrude in order to customise the look and feel of Moodle by limiting the output to a set of elements.
  • Aid designers by providing tools to support styling Moodle such as the element library.

Renderers in Moodle:

  • Are the link between Moodle and a theme through which all output is generated.
  • Are organised for the benefit of designers, and should be written following this document.
  • Most importantly allow designers to override the HTML that wraps the data being displayed in turn allowing designers to re-design output in a theme.
  • Allow designers to change the information being displayed by providing not just what is initially required but that which that may require.

A simple set of rules for a good renderer

Summarising what will be discussed further in this document a good renderer can be summarised as:

  • Think in elements. We have an element library, when planning the output for your plugin/component start with the elements in the element library and the markup they provide.
  • Containing only methods confroming to the four method types discussed below.
  • Encapsulated data is given, maximising the information available to the renderer and minimising the number of arguments.
  • Free of logic relating to anything except output. This includes not calculating the likes of links and capabilities.
  • Uses helper methods to manipulate data where manipulate is absolutely required, essentially abstracting logic to conform to the above rule.
  • Utilise the core elements as much as is possible.
  • Recognise unique output needs and create element(s) for it.
  • The render method should be used as often as possible to maximise consistent look.

The don'ts

The following are things that should not be done within a renderer.

DO NOT:

  • design interfaces from scratch when desiging output for your plugin/component. Always start with the elements found in the element library.
  • Use logic that isn't essential to producing output. This includes but is not limited to the following:
    • Database interaction of any kind.
    • Access or capability checks.
    • Generation of data such as producing URL's, that should be owned by the plugin/component and made available preferably through the given arguments or failing that through a helper method.
  • Generate HTML for something that should be an element, convert it to an element and call render on it.
  • Create custom elements for everything you plan to output, instead try to maximise the core elements that you use.
  • Write your own render methods for subelements of the elements you create. Only do this if you absolutely must change the markup from that produced by the natural render method for the element.

Creating a renderer

Location and naming

As of Moodle 2.8 renderers can be put into the output namespace. This is the recommended placement for Renderers in Moodle 2.8 and up, however the alternatives will also be listed here.

Recommended:

  • Put your renderer in mod/yourplugin/output/renderer.php use the namespace mod_yourplugin\output and call your class renderer.
  • To get an instance of your renderer $PAGE->get_renderer('mod_yourplugin')'

This is how mod/yourplugin/output/renderer.php will look:

<?php
 
namespace mod_yourplugin\output;
 
class renderer extends \plugin_renderer_base {
    // Your renderer methods in here.
}

Also available but not recommended:

  • Put your renderer in mod/yourplugin/renderer.php do NOT namespace it, and call your class mod_yourplugin_renderer.
  • To get an instance of your renderer $PAGE->get_renderer('mod_yourplugin')'

This was how things were done in earlier versions of Moodle (2.7 and below).

Render methods

Renderers can be well structured, the purpose of them is the same across all plugins and components. There are four distinct types of render methods that you can expect to find in a renderer, and these four can be categorised into one of two categories.

The four types of render methods:

  1. Layout methods
  2. Translator methods
  3. Render methods
  4. Convenience methods

These four methods can then be categorised in two ways:

Plugin|Component method 
The layout and translator methods are plugin or component methods. They take data for a plugin or component and meld it into renderables. These methods relate to and can be said to be owned by the plugin or component.
Element methods 
The render and convenience methods relate only to elements. They take already encapsulated abstracted data and simply output HTML structure around it. They pay no regard to the plugin or component and are completely and solely bound to the output of an element.

Layout methods

Translator methods

Render methods

If you've spent any time working with renderers in the past you will already be familiar with the concept of a render method. All elements within Moodle inherit the renderable interface. To produce output for them you call the renderers render method and give the element. The render method looks at what is given and looks

Convenience methods

These are very simple. A convenience method is simply an easy way to build and output an element in a single step. If you take an element, likely an atom or molecule, a convenience method would have the same arguments as the constructor for the element, build an instance of the element and call render on it. The following is a simple example using heading:

/**
 * A convenience method to render a heading.
 */
public function heading($content, $level = 2) {
    $heading = new \core\output\heading($content, $level);
    return $this->render($heading);
}

Creating output elements

This is a big field and as such a dedicated document has been writen as a Guide to creating output elements.

Tips on properly structuring your plugin

Talk here about OO structuring of code, ensuring a traversable heirarchy that enables maximum movement of code structure to obtain data and in turn minimises necessary arguments for layout methods.

See also