HiI'mJaanus.Blog,Works.

Movabletype text filter development woes: strange initialization bug, and configuration scope

So… I was previously implementing a plugin that formatted text in a particular way. And implementing it with callbacks was fine until I realized that you can’t really plug into the comment preview mode this way. So if you want comment previews also to look good, you’re screwed :(

There is, however, another solution that becomes handy here, and leaves your article texts in a much nicer state than the callback machine. This is implementing a text filter. And so I did.

The text filter interface is not very friendly if you want to interact with other filters too. The “text filter” option is just one dropdown, that contains, say “Convert Line Breaks” and “Markdown”. So if you want to have another layer of filtering on top of Markdown, you must do some tricks to load the Markdown code into your own code. Markdown, SmartyPants and code were helpful.

I did come across two strange things. First, look at this code.

use strict;
use base qw(MT::Plugin);
use MT::Entry;
use MT::Comment;
use MT::Util;
use MT::Template::Context;
my $filters = MT->all_text_filters();
my $markdown_sp_ref;
if (exists( $filters->{'markdown_with_smartypants'} ) ) {
    $markdown_sp_ref = $filters->{'markdown_with_smartypants'}{on_format};
}

I am not sure what I’m doing wrong here, but it just plain doesn’t work for me. Looks like the MT package isn’t initialized and thus the exists call returns false and $markdownspref never gets initialized.

HOWEVER: if you add just one line to it, as follows…

use strict;
use base qw(MT::Plugin);
use MT::Entry;
use MT::Comment;
use MT::Util;
use MT::Template::Context;
my $mt = MT->new; # THIS IS THE ONLY CHANGE
my $filters = MT->all_text_filters();
my $markdown_sp_ref;
if (exists( $filters->{'markdown_with_smartypants'} ) ) {
    $markdown_sp_ref = $filters->{'markdown_with_smartypants'}{on_format};
}

… it starts working fine. This is a total mystery to me. Notice that the $mt variable never gets used below, it is merely initialized once and then discarded.

I must say that even though I’ve been using Perl quite a lot, I’m still not at very good terms with its package management and initialization and maybe I’m doing a trivial error here (wasntme) but it’s not obvious to me.

Secondly. My filter is not hardcoded. I want to configure the behaviour of my filter in my blog configuration backend. Why would you want to do a crazy thing like that? Well, I need to. And MT provides you the tools for that just fine. EXCEPT that it’s not possible to operate with a blog-level configuration (as opposed to system-level). With a callback function for entries and comments, it was quite doable. You would just go…

MT::Entry->add_callback("pre_save", 1, $plugin, \&entry);
sub entry {
    my ($cb, $entry) = @_;
    my $conf = $plugin->get_config_hash('blog:'.$entry->blog_id);
    ...
}

Now… when doing a text filter, it goes something like this.

MT->add_text_filter('key' => {
    on_format => sub {
        my $text = shift;
        my $ctx = shift;
        my $conf = $plugin->get_config_hash();
    }
}

Unless I am totally missing something here (I must say I’m not too familiar with the $ctx template context variable - maybe that’s what I’m missing? Looks like MT::Template has blog_id, but how to get to it from $ctx that is of type MT::Template::Context???), there doesn’t seem to be any way to get the blog-level configuration with get_config_hash, since we have no way to get blog_id for current object. Which conceptually looks like a mistake, because with filter, you’re always operating on a text that belongs to a given entry/comment that has always a blog ID associated with it. And it’s a shortcoming of the API that you can’t get to it here — or me not being able to figure it out.

So the way out for me was take a step back and make the configuration system-level instead of blog-level. Which makes me lose a bit of flexibility, but it’s a working solution, available now. Any tips on how to get to the blog_id from $ctx would be great.

Comments