HelloWorld: The Movable Type Plugin Walkthrough: Registration & Configuration

Due to a few requests and for my own personal reference, I've decided to create a plugin walkthrough for Movable Type's incredibly powerful API. Before we even begin, I recommend you buy a copy of Hacking Movable Type to get acquainted with various aspects of the application from a developer's perspective.

In this walkthrough, we'll start with a very simple plugin that does little more than register itself in the system and provide a few configuration values and an interface. However, towards the end of the walkthrough, the plugin will develop and become very powerful, making use of the new developer features in Movable Type 3.2 that haven't been previously documented. So lets begin...

First download the plugin so that you can easily follow this tutorial. As always, extract the zip file and the folders you get correspond to the folders in your Movable Type directory.

Lets first look at plugins/HelloWorld/helloworld.pl. Pl files in the plugins directory are loaded everytime Movable Type is called and hence it is preferable to keep them as small as possible. Currently helloworld.pl contains some very basic code to get our plugin registered on the System Overview > Plugins page and store some configuration settings. At the top of helloworld.pl, you'll see

package MT::Plugin::HelloWorld;
use strict;
use base qw(MT::Plugin);
use MT;
use MT::Template::Context;
use vars qw($VERSION);
$VERSION = '1.0';

All this code does is say “I'm creating a plugin that perl can call MT::Plugin::HelloWorld and I'm basing it off the MT::Plugin class”. Defining a package, besides being good practice, is very useful as we'll see later on. The MT::Plugin class contains various routines that allow you to hook into the different parts of Movable Type and hence basing your plugin off it allows you to inherit those routines. I also define $VERSION which contains the plugin's version number. I find it easier to just use one variable in one file rather than version numbers hard coded across various files - as you only need to change one value!

Next comes the chunk of code that registers the plugin on the Plugins Listing under System Overview.

my $plugin = new MT::Plugin::HelloWorld({
        name => "Hello World",
        description => "The Plugin Walkthrough",
        doc_link => "http://www.movalog.com/archives/plugins/helloworld",
        plugin_link => "http://www.movalog.com/archives/plugins/helloworld",
        author_name => "Arvind Satyanarayan",
        author_link => "http://www.movalog.com/",
        version => $VERSION,
        system_config_template => \&template,
        settings => new MT::PluginSettings([
        ['text', { Default => 'HelloWorld' }]
        ]),
        config_link => 'helloworld.cgi'
});
MT->add_plugin($plugin);

Most of it is fairly self explanatory but there are a few new pairs that are new with 3.2:

  • name: The name of the plugin without the version number
  • description: A short description of the plugin
  • doc_link: A link to the documentation for the plugin
  • plugin_link: A link to the plugin's home (e.g. if you have setup a seprate category or blog for it)
  • author_name: The name of the author of the plugin
  • author_link: A link to the author's website
  • version: The version number of the plugin, in this case, it simply points to $VERSION (see what I mean about reusing that variable?)

Which creates:

Plugin Registration

The second part of the code block allows you to create a configuration interface for your plugin. This is a completely new developer feature that came with 3.2 and it's made our lives much easier as we now do not have to write load and save routines for our configuration, simply define the various fields you wish to store using the settings key/value pair and it's all taken care for you. For each field, you have to define the field's name and an optional Default value, as with HelloWorld, I have a field called text with a default value of HelloWorld. In a similar fashion you can create more fields like so:

settings => new MT::PluginSettings([
    ['text', { Default => 'HelloWorld' }],
    ['text2']
    ]),

which would allow me to store the values for two fields, text and text2, the latter with no default value. To provide an interface for these settings, you have to specify a config_template key/value pair. This key/value pair comes in three flavours:

  • blog_config_template - this causes a plugin to show up on the Blog Level Plugin Listing and allows you to store separate values for each blog.
  • system_config_template - the opposite of blog_config_template, this causes the configuration interface to only appear in the System Overview Plugin Interface, therefore, values saved here apply to all blogs.
  • config_template - specifying simply config_template allows you to save configuration data on both the blog and system level. In most cases this provides the maximum flexibility.

The value for these keys can be one of two things, it can either point to a subroutine or a template file (*.tmpl). Personally I prefer the former as I find them to be more powerful, as you'll see below.

In helloworld.pl, I've specified a system_config_template to point to the template subroutine, lets examine it below:

sub template {
        my ($plugin, $param) = @_;
        my $text = $param->{text};
        $param->{template_count} = MT::Template->count({ name => $text });
        my $tmpl = <<TMPL;
        <div class="setting">
        <div class="label"><label for="text">Text:</label></div>
        <div class="field">
        <select name="text">
        <option<TMPL_IF NAME=TEXT_HELLOWORLD> selected="selected"</TMPL_IF>>HelloWorld</option>
        <option<TMPL_IF NAME=TEXT_GOODBYEWORLD> selected="selected"</TMPL_IF>>GoodbyeWorld</option>
        </select>
        <p>HelloWorld can get a bit boring, choose something else to add a little flavour to life</p>
        </div>
        </div>
        <p>There are <TMPL_VAR NAME=TEMPLATE_COUNT> templates called '<TMPL_VAR NAME=TEXT>' in this system</p>
TMPL
}

At the most basic level, a config_template subroutine need only specify a value for $tmpl which will show up when the user clicks on Show Settings. Every config_template subroutine is passed a plugin object and a hash of HTML::Template tags. By default, these HTML::Template tags include:

  • FIELDNAME - where FIELDNAME is the name of the field. This template tag simply returns the value of the field and is used like so <TMPL_VAR NAME=FIELDNAME>
  • FIELDNAME_FIELDVALUE - if the value of the field does not contain any spaces, this tag is also created and is extremely useful when creating drop down menus or radio boxes as it allows you have an option preselected by checking for the presence of this variable, <TMPL_IF NAME=FIELDNAME_FIELDVALUE>

You can see examples of both these template tags in helloworld.pl with <TMPL_VAR NAME=TEXT> which outputs the value of the text field and <TMPL_IF NAME=TEXT_GOODBYEWORLD> selected="selected"</TMPL_IF>. Using these tags, you can build a configuration interface. Assign it to the variable $tmpl and you're done, Movable Type takes care of the rest. I also suggest you follow the markup I've used in HelloWorld to create a good looking configuration screen that fits in with the rest of the app.

Using subroutines over simple *.tmpl files gives you one big advantage, namely being able to populate your own HTML::Template tags. This is extremely useful when creating configuration screens that, for some parts, don't use MT::PluginSettings. As I mentioned previously, each config_template subroutine is passed a plugin object and a hash of HTML::Template tags. If we grab these two objects, we can populate our own template tags and this is done in the first line of the template routine, my ($plugin, $param) = @_; where $plugin is an MT::Plugin object representing your plugin and $param contains key/value pairs for HTML::Template tags. Now you can manipulate $param however you want - adding new template tags or changing current ones. I've given an example in HelloWorld with $param->{template_count} which is access using <TMPL_VAR NAME=TEMPLATE_COUNT>

All this leads upto the following appearing when the user hits Show Settings:

Plugin Configuration

So now your plugin can register quite nicely in Movable Type and is capable of having quite a complicated configuration. Next time, we'll look at the variety of ways in which you can create an interface for your plugin. There's a sneak peak in the HelloWorld distribution.

7 Comments

JDG said:
on Jan 12, 2006 10:03 AM | Reply

This is good stuff Arvind! Keep it up!

Dan Wolfgang said:
on Jan 12, 2006 4:27 PM | Reply

Arvind, this is awesome! As someone who knows a little and is always trying to take another step, this piece of information does exactly that: show me one more step I can take. I look forward to "next time"'s information!

kate said:
on Jan 12, 2006 6:47 PM | Reply

Thanks, Arvind! Very helpful!

Carla said:
on Jan 12, 2006 7:23 PM | Reply

Arvind, this is so weird. I was just reading this section in the book last night. I check my Bloglines this morning and see you've posted about it. This is indeed very helpful for those that haven't the purchased the book yet.

And I must add to your recommendation, this book is GREAT!

Aziz said:
on Jan 12, 2006 10:36 PM | Reply

I'm looking to see more professional techniques like how to create custom database tables in a consistent way or generally how to make an sophisticated application like Blogroll with MT

Dan Wolfgang said:
on Jul 30, 2006 5:33 PM | Reply

Hmph. Well, maybe I'm missing something, but it seems that using FIELDNAME_FIELDVALUE doesn't work with radio buttons. I can make it work fine with a dropdown, but not radio buttons. Suggestions?

Dan Wolfgang said:
on Jul 30, 2006 5:44 PM | Reply

I swear I've been scratching my head at this for about 2 hours now. It didn't work. I refreshed one more time... and it did.

Leave a comment

Preview