PapaScott I don't claim to succeed at all this

Hello World as an MT::App CGI

I've been waiting for a consumer version of Movable Type 3 before taking a look at it, having been bitten by a couple of bugs in the developer version and the lack of (the now award-winning) MT-Blacklist. Both will soon be alleviated in the upcoming Movable Type 3.1, scheduled for August 31, which means it may or may not be already in beta.

Reason enough to look again at MT3 and the plugin architecture. I had an idea for a plugin, and it took all of one hour to write up. (More on that later.) But then I wanted to be able to use a CGI to set a couple of configuration variables. And there I got stuck.

The plugin tutorial says that "The best way to (build a human interface for your plugin) is to write a subclass of MT::App" without really explaining how to do that. The docs for MT::App are a bit sparse on the subject as well. There are a number of mature plugins that build interfaces in this way, but looking at them, I felt like I was looking at the blueprints of the Empire State Building, when at first all I want to build is a hut on the beach.

Finally when I was looking at Chad Everett's MT-Notifier (also award-winning) did the light bulb turn on inside my head and I saw the light. It took me 4 files, each in a different directory, but I was able to write a Hello World CGI plugin for Movable Type 3.

First we need a MT_DIR/plugins/hello.pl. It doesn't do anything except register the plugin so I get a nice link to my CGI on the MT main page.

package MT::Plugin::Hello;
use strict;
use MT;
use MT::Plugin;
use vars qw($VERSION);
$VERSION = '0.1';
my $about = {
  name => 'MT-Hello',
  config_link => '../mt-hello.cgi',
  description => 'Say hello to the world in a unique way.',
  doc_link => 'http://www.papascott.de/archives/2004/08/12/hello-world-as-an-mtapp-cgi/'
}; 
MT->add_plugin(new MT::Plugin($about));

Next comes the CGI itself in MT_DIR/mt-hello.cgi, which does nothing but call my subclass of MT::App. Most plugin CGIs look exactly like this.

#!/usr/bin/perl -w
use strict;
my($MT_DIR);
BEGIN {
  if ($0 =~ m!(.*[/])!) {
    $MT_DIR = $1;
  } else {
    $MT_DIR = './';
  }
  unshift @INC, $MT_DIR . 'lib';
  unshift @INC, $MT_DIR . 'extlib';
}
eval {
  require shanson::hello;
  my $app = shanson::hello->new (
    Config => $MT_DIR . 'mt.cfg',
    Directory => $MT_DIR
  ) or die shanson::hello->errstr;
  local $SIG{__WARN__} = sub { $app->trace ($_[0]) };
  $app->run;
};
if ($@) {
  print "Content-Type: text/htmlnn";
  print "An error occurred: $@";
}

Now we get to the meat and potatoes in MT_DIR/extlib/shanson/hello.pm, where I say that all I really want my $app to do is print some text. I require a login only so I get a pretty header on the page. Update: I've incorporated Phil Ringalda's suggestions. The sub uri is so the pretty header links back to the proper mt.cgi instead of mt-hello.

package shanson::hello;
use strict;
use MT::App::CMS;
use vars qw(@ISA $VERSION);
@ISA = qw(MT::App::CMS);
$VERSION = '0.1';
sub uri {
  $_[0]->path . MT::ConfigMgr->instance->AdminScript;
}
sub init {
  my $app = shift;
  $app->SUPER::init (@_) or return;
  $app->add_methods (hello => &hello);
  $app->{default_mode} = 'hello';
  $app->{requires_login} = 1 ;
  $app->{user_class} = 'MT::Author';
  $app->{is_admin} = 1;
  $app;
}
sub hello {
  my $app = shift;
  my %param = (no_breadcrumbs => 1);
  $app->build_page('hello.tmpl', %param);
}

Finally, I put a template file in MT_DIR/tmpl/cms/hello.tmpl, so my class knows what it is supposed to print.

<tmpl_include NAME="header.tmpl">
Hello, world!
<tmpl_include NAME="footer.tmpl">

And no description of a web application is complete without a couple of screenshots:

Main screen:Main screen

CGI screen:CGI screen

Now I just have to write a CGI that actually does something, like, ummm, what did I want to do again? Oh yes, set a couple of configuration variables for my plugin.

Update 28 Oct 2004: David Jacobs noticed some missing backslashes, which I'm guessing went missing when I reimported all my blog entries into Movable Type. Sorry about that!

18 Mar 2005 MySQL ate my blackslashes again! Crucial backslashes were missing in $app->add_methods (hello => &hello); and $app->build_page('hello.tmpl', %param);. Thanks to the ProNet mailing list for pointing this out in February and to Nathanial Irons for reminding me that I hadn't yet corrected this page.

comments powered by Disqus