Annoyingly slippery

In my previous post I wrote about re-writing my site with one of the aims being to get to grips with Movable Type 4. Although I’ve been using MT for years I haven’t had a chance to delve into the most recent versions so I’ve felt a bit behind on all the new stuff.

MT is much more powerful than it used to be. It’s still clunky and infuriating in several places but it can do so much more than it once could. I think I now only use a single third-party plugin on this site whereas I used to rely on several. This is largely because MT’s template tags are now much more powerful than they once were.

On the downside MT has grown to become more complicated than most simple webloggers would need and the documentation is often infuriatingly vague and empty just when you need help the most.

Here’s a few of the most frustrating or useful things I came across this time around.

No OR

While MT’s newish loops and conditional statements are hugely welcome there seems to be one thing missing. You can do the equivalent of

if ( $category == 'fish' ) {

or even, relying on regular expressions,

if ( $category == 'fish' or $category == 'bird' ) {

but you can’t do something like this:

if ( $category == 'fish' or $entry_id == 632 ) {

There seems to be no way to do an OR statement with different variables. Which results in some annoyingly clunky and laborious nested and repetitive code.

Pages not publishing?

If you start creating some Pages (standalone pages, rather than templates listing Entries and Archives, etc) but they don’t appear on your site when you publish them then you’re lacking a Page archive template. This will almost certainly be the case if you originally had an old (like v3.x) version of MT and haven’t tried to use Pages since you upgraded.

Of course, MT won’t tell you your pages can’t be published. It will say everything’s gone just fine but provide you with a link to the front page of your site rather than the published Page. This time around was the second time I got caught out by this madness and it took me a while to remember the solution. Go to the templates and create a new Page archive template and then create an Archive Mapping for Pages. That should do the trick.

What page are we on?

If you’re customising your templates at all chances are you’ll want to customise things depending on the page being displayed. eg, “If this is the About page, display this thing.” How to do this isn’t immediately obvious because Pages are annoyingly slippery — there seem to be few hooks to customise the display for each one.

I think I picked this up from one of the add-on template sets or somewhere in the documentation I’ve long since lost… You can add tags to Pages (and, presumably, Entries) that begin with ‘@’ and these tags won’t show up anywhere on the site. But they can be used in template code.

For example, say you had one Page that shouldn’t have a sidebar. You could give it a tag called ‘@layout_wide’ and then in a template you’d have:

<mt:If name="page_archive">
    <mt:PageIfTagged tag="@layout_wide">
        <!-- Do something on a wide page here. -->
    <mt:Else>
        <$mt:Include module="Sidebar"$>
    </mt:PageIfTagged>
</mt:If>

Or something like that. You need those If tags around it all or else MT will complain when trying to parse the PageIfTagged tags when not rendering a Page archive. It’s a bit stupid like that.

System Templates

The System Templates have always been an annoyance. They’re the only templates that aren’t published with everything else; they’re displayed dynamically when, for example, someone previews a comment. Because these templates are processed by perl any, say, PHP code in shared Template Modules won’t be parsed and will be output to the browser.

While there’s no way to get your PHP code to function in System Templates you don’t want it displaying either. I got round this quite simply by setting a variable at the start of each System Template:

<$mt:SetVar name="no_php" value="1"$>

And then in my ‘Header’ Template Module hiding the bits of PHP:

<mt:Unless name="no_php"><?php
    // PHP code here...
?></mt:Unless>

Hardly rocket science, but it’s nice to still be able to use the same ‘Header’ template for the System Templates as well as the rest of the site.

Template caching

Finally, a pointer to an article in the documentation that’s very well hidden: Ultimate Guide to Template Module Caching. If you have any Template Modules that use a fair bit of MT code and are repeated a lot, such as lists of recent Entries or Comments in the sidebar of every page, this could save you a lot of rebuilding time. I didn’t have many cachable modules but I still reduced the site’s total rebuild time by 20%.

Comments

  • I feel your pain with the crappy Movable Type tag documentation, it's woeful. I've not worked with MT for years, and so when I had to re-do the Rattle website recently in MT, there was quite a lot of re-learning to do.

    One thing I did appreciate was the 'template sets' feature, which lets you package up your templates so that they can be easily backed up/version controlled/etc. Even that feature though has its niggles...

  • Six Apart have said that improving documentation is a priority for them... can't happen soon enough.

  • Hi, Phil.
    Some scattered notes:

    Tags beginning with @ are "private tags" in the terminology. They're generally for internal use and are not normally searched or exposed publicly eg. via mt:EntryTags, though there are ways to force that if desired. They're applicable to anything that can be tagged.

    You need those If tags around it all or else MT will complain when trying to parse the PageIfTagged tags when not rendering a Page archive. It’s a bit stupid like that.

    This confuses me a bit. The only obvious reason I can see for this objection is if you were doing the PageIfTagged test in a non-Page template. In which case either your template is wrong or that's exactly what you need to do: test if you're in Page context before testing Page features. What's stupid here? Keep in mind all we're seeing is very brief snippets of your code with little information about whatever else might be going on.
    Related, your solution seems a bit off from the problem described. You initially say you want to do a something when a particular page(About) is in context, but then go on to use a technique more appropriate to groups of pages. If you really wanted to do this only for the About page, your test could've just been:

    <mt:If tag="PageID" eq="[###]">
    <!-- This is the About page; do something special. -->
    <!-- PageBasename could also be used here; I know how much you love basenames. -->
    </mt:if>

    ...which would've required no extra @tagging as above. But if it was actually a group--or even unknown number-- of pages involved, what do you suggest otherwise? You could obviously expand my suggestion to include more IDs, but the tag option makes it extensible rather than requiring a template edit each time another comes up.

    Your "no_php" variable shouldn't be necessary. There's an internal variable to check for system template context:

    <mt:If name="system_template">
    <p>This is a system template</p>
    </mt:If>

    There should also be one available for testing the search template specifically(as have the others), but it's giving me a bit of trouble right now, so I won't bring it up in case it's actually broken since that was published. Either way, since you're applying no_php to all the system templates, this looks most appropriate, and does work.

  • Thanks for your thoughts Su -- great stuff as ever.

    I suppose calling MT "stupid" in that situation is a little harsh. I was using PageIfTagged in a module that was included in all pages so at first I was getting errors. I thought the cleverer thing to do would be for MT to think "No, this page isn't tagged with that because it isn't a Page; I'll move on." Instead you have to prevent it from even reaching the tag in the wrong context. It's not a big deal.

    I did think about using PageIDs to identify specific pages but I'm wary of using IDs that are internal to MT in my templates. Not least because I develop sites on a local machine and then, when it's all working, copy everything to the live site. I very much doubt that PageIDs are in synch on both servers, given how long it took me to get round to finishing this all.

    For me these tags aren't necessarily about groups of pages -- I have every page tagged with its own unique @tag to identify it and this doesn't seem like a problem to me. (They also have other @tags that are used by several pages.)


    But if it was actually a group—or even unknown number— of pages involved, what do you suggest otherwise? You could obviously expand my suggestion to include more IDs, but the tag option makes it extensible rather than requiring a template edit each time another comes up.

    I'm not sure if you think my "stupid" comment was referring to the whole idea of using PageIfTagged...? That's not what I meant -- I think this is a fine solution, once I'd realised how to do it.

    Good point about me not needing "no_php". I should have thought of the sensible solution you suggest. In my defence this was one of the last things I did so I probably wasn't thinking straight by that point!

  • I thought the cleverer thing to do would be for MT to think “No, this page isn’t tagged with that because it isn’t a Page; I’ll move on.”

    Ah, I see. That makes obvious sense intuitively, but there's something about it that bugs me, like it'll solve this problem but end up creating another that hasn't been considered; can't come up with a case right off, though. At the least, it seems like it might encourage a bit of sloppiness. Nothing really being read into the "stupid;" was just convenient for referring to the original comment.

    Developing on a separate install is a complication to using IDs, and something not intrinsic to the entry(like your tags) is definitely going to be better if the databases aren't being synchronized to whatever degree.

Commenting is disabled on posts once they’re 30 days old.

Friday 12 December 2008, 7:32pm

< PreviousIn all of WritingNext >

12 Dec 2008 at Twitter

  • 10:55pm: It never ceases to amaze me how Movable Type manages to make supposedly inviolable URL basenames change over time. Like geological shifts.
  • 4:46pm: @dotcode I'm constantly amazed these people ever got jobs in web dev/design never mind are able to keep them.
  • 10:44am: @smagdali @infovore Those people are trying *my* patience remotely, must be hell for @dotcode. They need some kind of... "persuasion".
  • 10:18am: @mattb That's the sound of irrational and possibly misguided superiority over the herd.
  • 10:11am: Why am I pleased that I've never heard any person's/mag's/site's best albums of 2008? Usually haven't even heard a single track off them.