Welcome to San Francisco Perl Mongers Wireless Network Info: SSID: melody No WEP, no keys, nada. Sponsored by Building on the Byrne Reese Manager, Platform Technology Six Apart, Ltd. October 20, 2005 overview Introductions About Six Apart Why Movable Type? Your First Plugin Page 3 me Product Manager Open Source Hacker CPAN Contributor (SOAP::Lite) Movable Type Plugin Developer Page 4 six apart 10+ million bloggers using our software to share their lives, experiences and opinions with their friends, their families and the world. plus, a company of perl experts, hackers and enthusiasts Page 5 our modules XML::Feed XML::FOAF WWW::Blog::Metadata XML::Atom XML::Atom::Filter SOAP::Lite Net::OpenID LWP::ParanoidAgent Perlbal SWF::Chart Crypt::OpenSSL::DSA Text::Textile Email::Find Page 6 plus over a more… hundred movabletype highly extensible plugin architecture large community of developers free! not a product… a platform Page 7 a platform Simple Complex Plugins can range from the very simple to the very complex. Page 8 a platform Simple Template Tags Text Filters Page 9 Complex Examples: IfEmpty ModifiedOn Textile Markdown Ajaxify a platform Simple StatWatch • Add one template tag and… • Get hit stats for your blog. • One template tag • A one-page user interface Page 10 Complex a platform Simple StyleCatcher • MT Template Plugin Action • Complex Javascript UI • Support for multiple template libraries Page 11 Complex a platform Simple SpamLookup • Complex set of plugin actions for filtering incoming comments • Expert use of MT’s plugin configuration framework Page 12 Complex a platform Simple Media Manager • Third party integration • Dedicated User Interface • Alternative templates • Overloaded modes Page 13 Complex a platform Simple Complex Not to mention plugins for: • Feedburner plugin • PayPal Firewalls • Editorial Workflow • Podcasting …you name it. Page 14 pronet you are not alone… hundreds of members strong articles, docs and mailing lists plugin directory a community of developers… Page 15 pronet …and professionals gig leads promote yourself deals on conferences free technical support Page 16 your first plugin Page 17 creating your plugin package MT::Plugin::MyPlugin; use MT; use base qw(MT::Plugin); use vars qw($VERSION); sub BEGIN { $VERSION = '1.0'; my $plugin; $plugin = new MT::Plugin::MyPlugin({ name => 'Photo Gallery', version => $VERSION, description => ‘A description.', doc_link => '', author_name => 'Byrne Reese', author_link => 'http://www.majordojo.com/', }); MT->add_plugin($plugin); } Page 18 registering your plugin place your plugin .pl file in the plugins directory your plugin will appear among the other plugins in MT’s Plugins Control Panel Page 19 template tags Page 20 a simple tag MT::Template::Context->add_tag(HelloWorld => \&helloworld); sub helloworld { my ($context, $args) = @_; my $who = $args->{who} || “World”; if ($who eq “Byrne”) { return $context->error(“Please don’t feed the animals”); } return “Hello $who”; } # <MTHelloWorld who=“Byrne”> Page 21 a container tag MT::Template::Context->add_container_tag(HelloWorld => \&helloworld); sub helloworld { my ($context, $args) = @_; my $who = $args->{who} || “World”; my $res; my $builder = $ctx->stash('builder'); my $tokens = $ctx->stash('tokens'); foreach my $p (split(“,”,$who) { $ctx->stash(‘who', $p); defined(my $out = $builder->build($context, $tokens)) or return $ctx->error($context->errstr); $res .= $out; } $res; } Page 22 a container tag (continued) MT::Template::Context->add_tag(Who => \&who); sub who { my ($context, $args) = @_; my $who = $context->stash(‘who’); return $who; } # <MTHelloWorld who=“byrne,ben,mark”> # <$MTWho$> # </MTHelloWorld Page 23 a conditional tag MT::Template::Context->add_conditional_tag(IfByrne => \&ifbyrne); sub ifbyrne { my ($context, $args) = @_; my $who = $context->stash(‘who’); return $who =~ /Byrne/i; } # <MTHelloWorld who=“byrne,ben,mark”> # <MTIfByrne> # Please don’t feed the animals. # <MTElse> # <$MTWho$> # </MTIfByrne> # </MTHelloWorld Page 24 text filters Page 25 a simple text filter MT->add_text_filter(‘bfil’, { label => "Byrne’s Filter", on_format => &filter, docs => ‘url’}); sub filter { my ($str, $context) = @_; $str =~ s#Byrne#<a href=“http://majordojo.com/”>\1</a>#gi return $str; } Page 26 building a UI of your own Page 27 MT::App your plugin == a tiny MT contains all of your application logic package MyPlugin::App; use strict; use MT::App; @MyPlugin::App::ISA = qw( MT::App ); sub init { my $app = shift; my %param = @_; $app->SUPER::init(%param) or return; $app->add_methods(‘hello’ => &hello); return $app; } Page 28 sub hello { my $app = shift; $app->l10n_filter( “hello world” ); } creating a cgi script dispatches requests to your MT::App MT::Bootstrap #!/usr/bin/perl # # My Movable Type Plugin use strict; use lib "lib", ($ENV{MT_HOME} ? "$ENV{MT_HOME}/lib" : "../../lib"); use MT::Bootstrap App => ‘MyPlugin::App'; __END__ Page 29 MT::Object abstracts developer away from SQL and database package MediaManager::Entry; use strict; use MT::Object; @MediaManager::Entry::ISA = qw( MT::Object ); __PACKAGE__->install_properties({ column_defs => { 'id' => 'integer not null auto_increment', 'blog_id' => 'integer not null', 'title' => 'string(150) not null', 'catalog' => 'string(50) not null', 'isbn' => 'string(50) not null', 'entry_id' => 'integer' }, indexes => { blog_id => 1, }, audit => 1, datasource => 'mediamanager', primary_key => 'id', }); Page 30 MT::Object methods load and load_iter count save exists remove my %constraints; $constraints{blog_id} $constraints{status} $constraints{catalog} my %options; $options{sort} = $options{direction} = $options{limit} = $options{offset} = = $blog_id; = $show if $show ne 'all'; = $catalog if $catalog ne 'all'; $sort; direction => $acs ? 'ascend' : 'descend'; $limit if $limit ne 'none'; $offset; my $iter = MediaManager::Entry->load_iter( \%constraints, \%options ); Page 31 etcetera alt-templates junk filters callbacks advanced plugin actions integrated plugin settings interface BigPAPI Page 32 oh yeah… Page 33 we’re hiring ;) Page 34 discussion Page 35