Using Mahara/Writing Plugins/Room Badge

Setting up a Development Environment edit

Before you start writing a plugin, you must have a development environment running:

Plugin Overview edit

Here, we show how to create a very simple blocktype that will add a class signature to a Mahara page. The tutorial assumes some knowledge of web development and php programming but is okay for persons with no prior experience developing for Mahara (I started exploring Mahara a week ago).

In this tutorial, we will produce a plugin that let the user add a classroom badge on its page:

 

The user can change the background color and the rooom number.

The easiest way to create a new blocktype is to copy an existing one and adapt it. Go for an existing blocktype that is as similar as possible in functionality to the plugin you want to write, copy and paste the base blocktype folder and start adapting it.

Here, we will start with a copy of the creativecommons blocktype. Once copied, rename the new new folder to something appropriate. Here we will use roombadge as name.

At this stage, you should have a folder:

mahara/blocktype/roombadge

First thing to do is run some renaming, from creativecommons to roombadge.

Let's rename the files first.

  1. Get rid of the folder roombadge/js. Our plugin doesn't require any javascript.
  2. Rename the file roombadge/lang/en.utf8/help/blocktype.creativecommons to roombadge/lang/en.utf8/help/blocktype.roombadge.
  3. Delete the folder roombadge/lang/en.utf8/help.
  4. Delete the folder roombadge/theme/raw/static.

It's best to change thumb.png early on, possibly with a temporary replacement one. I have provided a thumb template that you can download and edit:  

Let's now replace some textual content. In mahara/blocktypes/roombadge, open lib.php in a text or code editor

class PluginBlocktypeCreativecommons extends SystemBlocktype {

replace it with:

class PluginBlocktypeRoomBadge extends SystemBlocktype {

The camel case name for the plugin must match the lowercase name of the folder (RoomBadge and blocktype/roombadge).


Code Comments edit

Edit the comments at the top of the page.

/*
 * @package    mahara
 * @subpackage blocktype-creativecommons
 * @author     Francois Marier <francois@catalyst.net.nz>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
 * @copyright  (C) 2009 Catalyst IT Ltd
*/

Replace it with:

/*
 * @package    mahara
 * @subpackage blocktype-roombadge
 * @author    My name <name@mail.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
 * @copyright  (C) 2011 Myself
*/

As you have finished editing the comments, copy and paste them to other php code files.

  1. roombadge/lang/en.utf8/blocktype.roombadge.php
  2. roombadge/version.php

Plugin Constants edit

Okay, let's start modifying the code now. This is not as bad as it sound. Let's go line by line and decide whether we are likely to need that bit of code or not.

    // Standard Creative Commons naming scheme
    const noncommercial = 'nc';
    const noderivatives = 'nd';
    const sharealike    = 'sa';

It may be a good idea to limit the color options. Let's provide four default colours. These values will in fact be saved in the Mahara database. The shorter the name, the better. Here a single letter is enough to differentiate the four colours.

    // Standard Color scheme
    const orange    = '#D74300';
    const red       = '#9E0013';
    const blue      = '#006CC9';
    const green     = '#0F9400';

Now, the function single_only. A value of true means that there should be no more than one such block per page. That makes sense for our room badge. Let's keep it like that.

    public static function single_only() {
        return true;
    }

Plugin Metadata edit

get_title and get_description return the title and description of the plugin, as displayed in the plugin menu, at the top of the page, when in edit mode.

    public static function get_title() {
        return get_string('title', 'blocktype.creativecommons');
    }
    public static function get_description() {
        return get_string('description', 'blocktype.creativecommons');
    }

We need to change creativecommons to roombadge

    public static function get_title() {
        return get_string('title', 'blocktype.roombadge');
    }
    public static function get_description() {
        return get_string('description', 'blocktype.roombadge');
    }

As we are at it, let's make a general search and replace on that page. Search for 'blocktype.creativecommons' and replace all with blocktype.roombadge.

But we also need to make sure that the value being returned are appropriate. Let's open the file roombadge/lang/en.utf8/blocktype.roombadge.php and let's look for the title and description tags:

$string['title'] = 'Creative Commons License';
$string['description'] = 'Attach a Creative Commons license to your view';
$string['blockcontent'] = 'Block Content';

$string['alttext'] = 'Creative Commons License';
$string['licensestatement'] = "This work is licensed under a <a rel=\"license\" href=\"%s\">Creative Commons %s 3.0 Unported License</a>.";
$string['sealalttext'] = 'This license is acceptable for Free Cultural Works.';

$string['config:noncommercial'] = 'Allow commercial uses of your work?';
$string['config:noderivatives'] = 'Allow modifications of your work?';
$string['config:sharealike'] = 'Yes, as long as others share alike';

$string['by'] = 'Attribution';
$string['by-sa'] = 'Attribution-Share Alike';
$string['by-nd'] = 'Attribution-No Derivative Works';
$string['by-nc'] = 'Attribution-Noncommercial';
$string['by-nc-sa'] = 'Attribution-Noncommercial-Share Alike';
$string['by-nc-nd'] = 'Attribution-Noncommercial-No Derivative Works';

We need to edit these string tags.

$string['title'] = 'Classroom Badge';
$string['description'] = 'Attach a Room badge to your view';
$string['blockcontent'] = 'Block Content';

$string['alttext'] = 'Classroom Badge';
$string['defaultlabel'] = 'Room 1';

$string['R'] = 'red';
$string['O'] = 'orange';
$string['B'] = 'blue';
$string['G'] = 'green';

Plugin Category edit

get_categories defines the tab under which the plugin appears, in the plugin menu at the top of the page, in view (page in Mahara1.4) edit mode.

    public static function get_categories() {
        return array('general');
    }

HTML render edit

render_instance defines who the block will appear to the user in normal view mode.

    public static function render_instance(BlockInstance $instance, $editing=false) {
        global $THEME;
        $configdata = $instance->get('configdata');
        if (!isset($configdata['license'])) {
            return '';
        }

        $licensetype = $configdata['license'];
        $licenseurl = "http://creativecommons.org/licenses/$licensetype/3.0/";
        $licensename = get_string($licensetype, 'blocktype.roombadge');

        $html = '<div class="licensedesc"><a class="fl" rel="license" href="http://creativecommons.org/licenses/'.$licensetype.'/3.0/"><img alt="'.
            get_string('alttext', 'blocktype.roombadge').
            '" style="border-width:0" src="'.
            $THEME->get_url('images/' . $licensetype . '-3_0.png', false, 'blocktype/creativecommons') . '" /></a>';
        $html .= '<div>';
        $html .= get_string('licensestatement', 'blocktype.roombadge', $licenseurl, $licensename);
        $html .= '</div></div>';
        return $html;
    }

Let's change the rendering to the one of a badge. It would be better to keep the CSS separate, but here that's not too much of an issue as the badge can be added once only on the page. Let's keep it this way for the sake of simplicity.

    public static function render_instance(BlockInstance $instance, $editing=false) {
        $configdata = $instance->get('configdata');

        // Display the badge only if both color and label are defined. The tags color and label are defined in instance_config_form
        if (!isset($configdata['color']) || !isset($configdata['label'])) {
            return '';
        }
        
        $badgecolor = $configdata['color'];
        $badgelabel = $configdata['label'];

        $html = '<div style=";border:1px solid '.$badgecolor.';width:85px;">';
        $html .= '	<div style="background:#363636;border:1px solid #FFFFFF;padding:1px 2px;font-size:10px;font-family:Verdana,sans-serif;float:left;color:#FFFFFF;">';
        $html .= '»';
        $html .= '	</div>';
        $html .= '	<div style="background:'.$badgecolor.';border:1px solid #FFFFFF;padding:1px 6px;font-size:10px;font-family:Verdana,sans-serif;color:#FFFFFF;">';
        $html .= '&nbsp;&nbsp;'.$badgelabel;
        $html .= '	</div>';
        $html .= '</div>';
        return $html;
    }



Form Instance edit

Now let's take care of the form that is displayed to the user when the plugin is dragged and dropped into the view, in edit mode. Let's have a look at what the code that was in use for creative commons, limiting it the bare skeleton.

  • has_instance_config defines whether the user has the option to customize the plugin content by editing a form. Keep it to true. We want the user to be able to edit the color and the label.
  • instance_config_form defines the look and feel of the form that will be shown to the user.
  • instance_config_save defines how the data that have been specified in the form get saved in the Mahara database. $values holds the data provided by the user when editing the form.
    public static function has_instance_config() {
        return true;
    }

    public static function instance_config_save($values) {
        $configdata = array();
        return $configdata;
    }

    public static function instance_config_form($instance) {
        // provides a shortcut to the folder <tt>roombadge/theme/raw</tt>
        global $THEME;

       // read the config data that have been saved by the user and parse them if necessary. 
       $configdata = $instance->get('configdata');

       // return a configuration file for the form. 
        return array();
    }

becomes:

     public static function has_instance_config() {
        return true;
    }

    public static function instance_config_save($values) {
       switch($values['colorIdx'])
       {
          case 0:
            $color = self::orange;
            break;
         case 1:
            $color = self::red;
            break;
         case 2:
           $color = self::blue;
            break;
         case 3:
           $color = self::green;
            break;
       }       
       
        $configdata = array('title' => get_string('title', 'blocktype.roombadge'),
                            'label' => $values['title'],
                            'color' => $color,
        );
        return $configdata;
    }

    public static function instance_config_form($instance) {
        global $THEME;
        $configdata = $instance->get('configdata');

        // defaults to use
        $color   = 'O';
        $label   = get_string('defaultlabel', 'blocktype.roombadge');

        // if the user previously speficied some value, use the user values instead of the defaults
        if (isset($configdata['label'])) {
            $label = $configdata['label'];
        }

        if (isset($configdata['color'])) {
            $color = $configdata['color'];
        }
        
        // Convert the one letter color name into the index value of the radio group. 
        switch($color)
        {
           case self::orange:
             $colorIdx = 0;
             break;
          case self::red:
             $colorIdx = 1;
             break;
          case self::blue:
             $colorIdx = 2;
             break;
          case self::green:
             $colorIdx = 3;
             break;
        }

        

        return array(
            'title' => array(
                'type' => 'text',
                'value' => $label,
            ),

            'colorIdx' => array(
                'type' => 'radio',
                'title' => get_string('config:selectcolor', 'blocktype.roombadge'),
                'options' => array(
                                   0 => get_string('O', 'blocktype.roombadge'),
                                   1 => get_string('R', 'blocktype.roombadge'),
                                   2 => get_string('B', 'blocktype.roombadge'),
                                   3 => get_string('G', 'blocktype.roombadge')
                                   ),
                'defaultvalue' => $colorIdx,
                'separator' => '<br>',
                'help' => true,
                'rules' => array('required'    => true),
            ),
        );
    }

We need to add any string used in the config form the language file roombadge/lang/en.utf8/help/blocktype.roombadge

$string['config:selectcolor'] = 'Choose a badge color';

Testing the plugin edit

Navigate with your browser to the Mahara website, in your development sandbox

http://localhost/mahara/

If there is any error, correct it. You should have some message telling you about the file and the line number at the origin of the error.

For instance, I inserted this error

Parse error: syntax error, unexpected T_STRING in /Applications/XAMPP/xamppfiles/htdocs/mahara/blocktype/roombadge/lib.php on line 28

If all is well, put your mouse over the little arrow next the Mahara logo, at the top of the page. Select Site Administration. You should end up at

http://localhost/mahara/admin/

Click on the tab Extensions The name of your login should appear, with install next to it.

roombadge (Install)

Click install. All should go well. Navigate back to one of your user views, using the tab Return to Site. Select a view:

http://localhost/mahara/view/view.php?id=1

Click Edit Content at the top right of the page. Select the tab General as we opted for category 'general' in our lib file. Select Classroom Badge and drop it into your view. Click on the form icon to configure.


Readme and version files edit

Don't forget to change the file roombadge/README.txt. I went for this

Room Badge Blocktype for Mahara 
Copyright (C) 2011 Widged

Author: Marielle Lange

This block allows Mahara users to add a room badge on their views.

Double check the file roombadge/version.php and edit if necessary.

$config = new StdClass;
$config->version = 2011051200;
$config->release = '1.0.0';

Result edit

Direct link to the files content on github