oreilly.comSafari Books Online.Conferences.


Slash's Wiki Plugin
Pages: 1, 2, 3, 4

The wikiMenu Template

This template renders the menu itself. It's separate from the header so that it can be relocated elsewhere, including in a Slashbox. This is the only template not assigned to the wiki page, simply to make it available everywhere. This is mostly an HTML form, though it does offer a link to the current page's revision list, if there's a current Wiki page. If the current page is a preview of a Wiki update, there's no good reason to display revisions, as that could drop an important change. In this case, the preview parameter will evaluate to a true value:

        [% UNLESS page; page =; END %]

        [% IF page and ! form.preview %]

                <a href="[% "$constants.rootdir/$page&amp;op=list"

        %]">Revisions</a> of [% page %]

        [% END %]

The rest is mostly bare HTML, with another link to the list of recently modified Wiki pages:

        <a href="[% "$constants.rootdir/" %]">Recent Changes</a>

        <br />

        <form method="POST">

        Search for:

        <input type="text" name="page" />
        <input type="hidden" name="op" value="display" />

        <input type="hidden" name="version" value='' />

        <br />

        <input type="submit" value="Go!" />


Be sure to notice the interpolation of the rootdir configuration variable into the ``Recent Changes'' link.

The wikiView Template

By far the most complex of the templates, this takes several variables and displays them somewhat nicely. Most of the code simply interpolates passed-in variables into HTML formatting constructs. It has a few complications, namely that it can display empty pages, several variables are optional, previews should be marked, and that it must suppress the editing widgets for the readonly mode described earlier.

After displaying the page title, the template checks to see if there's anything in the raw variable. If this is empty, we reasonably assume that this is a new page, and so display the contents of the wikiEmptyPage template:

        [% INCLUDE wikiEmptyPage %]

If there's something in raw (we could also check cooked, for that matter), there's Wiki page metadata to be displayed:


        [% IF nickname -%]

                by <a href="[% "$constants.rootdir/~$nickname" | fixurl %]">

                [% nickname == user.nickname ? 'you' : nickname %]</>

        [% END -%]

        on [% date %]

        [%- IF version -%]

        , version [% version %]

        [%- END -%]

        [%- IF description -%]

                (<em>[% description %]</em>)

        [% END %].</strong>


        <hr />

        [% IF form.preview -%]

                <h1>Unsaved Preview!</h1>

        [% END %]

        [% cooked %]

If you're not familiar with Template Toolkit semantics, that looks pretty imposing, but it's almost readable as English. (Or you could read Appendix C.) If there's a nickname, we compare it to the user's nickname. If they match, we'll change the author to ``you'' instead of to the user's nickname. It's more personal that way. Whatever we display, we'll link to the user's homepage on the system. The assumption here is that my esteemed coauthor Brian's clever hack for username homepage redirections works. It's a default feature.

We expect a date parameter, and version and description will probably be there, but if they aren't, we won't display any empty fields. One final nice feature is to label previews clearly. If there's a preview parameter passed to the applet, it's probably because the user hit the preview button. We'll show a nice reminder that nothing has been saved.

Some of the template directives have extra dashes. This is simply to suppress any whitespace between the HTML and the results of the directive. If this weren't there, we'd have to smash everything together in tag soup. It looks much nicer this way.

At the very of this snippet, the cooked (HTML formatted) version of the page is displayed. It might be clearer to check for cooked in this case.

The rest of the template is a simple form, which provides the required parameters, like wid, op (set to ``update''), the page title, the raw text, and the description along with the preview and save buttons. The whole thing is wrapped in a readonly check:

        [% IF readonly %]

                <a href="[% "$constants.rootdir/$title" %]">

				latest version</a>

        [% ELSE %]

                big old form

        [% END %]

Again, the only out of the ordinary thing is the interpolated link, and that idiom has cropped up before.

The wikiRecent Template

This template only needs to loop through the pagelist array (array reference, though Template Toolkit handles dereferencing transparently), displaying the title, the nickname of the last user to modify the page, the modification date, and, if present the description and version number of each of the changes.

To avoid presenting an empty page if something is horribly wrong, there's one little trick at the top of the template:

        [% UNLESS pagelist.0 %]

                No recent changes.  Think tabula rasa.

        [% END %]

Unless the array reference has at least one member (at index 0), nothing will be displayed by the loop. We'll refer to the theories of John Locke, who admittedly didn't have hyperlinks in mind. It beats no feedback anyway.

The wikiRevisions Template

This template is very similar to wikiRecent, as it must display similar information. There are two differences. The links from this page must take into account version numbers (so they add the version parameter), and the start of the template lists the name of the page for which it lists revisions:

        <p>The last several revisions of '[% pagelist.0.title %]' are:</p>

Provided there's at least one element of the array referenced by pagelist, that's all we need. Aside from the slightly different formatting, these two templates could be merged very easily.

It is possible that the user could request the revision list of a nonexistent page, for whatever reason -- perhaps having clicked on the "Revisions" link for an empty page. It's hard to prevent this from happening due to the way the wikiMenu is produced. Of course, it's also possible someone could construct a URI with the appropriate parameters, or there could be a database error. In any case, the template needs to handle the possibility that there are no revisions. We wrap everything so far in a case statement:

    [% IF pagelist.0.title %]

       <p>The last several revisions of '[% pagelist.0.title %]'


       ( continue as before )

    [% ELSE %]

       There appear to be no revisions of this page.  It probably doesn't exist.

    [% END %]


The wikiEmptyPage Template

The final and simplest template is a simple message displayed when a user requests a Wiki page that doesn't yet exist. It's worth knowing that templates don't have to contain code to be useful -- they're also handy for storing changeable text (especially things that could be translated):

        This page has not yet been created.

        Here's your chance to make your mark.

Default Data

There are several pieces of data to insert into the database to get things up and running -- we need a default Wiki page, and the applet refers to several configuration variables. It's not a real problem if they're not there, but it's more professional if they are.

Since the installation process calls the schema file, creating the wikipage and wikitext tables, adding data is a snap:

        INSERT INTO wikipage VALUES('default', 1, 1);

        INSERT INTO wikitext VALUES(1, now(), 1, 2, 'this is the default Wiki page',

                'default page', 'this is the default Wiki page');

The values follow the order given in the schema. If these commands succeed, the database will have one page named ``default'', ready and raring to go.

The configuration variables are also easy. They are added to the vars table in the order name, value, and description:

        INSERT INTO vars VALUES('wikiRevisionLimit', 25, 

                'the default number of wiki page revisions to list');

The other variables include wikiRecentLimit, wikiRunAds, wikiDefaultPage, and wikiExtendedLinks. These all have sane default values, though they can easily be modified by the standard Slash Vars interface.


There are lots of potential enhancements, and the Slash Wiki may not be as simple architecturally as a monolithic 500-line program, but it integrates nicely with Slash and has a lot of cool features. It only took a few days to write, and data persistence, templating, user accounts, configuration variables, form parsing, and installation came, basically, for free.

Though it began as simple software to run a Web site, the current version of Slash is a powerful application platform. It'll just take a few developers to come up with a killer application to show off some amazing new technique you can't live without. Maybe it's an XML-RPC interface to the Stories List, or an NNTP gateway. Maybe it's something completely unrelated to Weblogs. Whatever it is, someone out there has it in mind, and just needs a little information and a little push to send us all off on interesting new tangents.

chromatic is the author of O'Reilly's Running Weblogs with Slash.

Sponsored by: