The Plugin Walkthrough: Plugin & Itemset Actions

So far in this walkthrough, our plugin registers itself, provides a basic interface to accept configuration values. Last week, we looked at creating an interface either via creating a separate cgi file or by hooking directly into MT::App::CMS. Today, we'll look at two ways of plugging into Movable Type, Plugin Actions and Itemset Actions. Not only will I show you how to use these two features but I'll explain when and where to use them - contrary to what many think, Itemset Actions have not replaced Plugin Actions!

As always, I suggest you download the latest version of the HelloWorld plugin so that you can better follow this tutorial. This new version sports both a Plugin Action (which takes you to a listing of all templates with HelloWorld or GoobyeWorld in their name) and an Itemset Action (which renames templates to contain HelloWorld or GoobyeWorld in their name)

Plugin Actions

We'll first take a look at Plugin Actions. Plugin Actions were first introduced with Movable Type 3.0D and have since been used by a wide variety of plugins (for example MT Blogroll, SidebarManager and StyleCatcher also use Plugin Actions). They appear on almost every screen in Movable Type and allow a plugin to be easily accessible from within Movable Type.

Open helloworld.pl right after the registration code, you'll see

MT->add_plugin_action('list_template', 'helloworld.cgi?__mode=list', 'List HelloWorld Renamed templates');

This is all it takes to add a Plugin Action. The first argument specifies the screen on which the plugin action is displayed, valid values are:

  • blog - A blog's menu
  • entry - The new entry/edit entry screen
  • list_entries - The entry listing screen
  • comment - The edit comment screen
  • list_comment - The comment listing screen
  • commenter - The commenter details screen
  • list_commenter - The commenter listing screen
  • ping - The edit trackback screen
  • list_pings - The trackback listing screen
  • list_template - The template listing

The second argument specifies where the Plugin Action should link to. As you can see, you simply need to specify the name of your cgi file, any mode and parameters (without any path information). Movable Type also automatically adds two more parameters to the link, a from parameter which contains the name of the screen, and (if applicable) a blog_id parameter which contains the blog_id of the current blog. The final argument specifies the link text of the Plugin Action. This results in:

Plugin Action

at the bottom of the template listing screen. On clicking the Plugin Action, you're taken to helloworld.cgi?__mode=list;from=list_template;blog_id=X which is basically a listing of all templates that contain the HelloWorld text configuration in their name. HelloWorld::list is responsible for producing this screen. Most of this routine should be pretty self explanatory, the only bit of code that I haven't previously explained is creating HTML::Template loops.

In HelloWorld::list, you'll see that at the end of each $tmpl iteration, I have

push @template_loop, { tmpl_name => $tmpl->name, id => $tmpl->id };

and then towards the end of the routine

$param->{template_loop} = \@template_loop;

These two lines define a HTML::Template loop which is simply an array of key/value pairs and can be displayed in an HTML::Template template using a TMPL_LOOP tag to start the array and TMPL_VAR tags within the loop to access the key/value pairs. For example:

<TMPL_LOOP NAME=TEMPLATE_LOOP>
<TMPL_VAR NAME=TMPL_NAME><br />
</TMPL_LOOP>

HelloWorld Templates

Itemset Actions

Itemset Actions are new with Movable Type 3.2 and refer to the drop down menu of actions typically found on item listing (e.g. the entry listing, the comment listing, the template listing) screen. A few plugins have started using Itemset Actions including MT Protect, Notifier and TemplateRefresh (included with 3.2). Itemset Actions were primarily built to make it easier for plugin to work with multiple items - those of you who had MT Blacklist installed with previous versions of Movable Type 3.0 may remember it had a plugin action at the bottom of the comment listing, a very clumsy hack, if MT Blacklist was rewritten for MT 3.2, it would now use an Itemset Action.

Adding an itemset action is quite easy. Open up helloworld.pl and in the init_app routine, you'll see this new block of code

$app->add_itemset_action({
    type => 'template',
    key => "helloworld_templates",
    label => "Rename Template(s)",
    code => sub { $plugin->rename_templates(@_) },
    condition => sub { $plugin->perm_check($app) },
});

For each add_itemset_action method, you must specify the following key/value pairs:

  • type - this specifies the object this itemset is for and hence populates the appropriate drop down menus. Valid values are blog, entry, comment, commenter, ping, template
  • key - this is a unique identifier for the itemset action and is used by Movable Type to ensure the correct itemset gets executed. To make sure the key is unique, you're recommended to add your plugin's name
  • label - this is the label that appears in the drop down menus
  • code - this should point to the code that gets executed when someone selects the action from the drop down menu
  • condition - this key/value pair is used to restrict when Itemset Actions appear, they're especially useful in preventing Itemset Actions from appearing if an author doesn't have the appropriate permissions. The subroutine this condition points to must return a value for the Itemset Action to appear, if no value is returned then the Itemset Action does not appear

Lets take a look at the code that powers this Itemset Action, first we'll take a look at perm_check which ensures that the Itemset Action only appears if authors have sufficient permissions.

sub perm_check {
    my $plugin = shift;
    my ($app) = @_;
    my $perms = $app->{perms};
    $perms ? $perms->can_edit_templates : $app->user->is_superuser;
}

Like every routine called from init_app, it is passed $plugin and $app so we grab those first and then we check the author's permissions which is always available in $app->{perms}. The routine returns a value if $perms exists and if the author has template editing permissions or is a System Administrator, hence the Itemeset Action will only appear if the author has template editing permissions or is a System Administrator. A complete list of possible permissions can be found in MT::Permission.

Next, lets take a look at the workhorse, the routine that gets executed when someone selects the Itemset Action.

sub rename_templates {
    my $plugin = shift;
    my ($app) = @_;
    my ($param, @message_loop);
    my @ids = $app->param('id');
    my $config = $plugin->get_config_hash;
    my $text = $config->{text};
    require MT::Template;
    foreach my $tmpl_id (@ids) {
        my $tmpl = MT::Template->load($tmpl_id);
        my $tmpl_name = $tmpl->name;
        if(index($tmpl_name, $text) == -1){
            push @message_loop, { message => "Template \"$tmpl_name\" renamed to \"$tmpl_name $text\""};
            $tmpl->name($tmpl_name .= " $text");
        } else {
            push @message_loop, { message => "Template \"$tmpl_name\" not renamed"};
        }
        $tmpl->save or die $tmpl->errstr;
    }
    $param->{message_loop} = \@message_loop;
    $param->{return_url} = $app->return_uri;
    $app->build_page($plugin->load_tmpl('results.tmpl'), $param);
}

The key bit in this routine is my @ids = $app->param('id'); where we create an array of IDs of the templates that were selected. Then for each ID, we load the corresponding template, check whether we need to change its name (which is done using the index command which basically checks whether one string is found within another) and build a HTML::Templateloop of result messages. We also add a return_url HTML::Template tag so that we can easily bring people back to the templates listing.

Which & When

A big misconception today is that Itemset Actions have replaced Plugin Actions and that Plugin Actions are deprecated, and honestly, I thought this when I first came across Itemset Actions. However, both types of actions have their place.

Plugin Actions can be thought of as a way for plugins to extend Movable Type screens without having to resort to some type of hack (for example BigPAPI). The beauty of Plugin Actions are that several plugins can co-exist peacefully, while had they been resorting to hacks, some might have caused others to break. Plugin Actions can be thought of being tied to screens in Movable Type. On the other hand, Itemset Actions can be thought of as tied to items in Movable Type, e.g. entries, comments, blogs and are used to easily carry out operations on a number of items at once.

An easy way to better understand the difference would be to look at current plugins that add Itemset or Plugin Actions. Try and imagine how it would work if the plugin used the other type of action, for example StyleCatcher uses a Plugin Action to send users to its own interface where users can select a style, how would that work as an Itemset Action? Or what about TemplateRefresh, could it really use a Plugin Action to refresh only selected templates?

Hopefully that's cleared up the misconception that Plugin Actions have been deprecated. Both Plugin Actions and Itemset Actions are tremendously useful as they allow you to plug directly into Movable Type, therefore making your plugin more easily accessible to the user.

Next time, we'll look at the new way of creating custom tables in the database and using some of Movable Type's new upgrading infrastructure

3 Comments

Rich said:
on Jan 31, 2006 10:57 AM | Reply

And just a reminder to be sure everyone is using MT 3.2 and not earlier version!

Mark Carey said:
on Mar 9, 2006 10:52 PM | Reply

First of all, Arvind, thanks for this series -- very useful!

Following your guidelines, I have created an itemset action for comments. The action appears in the dropdown on the Comment Listing screen, but it doesn't appear in the dropdown on the "edit comment" screen -- on that screen the "actions" dropdown remains empty and grayed out. Any advice?

amber said:
on Jun 22, 2007 3:11 AM | Reply

hi, i've been trying to find a way to only show a plugin action if the user is a system administrator and haven't figured anything out yet.

is it even possible to restrict plugin actions?

thank you!