Developer Area/Development Tutorials/Basic blocktype plugin

From Mahara Wiki
Jump to: navigation, search

Let's look how to write a blocktype plugin for Mahara. The purpose of that plugin is, to add a Twitter Tweet button to any Mahara view. We'll see what is needed to write a blocktype plugin for Mahara - what are the minimal required files, what is the folder structure, etc.

Let's begin with minimal set of needed files and folder structure. Let assume, we will call our plugin Tweety - the name of the plugin must be unique. So you'll need at least those files (placed in correct folders):

  • /htdocs/blocktype/tweety/lib.php - the file that actually is your blocktype plugin. It contains all the logic for rendering content, etc.
  • /htdocs/blocktype/tweety/thumb.png - the icon image, which will be shown at one of the categories (in which you placed your blocktype plugin). Think about the tabs on top, when creating/editing a Mahara view. All other icons/thumbs are 70×58 pixels, so I think yours should also be the same size.
  • /htdocs/blocktype/tweety/version.php - the file, which contains the version of your blocktype plugin, usually in version and release format. E.g.: version = 2011051500 (YYYYMMDDNN), where Y is year, M is month, D is day and N is incrementing number, starting at 00; release = 1.0.0, for initial release.
  • /htdocs/blocktype/tweety/lang/en.utf8/blocktype.tweety.php - the file, which contains all the strings, used by your blocktype plugin in English language.
  • /htdocs/blocktype/tweety/lang/xy.utf8/blocktype.tweety.php - (optional) the file, which contains translated strings of xy language, where xy is an ISO 639-1 language code.


/htdocs/blocktype/tweety/thumb.png

An icon that will represent your blocktype plugin, so the users will know very quickly, what your blocktpye plugin is all about. Keep in mind, that it has to be 70×58 pixels. You can use the thumb from one of existing blocktypes as a start and change it...

Tweety.png

/htdocs/blocktype/tweety/version.php

<?php
/**
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
 * Copyright (C) 2011 Gregor Anzelj, gregor.anzelj@gmail.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @package    mahara
 * @subpackage blocktype-tweety
 * @author     Gregor Anzelj
 */

defined('INTERNAL') || die();

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

Don't forget to change @subpackage, @author and @copyright in commented part on top. You also have to change version and release numbers.

/htdocs/blocktype/tweety/lang/en.utf8/blocktype.tweety.php

<?php
/**
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
 * Copyright (C) 2011 Gregor Anzelj, gregor.anzelj@gmail.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @package    mahara
 * @subpackage blocktype-tweety
 * @author     Gregor Anzelj
 */

defined('INTERNAL') || die();

$string['title'] = 'Twitter Tweet';
$string['description'] = 'Add Twitter Tweet button';

The language file should contain at least title (the title of your blocktype plugin) and description (the description of your blocktype plugin) strings.

/htdocs/blocktype/tweety/lang/sl.utf8/blocktype.tweety.php - optional, translation to Slovenian language

<?php
/**
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
 * Copyright (C) 2011 Gregor Anzelj, gregor.anzelj@gmail.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @package    mahara
 * @subpackage blocktype-tweety
 * @author     Gregor Anzelj
 * @translator Gregor Anzelj
 */

defined('INTERNAL') || die();

$string['title'] = 'Twitter Tweet';
$string['description'] = 'Dodaj Twitter Tweet gumb';

The translation language file should contain at least title (the title of your blocktype plugin) and description (the description of your blocktype plugin) strings. You can also add @translaton in the above commented section... It is not necessary that the author and translator are the same person.

/htdocs/blocktype/tweety/lib.php

<?php
/**
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
 * Copyright (C) 2011 Gregor Anzelj, gregor.anzelj@gmail.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @package    mahara
 * @subpackage blocktype-tweety
 * @author     Gregor Anzelj
 */

defined('INTERNAL') || die();

class PluginBlocktypeTweety extends SystemBlocktype {

    public static function single_only() {
        return true;
    }

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

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

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

    public static function render_instance(BlockInstance $instance, $editing=false) {
        $full_self_url = urlencode(get_full_script_path());
        $result = '<a href="http://twitter.com/share?url=' . $full_self_url . '" class="twitter-share-button" data-count=none">Tweet</a>'
                . '<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>';
        return $result;
    }

    public static function has_instance_config() {
        return false;
    }

    public static function default_copy_type() {
        return 'full';
    }

}

Let's go over the functions in the PluginBlocktypeTweety class:


function single_only()

This function can return true or false. If it returns true it means, that the user can use only one instance of this blocktype on particular Mahara view.


function get_title()

This function returns the blocktype plugin title, as defined in blocktype.tweety.php language file. It returns the blocktype title in Mahara site defined language or in English, if the translation doesn't exists.

In our example this function would return 'Twitter Tweet', assuming that Mahara site defined language is English.


function get_description()

This function returns the blocktype plugin description, as defined in blocktype.tweety.php language file. It returns the blocktype description in Mahara site defined language or in English, if the translation doesn't exists.

In our example this function would return 'Add Twitter Tweet button', assuming that Mahara site defined language is English.


function get_categories()

This function returns the category (tab in Mahara view editing mode) in which the blocktype plugin is shown. Possible values are: blog, feeds, fileimagevideo, general, internal and resume. These categories are defined in Mahara database, in blocktype_category table.


function render_instance(BlockInstance $instance, $editing=false)

This is the most important function, because it renders the content of the blocktype.

In our example, we wish to render Twitter Tweet button. There is a Twitter Tweet button online generator form, which can help you generate the appropriate Twitter Tweet button code. The basic code looks like this:

<a href="http://twitter.com/share?url=http://mahara.org%2fview%2fview.php%3fid%3d35645" class="twitter-share-button" data-count="none">Tweet</a>
<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>

If we look at the code of this function, we see, that we need to provide/encode the URL of current Mahara view (web page) with all the arguments! This URL must be URL-encoded. This is achieved in the first line of code in this function:

$full_self_url = urlencode(get_full_script_path());

All you have to do after that point: you have to copy the basic code (obtained from Twitter Tweet button online generator form) and place $full_self_url to the right place (see the above code).

Please note: This is a very basic example, which is meant to show you, how to write a basic blocktype plugin. For more complex example, which also includes instance_config_form so the user can set more options, please download and compare TwitterTweet blocktype plugin.


function has_instance_config()

This function can return true or false. If it returns true it means, that the blocktype plugin has an instance config form in which the user supplies additional data, parameters, etc. that will affect the blocktype appearance in Mahara view.

If set to true than the function public static function instance_config_form($instance) must also be present. This function contains Pieform for rendering form in which the user will enter/select additional data, parameters, etc.

To understand how to use Pieforms and how Pieforms work, please see Pieforms documentation.


function default_copy_type()

When a page that contains this block is copied, this function controls what portions of this block git copied into the new block. (The name "default_copy_type()" is because some blocktypes, such as the "Journal" block, provide the ability for the block copy settings to be customized per block instance.)

Possible values are:

  • shallow (Default): Copies the block's config, removing any specific artefact IDs.
  • reference: Copies the block's config, leaving artefact references in place.
  • full: Copies the block's config, and any artefacts that are linked to the block.
  • nocopy: This block is not included when a page is copied

If these settings don't work as expected, see the implementation of BlockInstance->copy() in htdocs/blocktype/lib.php for details on how it all happens. For instance the "full" copy is based on the artefacts linked to the block via the view_artefact table, which should be auto-populated if your block stores artefacts in a variable called artefactid or artefactids in its config, but may not be populated if you are doing something more complex.

(optional) function rewrite_blockinstance_config()

If you set your blocktype to use the shallow copy type, this function is called to rewrite the origin block's config data to remove the specific artefact references from it. The base PluginBlocktype class provides a default implementation that removes any variable called artefactid or artefactids, which is usually sufficient.

(optional) function rewrite_blockinstance_extra_config()

This function is called at the end of doing a "shallow" or "full" copy of a block. If your block is copied by "shallow" or "full" and needs to have its data rewritten in ways beyond what the standard BlockInstance->copy() method does in those cases, then you may implement this function to help with that.

This method is called before the new block is saved into the database, so you will not know the new block's ID yet, and consequently this method should not insert records directly into the database. It is mostly useful for altering the contents of the configdata.

If your block stores data in external tables...

If your block stores data in external tables and this data needs to be copied to the new blocktype, then your options are limited. Unfortunately BlockInstance->copy() doesn't have a hook method that is invoked after the new block instance gets committed to the database and assigned an ID. (See forum discussion: https://mahara.org/interaction/forum/topic.php?id=7448#post30077 ). If you'd like to implement a post-blockinstance-commit hook method (it should probably go at the end of Blockinstance->copy() right after it calls $newblockinstance->commit() ), then please upstream it! ;)

If you don't want to do that, then your best option is to use an event handler. BlockInstance->commit() fires a "blockinstancecommit" event each time a block instance is created or updated, and it passes the BlockInstance object as its parameter. So, in your rewrite_blockinstance_extra_config() method you could add the extra data to the BlockInstance object that is passed in, and then in your event handler, look for that extra data and use it to create the necessary records in the database. Bear in mind this event handler is called every time any block is updated or inserted. So before doing anything else, your event handler will need to check whether the BlockInstance is of the right blocktype, and whether it is a newly-copied block.

(optional) function export_blockinstance_config()

This function is called when exporting a blockinstance to a restorable format (currently; only Leap). Passed a block instance, it should export an array containing enough data to recreate a copy of the block. For most blocks the default implementation will probably be sufficient, but if your blocktype uses custom tables or unusual data structures you may need to customize this. If you customize this, you should probably also customize import_create_blockinstance()

See the PluginImportLeap->rewrite_blockinstance_config() method in htdocs/import/leap/lib.php for details on when this method is called, what data it is passed, and what return format it expects.

(optional) function export_blockinstance_config_leap()

This function is called when exporting a blockinstance specifically to leap2a. The default implementation simply calls the same blocktype's export_blockinstance_config() method and then JSON-encodes the results.

Usually it is better to customize export_blockinstance_config() instead of this method, so that your code will be forwards-compatible with any additional restorable export formats Mahara may support in the future.

(optional) function import_create_blockinstance()

This method is called during import to create a copy of an imported block. It should receive an array like the one generated by export_blockinstance_config() and turn it into a new BlockInstance.

See the method View::import_from_config in htdocs/lib/view.php for context on when this method is called, what data it receives, and what return value is expected.

(optional) function import_create_blockinstance_leap()

Similar to import_create_blockinstance(), except it is called only during a Leap2a import. (Since Leap is currently mahara's only import format, it is essentially the same at present. You should probably create an import_create_blockinstance() method instead, to give your block better forward-compatibility in case other import formats are created in the future.)

(optional) function import_rewrite_blockinstance_extra_config_leap()

Similar to the standard rewrite_blockinstance_extra_config method, this method is called during the Leap2a import process, to allow you to rewrite the blockinstance in the database. It is called immediately before calling import_create_blockinstance_leap(), and can be used to rewrite the artefact references in the configdata before the blocktype gets created.

See the method PluginImportLeap->rewrite_blockinstance_config() in htdocs/import/leap/lib.php for more details.

(optional) function import_rewrite_blockinstance_relationships_leap()

This function is called when importing a blockinstance from the Leap2a format. Unlike import_rewrite_blockinstance_extra_config_leap, it is called at the end of the import process (after views and collections have been imported), so you can use it to rewrite any references to these items stored in your blocks' configurations.

Because artefact references get rewritten automatically (or in import_rewrite_blockinstance_extra_config_leap), you should only need to implement this method if your blocktype contains references to views and collections (like the core "Navigation" blocktype).

See the function PluginImportLeap->rewrite_blockinstance_relationships() in htdocs/import/leap/lib.php for details on when this method is called, what data it is passed, and what return format it expects.