Building a static website with Textpattern

Textpattern is “a flexible, elegant, easy-to-use content management system for all kinds of websites, even weblogs.”

Out of the box, a Textpattern site resembles a newspaper or magazine with front page articles that sink down into the past as new articles are posted. I wanted to build sites more like books with multi-level tables of contents. Simple websites, such as this one and Kitchen Ink, that organize their content into pages grouped in a simple hierarchy.

I wanted to do this in Textpattern to take advantage of its rule-based simplicity and content management features: browser-based maintenance, multi-user workflow, and easy design markup.

My reading on the Textpattern forums indicated that Textpattern could be adapted to presenting websites with so-called static pages.

In the beginning, it was not at all obvious how to change Textpattern’s blog-like nature. There are several reasons for this:

  1. Not until zem_rewrite was there a reasonable way to handle sections.
  2. None of Textpatterns ready-made tags can produce menus that are aware of the current section.
  3. Textpattern’s documentation has not caught up with its code.
  4. As Zem observed in his TXP Magazine interview, one of Textpattern’s virtues is inflexibility in the service of purpose-specific freedom.

In the end, Textpattern’s Section/Article approach served my purpose very well. First of all, zem_rewrite provided an indispensible rationalization of how Textpattern handles section URLs. Then, I found two plugins, chh_article_custom and mdp_sectionmenu, while browsing around forum.textpattern.com and textpattern.org. I modified them enough to justify presenting the pair in a new plugin, rdt_dynamenus.

The following article describes how to build non-blog websites with the aid of my rdt_dynamenus plugin which you can save to your computer and then upload under Textpattern’s Admin -> plugins tab.

Note: the newest version of Textpattern, 1.0rc3, incorporates zem_rewrite.

Fairly generic instructions

In the following, let’s assume we’re working with an out-of-the-box installation of Textpattern from the last couple of months, 1.0rc2 at least. Ideally, you should use version 1.0rc3 which incorporates zem_rewrite’s functionality. You should be logged in as site administrator under http://yoursite.xxx/textpattern. In the documentation, you can find more information on how to deploy the menu tags.

The Pages template

In Administration mode, go to the presentation tab and choose pages (presentation > pages). We’ll modify the default page/template.

In the #center division, change the txp:article tag to show only one article at a time:

<txp:article limit="1" form="default" />

In the left, right, or head DIV where you want the section menu, insert:

<txp:rdt_section_menu default="Welcome home" id="sections"/>

In the right or left DIV where you want the article menu, insert:

<txp:rdt_article_menu id="articles" />

Example CSS

The following CSS code demonstrates how to format a vertical article menu and a horizontal section menu, both with active pages highlighted. In the documentation,

Article menu CSS


  #articles {
    list-style: none;
    margin: 0em;
    padding: 0;
    line-height:120%;
  }
  #articles li {
    text-indent: -1.25em;
    padding-left: 1.25em;
  }
  #articles li.active {
    border: 1px solid;
  }

Section menu CSS



  #sections {
   clear:both; 
    margin: 0;  padding: 0;  
    height: 2em;
    line-height: 2em;
    margin: 0;  padding: 0;  
    list-style: none;
  }

  #sections li {
    float:left;
    padding:0;
    text-align: center;
    white-space:nowrap;
  }

  #sections a {
    color: #574;
    font-size: 1.2em;
    font-weight:bold;
    width: 9em;  
    display:block;
  }
  #sections a:hover {
   border: 1px solid black;
   margin:-1px;
   background: skyblue;
  }

  #sections .active a, #sections .active a:hover  {
    cursor: default;
   color: #574;
   border: 0px;  /* turn off border */
   margin: 0px;
   background: #feb;
  }

Group your content into sections

First, plan the sections that will organize your future content.

In Administration mode, go to presentation > sections and add new sections to match your plan.

You must set one and only one section to appear “on the front page”. In this discussion, set the about section to appear on the front page. Articles tagged with this section will thus appear, one at a time, on the front page, and their permalinks will appear in the rdt_article_menu. Here, the about section will be your “Home” section—what your visitors see when they first arrive and to which they will often return again before visiting other parts of the site.

Create new articles in your sections

In Admin mode, go to the content > write tab, write an
article and assign it to the home section in the Section
dropdown list on the right. Save the page. Write other articles and assign them to other sections.

Go look at the website—one way is to click the view site tab. You should see the new sections and articles in their respective menus.

Note: you can control the order of article headings in the menu by changing the “Publish at” date. To make something appear at the top of the list, change the date to far in the future.

Tradeoffs to this approach

You get a very efficient, easy-to-use CMS website—the freedom of following Textpattern’s well-crafted rules. But you may run into some constraints:

How to develop tags

It became clear, after much editing and reloading of web pages, that a faster way to test PHP code behavior was needed while writing it. Paul Graham convincingly argues that you can program better with a shorter feedback loop.

To that end, I set up a little file, tryout.php, that looks a lot like index.php but lacks the final textpattern() invocation.

<?php
  $txpcfg['db'] = 'txp';
  $txpcfg['user'] = 'loot';
  $txpcfg['pass'] = '';
  $txpcfg['host'] = 'localhost';
  $txpcfg['table_prefix'] = '';
  $txpcfg['txpath'] = '/home/rtietjen/tmp/txp/rc2/textpattern';
  $txpcfg['doc_root'] = '/rdtietjen.local/www';
  include $txpcfg['txpath'].'/publish.php';
  ?>

A second file, rdt_menus.php, containing the actual candidate plugin code would look like this:

<?php include "tryout.php"; function rdt_article_menu ($atts) { // code here: } print parse("<txp:rdt_article_menu />"); ?>

And, finally to test my code, I run the command line:

php rdt_menus.php

in Emacs by hitting F2 and observe the results in a second window. This is much quicker than tweaking code in the browser, then saving, then reloading a page. and I get better error messages because the code isn’t evaluated inside of the textpattern() function.



  1. Richard, thanks for this plugin and tuto, it will be more efficient than the hand made section and articles menu I am using right now :)
    davidm    Apr 8, 12:00 PM    #
  2. Ok,I’m working with this right now,It took me a little to find the right thing,since I’m new to textpattern.
    Looks promising so far.
    I’m on revision 295,so If see any bug I’ll report back.
    marios    Apr 19, 03:58 PM    #