Textpattern plugin for custom article lists
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



This is a plugin for Textpattern.

Code preview and compiled (ready-to-install) downloads available on the author’s website (latest release only) and on GitHub (all release versions).


This plugin relies on the trick of creating a temporary database table in memory. So the MySQL user you have assigned to Textpattern (indicated in config.php) must have CREATE privileges. If table creation fails, the plugin will return blank (as of version 0.2.5).


Contains one tag, soo_article_filter. It allows you to pre-select articles to limit the scope of an article or article_custom tag, using selection criteria not offered by those tags. In short, it’s like adding selection attributes to one of those tags.

As of version 0.2.4 there is also the option to add index-style titles to a custom field. E.g., “The First Article” becomes “First Article, The”. You can then access that custom field with the usual Txp custom field tags, allowing you to create alphabetical indexes.

As of version 0.2.6 you can do an additional UPDATE query on the temporary table, by using the update_set and update_where attributes. One use for this is to change article status from “Draft” to “Live” or “Sticky”, allowing you to display draft articles publicly.

Thanks to net-carver for clueing me in to MySQL temporary tables.


soo_article_filter is a container tag, intended as a wrapper for article or article_custom.

<txp:article />

Note: the filter will not be applied to search results.


None required, but without attributes the tag doesn’t do anything useful.

  • expires (“past”, “future”, “any”, or 0)
    If set to “past”, “future”, or “any”, only include articles with an Expires value. If set to “0”, only include articles without an Expires value. (%(default)Default% is null; no filter on Expires.)
  • customfieldname (empty or regexp pattern) replace “customfieldname” with any custom field name as set in site preferences. If the attribute value is empty, only articles with an empty value for this custom field will be included. Otherwise the attribute value will be treated as a MySQL regular expression pattern.
  • article_image (boolean) If 1, only show articles with an article image. If 0, only show articles without an article image. If not set (the default), article image has no effect.
  • multidoc (boolean) default false
    For use with the soo_multidoc plugin. See note below.
  • index_ignore (list) Comma-separated list of leading articles to transpose, when used in combination with index_field (%(default)Default% “A,An,The”)
  • index_field (custom field name) Set this to the name of an existing custom field to hold index-style titles (e.g. “The Title” becomes “Title, The”). Default empty.
  • update_set (SQL clause) default empty. Set this (and, optionally, update_where) to run an UPDATE query on the temporary table.
  • update_where (SQL clause) default “1=1”. Use this in conjunction with update_where to run an UPDATE query on the temporary table.
  • where (SQL clause) default empty. Any text here will be added to the end of the array of WHERE expressions used for article selection.
  • limit (integer) Number of articles to select. default unset, no limit.
  • offset (integer) Number of articles to skip. default unset, no offset.
  • sort (Column [direction]) Sort column (and optional sort direction), e.g. Posted asc. default unset.

Complex selection

The selection attributes (expires, customfieldname, article_image, multidoc, and where) may be used in combination. The result is a conjunctive (AND) search, i.e., each additional attribute makes the filter more restrictive.

The where attribute allows you to enter MySQL expressions and functions for even greater power.


Only show expired articles

You must set “Publish expired articles” to “Yes” in advanced site preferences.

<txp:soo_article_filter expires="past">
<txp:article />

Only show articles with “my-custom-field” set

Note the value, ".+". This will match any character. Note also that you can accomplish the same thing without a plugin, using the technique discussed in this Txp forum thread.

<txp:soo_article_filter my-custom-field=".+">
<txp:article />

Only show articles with “my-custom-field” not set

<txp:soo_article_filter my-custom-field="">
<txp:article />

Only show articles where “my-custom-field” includes “blue”

Note: this is not case sensitive. Would match “Blues”, “true blue”, etc. article and article_custom already work this way if you add the wildcard character % (e.g., my-custom-field="%blue%"), so you don’t need this plugin just to do this.

<txp:soo_article_filter my-custom-field="blue">
<txp:article />

Only show articles where “my-custom-field” contains only digits

Note the value, "^[[:digit:]]+$". This is a MySQL regexp pattern, not a PCRE pattern.

<txp:soo_article_filter my-custom-field="^[[:digit:]]+$">
<txp:article />

Only show articles that have an article image

<txp:soo_article_filter article_image="1">
<txp:permlink><txp:article_image thumbnail="1" /></txp:permlink>

Only show the most recent article with an article image

<txp:soo_article_filter article_image="1" limit="1" sort="Posted desc">
<txp:permlink><txp:article_image thumbnail="1" /></txp:permlink>

(Note: while you could declare the limit in the article tag, this method uses less memory.)

Use where to select on a numeric range

<txp:soo_article_filter where="image BETWEEN 4 AND 27">
<txp:article />

An alphabetical index using index_ignore and index_field

<txp:soo_article_filter index_field="index_title">
<txp:article sort="custom_3 asc" wraptag="ul" break="li">
<txp:permlink><txp:custom_field name="index_title" /></txp:permlink>

When index_field is set to the name of an existing custom field, this field will receive an index-style version of the article title, e.g. “The Title” becomes “Title, The”. You can then sort on and/or display the index-style title with standard Textpattern custom field tags and attributes, as shown.

Leading words getting special treatment are those listed in index_ignore. This defaults to English articles, i.e. “A,An,The”.

The custom field has to be one you have actually created in site prefs. In the example it is called “index_title”, and it is custom field #3. When saving articles leave this field blank, otherwise soo_article_filter will leave it unchanged.

The index-style title is created only within the soo_article_filter container — corresponding custom field in the database remains blank.

Add an UPDATE query to change article status

The update_set attribute allows you to run an UPDATE query on the temporary table. For example, to temporarily change the status of all “draft” articles in the “News” section to “live” (Textpattern’s status code for “live” is 4 and for “draft” is 1):

<txp:soo_article_filter update_set="Status=4" update_where="Status=1 AND Section='News'">
<txp:article />

Technical notes


This plugin attempts to run CREATE, DROP, and, optionally, UPDATE queries. There is a safety check: if the initial CREATE TEMPORARY TABLE query fails, the plugin exits immediately, without parsing the tag contents. However, the plugin has not been tested extensively, and you should certainly keep regular database backups if you are doing anything especially interesting with this plugin. Of course, you should keep regular database backups in any event.

One thing you should absolutely NOT do is assume that it is safe to do anything you like within the tag contents. The main issue is that if the page context is search results (i.e., the q query parameter is set), the tag will simply parse its contents and return them as is. If you stuck a raw query into the tag contents on the assumption the query would only run when the temporary textpattern table exists, you’d regret it. Maybe not today, maybe not tomorrow, but soon, and for the rest of your life.


You might get an error like this: Textpattern Warning: Not unique table/alias: 'textpattern'. It seems that some configurations allow the shortcut of creating the temporary table and selecting from the actual table of the same name in the same statement, but some don’t. Performance-wise it is certainly better to use a single statement, but if this doesn’t work for you, use the alternate version of the plugin, included in the download please contact me.

If you use Multidoc and see an error message including Table 'textpattern' already exists, see the note on Multidoc compatibility, below.

Performance considerations

Most plugins that give you a souped-up equivalent of article or article_custom have to duplicate and modify doArticles() plus a couple of other core Txp functions. Less than ideal, at least in terms of ease of plugin authoring, because doArticles() is quite a lot of code to duplicate and edit in a plugin.

This plugin takes a very different approach—it creates a temporary table holding a filtered set of articles, thus allowing you to use article and/or article_custom normally. Code-wise this is very simple; performance-wise it might be inferior (I don’t know). In my limited and informal testing the extra time required for dealing with the temporary table is a non-issue. This could change with a very large textpattern (articles) table. But as long as you set @soo_article_filter@’s attributes so as to produce a relatively small number of articles, there shouldn’t be a problem in most cases. (Version 0.3.1 adds limit, offset, and sort attributes to make it easier to target the exact articles you want.)

Might be another story on a highly-optimized, large, high-traffic website where maximum performance is a major concern.

Multidoc compatibility

The soo_multidoc plugin also uses the temporary table trick to filter articles, which can only be done once per page load. To achieve compatibility between soo_article_filter and soo_multidoc, follow these steps:

  • In Multidoc prefs (click *soo_multidoc*’s “Options” link in the plugin list) set the “Show all” preference to “yes”.
  • As needed, use soo_article_filter, with multidoc="1", to filter Multidoc interior pages.

Note that, unlike Multidoc’s built-in filter, soo_article_filter does not distinguish between list and individual article context, so if your Multidoc setup uses the same article tag for lists and individual articles you will have change this. (This is deliberate; it allows you to use soo_article_filter for an article_custom list on an individual article page.)

Version history

0.3.3 (2017/02/15)

Textpattern 4.6 compatibility update

0.3.2 (Jan 3, 2011)

Multidoc compatibility update

0.3.1 (Dec 9, 2010)

Added limit, offset, and sort attributes.

0.3.0 (Jul 11, 2010)

New attribute: where, allows you to add a raw WHERE expression to the selection criteria. (Thanks to Victor for the idea.)

0.2.7 (Jun 6, 2010)

Fixed bug in index_ignore attribute. (Thanks to th3lonius for spotting it.)

0.2.6 (Mar 8, 2010)

New attributes, update_set and update_where, allowing an additional UPDATE query on the temporary table.

0.2.5 (Feb 19, 2010)

Checks that temporary table creation was successful, else returns nothing.

0.2.4 (Feb 19, 2010)

Create properly-alphabetized indexes with the new index_ignore and index_field attributes.

0.2.3 (Jan 20, 2010)

Fixed custom field bug

0.2.2 (Sept 28, 2009)

New article_image attribute

0.2.1 (July 7, 2009)

soo_multidoc compatibility.

0.2 (July 4, 2009)

Fixed behavior of expires attribute.

0.1 (July 3, 2009)

Initial release. Allows filtering on the Expires field, and regexp pattern matching on any custom field.