Textpattern plugin: Gallery

n: smd_gallery | v: 0.62 | f: /

Documentation for the Textpattern plugin smd_gallery by Stef Dawson follows this short message from our sponsor ;-)

Plugin list button Plugin download button Compressed plugin download button



  • Supports all current and (probably) future gallery scripts including thumbpop, rollover, tooltip, lightbox, litebox, slimbox, moonbox, thickbox, slideshow, fancyzoom, etc
  • Pull images from the TXP database that match categories, IDs, author, extension or particular dimensions / aspect ratios
  • Use article fields to hold lists of image categories/IDs for article-specific galleries
  • Multi-level sub-category support
  • Gallery layout is defined in a TXP form/container
  • Direct-access pagination is supported and the layout of paging features can be controlled by a second form
  • Uses a tag-replacement system like the wet_for_each_image plugin
  • MLP support


Stef Dawson. For other software by me, or to make a donation, see the software page.

Installation / Uninstallation

Requires TXP 4.2.0+ and smd_lib v0.36+

Download the plugin from either textpattern.org, or the software page above, paste the code into the TXP Admin -> Plugins pane, install and enable the plugin. Visit the forum thread for more info or to report on the success or otherwise of the plugin.

To remove the plugin, simply delete it from the Admin->Plugins tab. If no other plugins are using smd_lib you may safely delete that too.


The general idea is that this plugin acts as a flexible image filter; nothing more. The plugin options govern which images are pulled out of the database and they are sorted into whatever order you like.

After that, each image — one by one — has all its attributes passed through the container or form of your choice; you simply choose to display whichever image attributes you like in this form. This means any image attributes can be “injected” directly into any markup; it could be TXP tags, it could be content, it could be javascript, or CSS; anything.

Pagination works the same way, allowing you to specify how users can step through your image galleries.

There is also a special “collate” mode that allows you to collect all image attributes together into a series of big long lists without calling the form every time. The form/container is then only processed once at the end.

Between these two modes you should be able to realise any gallerying solution; now and in future.

Place one or more smd_gallery tags in an article, page or form, and supply any of the following options to configure it. The attributes are grouped by function to make it easier on your eyes / sanity.



  • id : list of image IDs to display. May be integers or ranges, for example id="5, 42, 8-11" would grab images 5, 8, 9, 10, 11 and 42. Use ‘!’ in front of a number or range to exclude those images. Use ‘?’ and the name of a TXP field to read the list of image IDs from that field, e.g. id=?article_image"
  • name : list of image names to display. You can either specify exact matches, e.g. name="lion.jpg, tiger.jpg" or regular expression matches by appending :regex to terms. For example, name="lion:regex" would match lion.jpg, lioness.jpg and megalion.jpg. Alternatively, name="^lion:regex" would only match images that start with ‘lion’. Use ‘!’ in front of names to exclude those images. Use ‘?’ and the name of a TXP field to read the list of image names/regexes from that field, e.g. name=?filenames" to read them from a custom field of that name.
    If you want to negate a regular expression, things may get tricky if you are using meta characters; in this case it is better to set your regular expression up in, say, a txp:variable (or an article field) and use name="!var_name:regex".
    You can mix exact matches and regex matches in the same name attribute if you wish. The colon can be altered with paramdelim — this is sometimes necessary if you are using character classes such as [[:digit:]] in your regular expression.
  • category : list of image categories to display. You may specify fixed-name categories (e.g. “animals”) or a’?’ followed by an article field name. e.g. category="animals, art-?thisid" would grab all images from category “animals” and category “art-42” (assuming the current article has an id of 42). Use ‘!’ to exclude the given category or field.
    Fields may themselves contain lists of categories. The ‘?’ field names may be combined (e.g. ?s-?article_image) but be aware that custom field names may contain spaces if strictfields="0"
  • sublevel : an integer that specifies how many ‘levels’ down to traverse each matching category. sublevel="0" (the default) is only the top-level; 1 = top-level plus the 1st sub-cat; 2 = top-level plus the next 2 sub-cats, and so on. sublevel="all" is all sub-cats
  • author : filter images by this list of author login names
  • extension : filter images by this list of file extensions (without the leading dot)
  • aspect : filter images by this list of aspect ratios. Choose from any of portrait, landscape or square
  • dimensions : filter images matching the given dimensions. Specify up to two values. The first is the width and the second is the height. If you wish to specify minimum or maximum dimensions, add >, >=, < or <= before the value. For example, dimensions=">=1024, >=768" would only show images greater than or equal to 1024 × 768 pixels
  • sort : re-order the images by category (the default), name, date, id (the default if using an id), file extension, alt, caption, author, width, height, thumb_width, thumb_height, hasthumb in either ascending or descending order. Two special cases exist: fixed maintains the order you specified in the id and/or category attribute, while random shuffles the order.
    Note that if random appears as the first item in the list, random images will be pulled from the database and they will then be sorted according to the order listed after it. If random appears anywhere else in the list, any sort items before it will determine the order of data pulled from the database, and the results will then be ordered randomly. In the 2nd case, any items listed after ‘random’ will be ignored, but fixed is still honoured

Limits / offsets / sizes

  • limit : the maximum number of images to show per page. 0 (the default) or omitted = unlimited
  • maxlimit : the absolute maximum number of image to pull from the database. Must be greater than 0
  • offset : skip this many images and start displaying them thereafter
  • thumblimit : the maximum number of thumbnails to show. 0 or omitted = all thumbs. Note that this differs from limit; you can launch a 20-image gallery but only show 1 thumbnail on the page. Be aware that if you are showing multiple categories from a single tag, you will see thumblimit thumbnails at each change in category. If you don’t want this, set onchange to something else. See the {object} replacement tag
  • grouplimit : the maximum number of images to put on the page, per group. A group is considered any set of images (e.g. all images from one category) so this can be used to only display N images at each change in category. A concrete example is displaying a thumbnail that launches a gallery showing the 5 most recent works from each author. Without thumblimit="1" grouplimit="5" the number of images in the group would be unlimited. See example 12 for more
  • thumboffset : skip this many thumbs before displaying thumblimit thumbnails
  • thumbsize : takes one or two comma-separated numbers to specify width and/or height of all your gallery thumbnails. The default is in pixels if you don’t specify units. Missing out one or the other parameter (i.e. having an “empty” parameter before or after the comma) will only set one of the dimensions. Use a single value to make square thumbs. If you omit either or both, the corresponding value will be read from the database
  • imgsize : identical to thumbsize but for the full size images

Forms and paging

  • form : the TXP form used to layout your matching images. Without this attribute the plugin acts as a container tag. Without a container, the plugin displays each full-size image, hyperlinked
  • pageform : the TXP form used to specify the layout of your paging navigation
  • paging : switch paging on without having to specify a pageform. When this is used, all page replacement tags become available in the gallery replacement tags as well
  • pagepos : the position of the paging block. Options are below (the default), above, or both of them separated by delim
  • objectform : the TXP form used to specify the layout of your {object} replacement tag. You can use all the standard gallery replacement tags with the exception of {object} itself! Uses a hyperlinked image if no form is specified
  • countform : list of TXP forms to use when certain numbered images are reached. See count forms and example 10. This has no effect in collate mode
  • countpos : default position of the countforms. Either above (the default), below, or both of them separated by delim. Can be overridden on a per-form basis

Grouping images

  • onchange : a list of attributes to “watch”. It tells the plugin that you want to be notified when items in this list change compared to the previous image. Under normal circumstances this should be the same as your sort parameter or you may get some freaky results! It defaults to category.
    This is very useful for splitting galleries at every change in category and displaying the category title above each group. Items you watch are added to the list of replacement tags and are available by putting “onchange:” in front of their name (e.g. {onchange:category} — see example 6 for more). The colon delimiter can be changed with paramdelim.
    You can also elect to defer processing of onchange events to a form. To do so, specify a form after your watch item like this category_title:my_form. In my_form you can put any markup and replacement tags. See example 11 for more.
    Another way of using this attribute is with the special prefix smd_every:n which will trigger a group change every Nth image. Note it can’t be used to watch specific things in this mode; it is only used to trigger grouptag changes
  • onchangewraptag : the (X)HTML tag to surround any onchange elements you are watching, e.g. onchangewraptag="h3"
  • onchangeclass : the CSS class name tro apply to the wraptag of any onchange elements you are watching
  • grouptag : the (X)HTML tag to make available as a replacement so you can wrap groups of elements at each onchange. Default: unset. See examples 6 for more on the grouptagstart / grouptagend replacement tags
  • groupclass : the CSS class name applied to any grouptag

Tag/class/formatting attributes

  • wraptag : the (X)HTML tag to surround the entire gallery, e.g. wraptag="div"
  • break : the (X)HTML tag to surround each thumbnail
  • class : the CSS class name applied to the wraptag
  • breakclass : the CSS class name applied to the break elements
  • html_id : the name of an HTML id attribute to apply to the wraptag
  • navwraptag : the (X)HTML tag to surround the entire pageform, e.g. wraptag="div". Default: ul
  • navbreak : the (X)HTML tag to surround each item within the pageform. Default: li
  • navclass : the CSS class name of the navigation wraptag. Default: smd_gallery_nav
  • emptyclass : the CSS class name of the navigation items that are not links. Default: empty
  • format (only if using {date}) : allows you to change the date format used. Can take any strftime() values. Defaults to the date system as set in the site’s prefs
  • lang (only if using {date}) : sets the language code of the date format
  • gmt (only if using {date}) : returns either local time according to the set time zone preferences (0), or GMT time (1). Default: 0

Plugin customisation

  • delim : change the delimiter for specifying attribute lists. Default is comma (,)
  • paramdelim : change the delimiter for specifying inter-parameter attributes. Default is colon (:)
  • collate : switch the plugin into collate mode
  • collatedelim : change the delimiter between each collated item. Default is comma (,)
  • combo : specify your own custom replacement tags
  • escape : list of replacement variable names to ‘escape’, in other words convert any HTML tags to their character entity equivalents. Set to escape="" to turn this feature off. You can escape your own combos. Default: alt, title, caption
  • strictfields : when using ‘?’ or ‘!’ fields, spaces are allowed in field names. Set strictfields="1" to forbid spaces. Default: 0
  • galleryid : under normal circumstances you should never need this. Each gallery is assigned a unique ID based on the supplied attributes so you may use more than one gallery on a page and navigate them independently. In the unlikely event that two identical IDs are generated you can override the ID for a gallery by using this attribute.
    Internally the plugin generates a 32-character hash string for each tag, then picks a 4-char code from this string (it takes every 6th character by default). You can supply a unique fixed string (e.g. galleryid="MyGal") or give it a question mark and 2 numbers separated by a colon (e.g. galleryid="?5:4"). The first number is the length of the final string to generate, the second number is how many characters to skip in the 32-char string each time it picks one.
    In this case it generates a 5-character string from the characters it finds at positions 1,5,9,13, and 17. If you omit the 2nd number (e.g. galleryid="?6") it will assume it’s an increment of 1
  • thumb : under normal operation, thumbnails use the ‘t’ image in your images directory and the full size pictures don’t. If you wish to redefine this you may specify up to two values separated by a colon. The first indicates the state of the full size image, and the second is the state of the thumbnail:
    • thumb=0:1 — fullsize = regular image : thumbnail = thumb
    • thumb=1:0 — fullsize = thumb : thumbnail = regular image
    • thumb=0:0 (or thumb=0) — fullsize = regular image : thumbnail = regular image
    • thumb=1:1 (or thumb=1) — fullsize = thumb : thumbnail = thumb
  • text : display the given text instead of thumbnails. The text can contain ? article fields

Special attributes

  • columns : give a comma-separated list of additional columns you would like to pull from the database. Each item you specify is split into three parts: table.column:replacement name. The only mandatory part is the replacement name, since table defaults to txp_image, and the column defaults to the same name as the replacement you specify.
    For example, if you have installed the cno_image_order plugin you could use columns="position", since the plugin adds the ‘position’ column to txp_image. You could then sort by position and also display the image’s {position}. If you wished to rename the variable to, say, imgpos you would use columns="position:imgpos". Note that if you specify the table name you must also include the table prefix if you have used one.
  • directory : (experimental) read images from a list of directories (or URLs) instead of the TXP database
  • match : limit the images and directories chosen in directory mode. Give a list of words to include or !exclude and any matching files or directories will be chosen or ignored, respectively. The match terms are automatically assumed to be “wild” so any part of the file name / path will trigger the match
  • debug : turn on diagnostics. Varying levels of verbosity from 0 (none) to 4 (a lot)

The form is where you design what every thumbnail will look like on the screen. You do this by specifying HTML markup or TXP tags as normal. In key places where you want, for example, an image ID / alt tag / image width to be displayed, you specify special replacement tags, detailed below. These are replaced for each image in turn, thus building up the gallery.

In collate mode, the image details are instead made into lists. The form is only processed once and the replacement tags output the entire list.

  • {id} : image ID (or, in directory mode, the filename without its extension)
  • {name} : full image filename as defined in the database, usually including extension
  • {ext} : file extension, including dot
  • {category} : image category name
  • {category_title} : image category title
  • {author} : who uploaded the image
  • {url} : URL of the fullsize image
  • {thumburl} : URL of the thumbnail
  • {imagepath} : directory the image is in
  • {imagedef} : just the file name part of the image (e.g. 5.jpg)
  • {thumbdef} : just the file name part of the thumbnail (e.g. 5t.jpg)
  • {alt} : alt text
  • {title} or {caption} : caption
  • {date} : image upload date
  • {width} : image width
  • {height} : image height
  • {wunits} : image width units (e.g. px, %, em, etc.)
  • {hunits} : image height units
  • {thumbwidth} : thumbnail width
  • {thumbheight} : thumbnail height
  • {thumbwunits} : thumbnail width units (e.g. px, %, em, etc.)
  • {thumbhunits} : thumbnail height units
  • {hasthumb} : if the image has an associated thumbnail or not
  • {galleryid} : gallery id that you or the plugin assigned
  • {object} : a special item containing either the text OR the image tag of the corresponding thumbnail, but only if thumblimit allows it. e.g. if thumblimit="1" this variable is only set for the first thumbnail in the list; every other time it is empty
  • {counter} : image counter, starting from 1 and incrementing each time
  • {index} : index counter (zero-based — probably not much use)
  • {thumbcounter} : thumbnail image counter, starting from 1. Note it is ‘reset’ whenever an element given in onchange differs from the previous item
  • {thumbindex} : index counter (zero-based — probably not much use). It is reset like {thumbcounter}
  • {totalimages} : total number of images matched on this page
  • {maximages} : absolute maximum number of images across all pages

In addition, if either paging="1" or pageform have been specified, all the paging replacement tags are available too. If those aren’t enough, you can create your own by grouping combinations of the above, optionally with article variables such as ?excerpt, ?keywords, ?article_image, etc.

Other tags are added depending if you are watching for onchange elements, or if you have specified a grouptag. If you added onchange="author, category" then every time the author or category changed compared to the previous image, one or two new replacement tags would become available; namely {onchange:author} and {onchange:category). Using onchange with smd_every does not add a new replacement tag as it is merely used to count.

If you used grouptag="div" as well, you would be given two new replacement tags labelled grouptagstart and grouptagend. See example 6 for details.

Paging form

Add gallery navigation to your page. Works in a similar manner to the gallery form: a series of replacement tags govern which gallery navigation items are available. You could choose to only show next/prev. Or perhaps 1st page/last page. Or numbered page links.

Replacement tags: paging

  • {navfirst} : first page (default label: “First” / MLP)
  • {navprev} : previous page (default label: “«” / MLP)
  • {navearlier} : any page numbers before the current page
  • {navthisurl} : current page with a URL link to itself
  • {navthis} : current page without a URL link
  • {navlater} : any page numbers after the current page
  • {navnext} : next page (default label: “»” / MLP)
  • {navlast} : last page (default label: “Last” / MLP)
  • {navfirstpageurl} : raw URL to first page
  • {navprevpageurl} : raw URL to previous page
  • {navthispageurl} : raw URL to current page
  • {navnextpageurl} : raw URL to next page
  • {navlastpageurl} : raw URL to last page
  • {totalimages} : total number of images matched on the current page
  • {totalpages} : total number of pages in this collection
  • {maximages} : absolute maximum number of images across all pages

The current page has a fixed class of ‘current’ and each item is, by default, a <li> for easy styling. Custom labels are defined directly in the form itself; for example to label the link that takes users to the first page of the gallery as “1st”, use:


With this syntax you can label navfirst, navlast, navprev, navnext and navthis (the ‘:’ delimiter in this case is specified by paramdelim). You can use this mechanism to read MLP snippets, e.g:


You are not limited to text labels. Images could be used:

{navlast: <img src="images/last.png" />}

You can override the number of items displayed by navearlier and navlater by specifying a colon and a number. So to only show 2 items to the left of the current page and 3 items to the right, use {navearlier:2} {navlater:3} in your form. If you were on page 9 of 15, {navearlier:4} {navlater:3} would show << 5 6 7 8 9 10 11 12 >>

Currently {navearlier} and {navlater} only display arabic numerals. Any ideas on how to offer other character sets greatly appreciated.

Count forms

Sometimes it’s handy to be able to take action only when certain images are reached; for example:

  • only display something on the first or last image
  • start a new HTML ‘row’ every 3rd image
  • break your gallery up with an advert

This can be done with smd_if but since it is such a common feature, the plugin has the ability built in. All replacement tags are available within your countforms so you can do some pretty neat stuff. It is best explained by example:

  • countform="1:gal_head" : this would output the form gal_head only when the first image is displayed
  • countform="{totalimages}:gal_foot" : this would output the form gal_foot only when the last image is displayed
  • countform="1:gal_head, {totalimages}:gal_foot" : do both of the above
  • countform="1:gal_head, {totalimages}:gal_foot:smd_below" : the same as the previous example, but put the contents below the last image (by default, all output appears above the given image)
  • countform="4:9:smd_below:gal_ad" : output gal_ad after the 4th and 9th images only
  • countform="4-9:smd_below:gal_ad" : output gal_ad after the 4th, 5th, 6th, 7th, 8th and 9th images only
  • countform="smd_every:3:gal_row" : output gal_row before every 3rd image
  • countform="smd_every:2:!8:gal_row" : output gal_row before every even image but not on the 8th image
  • countform=":gal_row" : use an empty first value to output gal_row before every image. This may seem useless, but it means you can use two, three, four… forms (or any number of forms and the container) simultaneously to iterate over the same gallery. Or use the same form at different frequencies. Get creative!
  • countform=":!5:gal_row:smd_below" : again, missing out the first value will output gal_row after every image, but this time skipping the 5th image

The , and : can be overridden with the delim and paramdelim attributes, respectively.

There are a few rules when using the countform:

  • numbers must appear before the form name
  • the form name is usually the last item in the colon-separated list, though you can put smd_above or smd_below last if you wish
  • smd_every only affects the value that immediately follows it, e.g. countform="smd_every:5:7:12:my_ad" will output my_ad at every 5th image, as well as only on the 7th and 12th images. Thus the sequence would be 5, 7, 10, 12, 15, 20, 25, 30…
  • if using smd_every, it must appear as the first item. For example countform="4:the_fourth, 6:smd_every:5:my_ad" is invalid, but countform="4:the_fourth, smd_every:5:6:my_ad" is OK

See example 10 for more.


If the built-in replacement tags aren’t enough for your needs or you find yourself repeating the same combination and want to save yourself some typing, you can define your own. The syntax is:

combo="newtag1:definition, newtag2:definition, ..."

‘definition’ can be any fixed text, any existing replacement tag, or any ‘?’ article variable so you can get really wild here, for example:

combo="imgin:found in ?s [tagged with ?keywords. Photo by {author}]"

Once defined, {imgin} is available to your gallery form and might be replaced with “found in zoo [tagged with zebra, africa, stripes. Photo by Bloke]”. $pretext is also available for those geeks who know what’s in it (temporarily use debug="4" to view all available article variables).

One thing to watch out for is that the space character isn’t necessarily a delimiter for ? variables (because custom fields can have spaces in them). So combo="doesnotwork:?s in ?category1" will look for a variable labelled “s in” and one called “category1”. Only one of those exists! Clever use of parentheses or other punctuation can work round this. Or use strictfields="0" to turn off the use of spaces in custom field names.

Collate mode

If you want to get really funky you can put the plugin into a 2nd mode called “collation mode”. This means your chosen form is not executed for every image; it is only used once at the very end of the list, after all the images have been internally “collected”. In effect, the plugin builds up a giant array of all matching images ready for you to output them all in one go. This is very handy for doing slideshows and is best explained by example:


switches collation mode on. If the plugin matched 4 images and you were to use the replacement tag {name} in your form like this:

The matching images: {name}

you might get this:

The matching images: heron.jpg,penguin.jpg,emu.jpg,puffin.jpg

Sometimes it’s useful to be able to put quotes around each item so you can tell collate mode to do that instead:


You would then get:

The matching images: "heron.jpg","penguin.jpg","emu.jpg","puffin.jpg"

The delimiter (a comma in this case) can be overridden with the delim attribute. You may use sglquote to wrap single quotes round the items, or “dblquote” as a synonym for “quote” if you prefer. You can quote more than one thing at once by specifying the items as a delimited list:


Yes, you can use combos! The delimiter used between items can be overriden with the collatedelim attribute.

The second special feature of collation mode is that you do not have to always output the entire list. You can grab individual entities from within the internal array by using the ‘#’ notation thus:

{name} might output "heron.jpg","penguin.jpg","emu.jpg","puffin.jpg" (as before)
{name#1} would only output heron.jpg
{name#3} would only output emu.jpg

Note that when pulling out individual entries they do not get quotes added to them, regardless of whether you used quote or not. This is because it is a single item so you can easily put the quotes in the form itself (viz: "{name#2}")

Messing around with pulling out individual items and lists can yield some very interesting results and allows some completely wacky galleries to be generated. Try combining smd_gallery tags with <txp:if_different> for a real mind scramble :-)


The examples all use the classic zoo website. Let’s get some pictures out of the database…

Example 1: simple / lightboxed gallery

<txp:smd_gallery category="animals" sublevel="all" form="gallery" />

That pulls out all pictures from the animals category, including all sub-categories, and passes them to the form called ‘gallery’ for processing. The form could be:

<img class="animage" src="{url}" alt="{alt}" />
<div class="acaption">{title}</div>

That means, for every matched image, substitute its URL, alt and title tags into the relevant places. Thus you get a series of images on the page, which you can style accordingly.

For a more fancy output using, say, slimbox, you could load the relevant libraries and styles in the <head> of your page:

<script type="text/javascript" src="/js/mootools.js"></script>
<script type="text/javascript" src="/js/slimbox.js"></script>
<link rel="stylesheet" type="text/css" href="/css/slimbox.css" />

Then your ‘gallery’ form could be:

<a rel="lightbox-{category}" href="{url}"
     title="A picture of {caption}">
 <txp:thumbnail id="{id}" />

Voila! Using the same smd_gallery tag you have changed the way the gallery renders from a simple list to a full-featured slimbox. With virtually the same form you can switch the output to thickbox, lightbox, litebox, moonbox or whatever-you-like-box depending on which libraries you load. Follow the instructions for your favourite effect and plug it into smd_gallery.

Example 2: launch from one image

A common request is to be able to “launch” a slimbox gallery from a single image or text link. Using a single image:

<txp:smd_gallery category="animals"
     form="gallery" thumblimit="1" />

The form will use the special {object} replacement tag so it only displays the thumbnail if the value of thumblimit has not been reached:

<a rel="lightbox-smd" href="{url}"
     title="A picture of {title}">

Change the start image by specifying thumboffset — note this will also start the lightbox effect from the image you choose. If you want to start on a specific image in position 1, use the id attribute to bring it to the top of the list, or change the sort order.

If you wanted to launch the gallery from a text link, add something like text="Click to start lightbox".

Example 3: popup gallery

To achieve an effect similar to rss_thumbpop, add an image and caption placeholder outside the call to smd_gallery, then include your smd_gallery tag as usual. This time we are only interested in all the pictures from the categories up to two levels below both “animals”, plus whichever categories are listed in my_custom_field and the images with IDs 25, 38, 39, 40 and 42:

<img id="fullsize" src="/images/empty.jpg" />
<span id="fullcaption"></span>
<txp:smd_gallery sublevel="2"
     category="animals, ?my_custom_field"
     id="25, 42, 38-40" form="gallery" />

The gallery form looks scary but is only a thumbnail image surrounded by a simple anchor tag with two actions assigned to it: a mouseover to copy the picture and caption into the placeholder; and a mouseout to remove them:

<a href="{url}" title="{title}"
     onmouseover="document.getElementById('fullsize').src = this.href;
     document.getElementById('fullcaption').innerHTML = this.title; return false;"
     onmouseout="document.getElementById('fullsize').src = '/images/17.jpg';
     document.getElementById('fullcaption').innerHTML = ''; return false;">
  <img src="{thumburl}" alt="{alt}" />

Note there are much neater ways of doing this (e.g. with jQuery) and it’s not recommended to use this form in a live site, but it gives a flavour of what is possible.

Example 4: slideshow

This one uses collate mode but is not much more difficult to understand. In your <head> section:

<script type="text/javascript" src="/js/mootools.js"></script>
<script type="text/javascript" src="/js/slideshow.js"></script>

The tag:

  category="birds, fish" form="gallery"
  collate="quote:{imglist}:{alt}" />

That pulls all pictures from the birds and fish categories. Although technically unnecessary, a combo has been defined to show how it can be used. This combo is called imglist and is defined as the image’s ID number plus its extension. We use this in the collate attribute and tell it to put double quotes round every item in ‘imglist’ and ‘alt’. Then we can put these values into the necessary javascript in the gallery form to generate the slideshow:

<div class="slideshow" id="slideshow1">
 <img src="<txp:site_url />images/{id#1}.jpg"
     alt="{alt#1}" width="{width#1}" height="{height#1}" />

<script type="text/javascript">
myShow1 = new Slideshow("slideshow1",
  { hu: "<txp:site_url />images/",
    images: [{imglist}],
    captions: [{alt}],
    classes: ["prev","next","active"],
    type: "fade"

Note that the initial portion (in the div and img tags) uses the ‘#’ notation because we only want to display one image to “start” the slideshow. In this case we’re using the first image in the list, but you can change the #1 for #42 if you wanted to show the forty-second image instead! The part in the script tag uses the full, quoted lists because that’s the format the javascript requires.

Example 5: pagination

To add paging to a gallery you use the limit attribute to show a number of thumbs per page. For a paged thumbpop gallery that shows five thumbs per page:

<img id="fullsize" src="/images/empty.jpg" />
<span id="fullcaption"></span>
<txp:smd_gallery category="animals"
  form="gallery" pageform="gallery_nav"
  limit="5" />

The ‘gallery’ form is identical to the one in example 4, while your gallery_nav form might look like this:

<div class="total"># of pics: {totalimages}</div>
     {navfirst} {navprev}
     {navearlier} {navthis} {navlater}
     {navnext} {navlast}

That might render something similar to this below the thumbs:

# of pics: 38
     First < 1 2 3 4 5 6 7 8 > Last

Example 6: onchange

If you want to simulate multiple galleries from one smd_gallery tag you can use onchange to “watch” for when certain attributes of images change and insert special tags only when something changes. In this regard it acts like a souped-up version of TXP’s built-in <txp:if_different> tag.

You can watch the usual things like category, author, width, height, extension and so on:

     category="birds, fish" form="gallery"
     onchangewraptag="h3" />

Since the plugin normally sorts by category, this will have the effect of adding one replacement tag {onchange:category_title} at the very beginning of the thumb list and also when the category switches from ‘birds’ to ‘fish’. Thus your gallery form could be:

<a href="{url}" rel="lightbox-{category}">

That would make two lightboxable sets of thumbnails with a heading 3 above each group containing the category title.

Note that if you add thumblimit="1" to the smd_gallery tag you can show just one thumbnail in each group, with headings above each thumb. Visitors clicking the thumb will launch the lightbox and be able to browse the relevant category. If you want to make sure that they can only browse six images in each category set, add grouplimit="6".

An extra pair of replacement tags are available if you wish to wrap the objects themselves to group them. Use the grouptag and groupclass attributes to set it up, then two new replacement tags called grouptagstart and grouptagend become available. They are conditional and are only populated when the attributes you are watching/sorting by change. Use it like this:

<txp:smd_gallery id="?article_image"
     category="birds, fish" form="gallery"
     grouptag="div" groupclass="box" />
<a href="{url}" rel="lightbox-{category}">

Note that you can move the grouptagstart to surround the onchanged title if you wish.

Example 7: smd_every

You can also trigger an onchange event every nth image:

<txp:smd_gallery category="frontpage"
     limit="9" sort="random"
     grouptag="ul" groupclass="slideshow">
      <a href="<txp:permlink id="{alt}" />">
         <img src="{thumburl}" alt="" />

Example 8: uncategorized images

Sometimes you might wish to extract images that do not have a category assigned. You need to use the special value SMD_EMPTY for this:

<txp:smd_gallery category="SMD_EMPTY, shoes" />

You can also negate the logic so you can extract all images that have some (any) category assigned to them:

<txp:smd_gallery category="!SMD_EMPTY" />

Example 9: {object} and objectform

The default {object} outputs a simple hyperlinked thumbnail. If you want something a bit more exotic, like launching a shadowbox effect from a single thumbnail that also has the caption beneath it, you need to customise the {object} via the objectform attribute. Put a list of image IDs in your article image field and then:

<txp:smd_gallery thumblimit="1"
     id="?article_image" wraptag="div"
     class="thumbs" objectform="my_obj"
  <a rel="shadowbox[{artid}];

And in my_obj, you could put:

<txp:thumbnail id="{id}" /><br />{title}

Notice how the replacement tags still work in the objectform? This allows you to build up a complete layout for the launchable thumbnail and have it only rendered once on the page. The rest of the container in this example renders all the “hidden” images in the shadowbox gallery.

Example 10: countform

<txp:smd_gallery category="animals"
<txp:thumbnail id="{id}" />

Note that countpos is set to below in this example so all output appears after the given images. If you made the following three forms, your tag would split the gallery into ‘rows’ of 3 images:

gal_a: <div class="newrow">
gal_b: </div><div class="newrow">
gal_c: </div>

Breaking the countform attribute down into its components, you can see that:

  • 1:gal_a:smd_above adds the ‘newrow’ div above the first image
  • {totalimages}:gal_c adds the closing div below the last image on this page
  • smd_every:3:!{totalimages}:gal_b adds a closing and then an opening div after every 3rd image, except on the last image. If we didn’t put the exception in, and you had 12 thumbnails in your gallery (which is divisible by 3!) you would see the contents of gal2 after the last image as well

Example 11: Using an onchange form

     category="birds, fish"
<a href="{url}" rel="lightbox-{category}">

and in form oc_form:

<div id="{category}"

Example 12: Portfolio landing page

Here we will render a gallery for each artist on a gallery site. Arrange your image categories so they are children of a parent image category:

  |--> monet
  |--> van_gogh
  |--> turner
  |--> dali
  |--> ...

Then of course, upload your images and assign them to the appropriate artist category.

     category="portfolio" sublevel="1"
     onchangewraptag="h3" thumblimit="1"
     grouplimit="5" sort="category asc, date desc"
<a href="{url}" rel="lightbox-{category}">

In Form full_link:

<txp:thumbnail id="{id}" />
   See <a href="/artists/{category}">all images by {category_title}</a>.

That will grab each artist category and display a thumbnail of the most recent work submitted by each author under their own heading. When you click the thumbnail it launches the lightbox gallery and allows you to navigate through the five most recent pictures submitted. Beneath the thumbnail is a link to an individual article that could show that artists’s complete works and a bio.


All available versions and changes are listed here.


  • 14 Feb 08 | 0.1 | Initial release – Happy Valentines Day :-)
  • 19 Feb 08 | 0.2 | Added {galleryid} (thanks rloaderro) and some skeleton docs


  • 11 Mar 08 | 0.3 | Official public release. Fixed silly empty field bug; added {counter}, {index} and the totals (all thanks jakob)
  • 15 Mar 08 | 0.31 | Fixed a couple of undefined indexes and added {category_title} (thanks jstubbs)
  • 17 Mar 08 | 0.32 | Fixed another undefined index and removed bogus call to smd_lib (both thanks secundar)
  • 21 Mar 08 | 0.33 | Did v0.31 properly, including table prefix (thanks nardo)
  • 01 Apr 08 | 0.34 | Fixed SQL parenthesis bug ; added emptyclass and {maximages} (thanks the_ghost)
  • 08 Apr 08 | 0.4 | Changed thumb to allow thumb/fullsize swapping ; Added thumbchange, thumbchangewraptag, thumbchangeclass, {thumbindex}, {thumbcounter} and the {changed:*} replacement tags (thanks fuls)
  • 26 May 08 | 0.41 | Fixed Directory separator (thanks cuda) ; added raw page URLs to the nav replacement array and made the nav array available in the standard replacements array (thanks visualpeople)
  • 27 May 08 | 0.42 | Added pagepos and made page blocks independent of thumb block (thanks duchamp)
  • 10 Jun 08 | 0.43 | Fixed sort=“fixed” when using limit (thanks robin746) ; added per-group onchange wrapping and allowed fixed sorting of categories (thanks jstubbs) ; deprecated thumbchange* and renamed as onchange* ; fixed $idx counter problem
  • 10 Jun 08 | 0.44 | Attempt #2 at per-group onchange wrapping (thanks again jstubbs)
  • 14 Jul 08 | 0.45 | Fixed lack of output when not using categories (thanks robin746)
  • 16 Nov 08 | 0.46 | Added collatedelim (thanks curiouz) ; fixed (I hope) the category / id bug from 0.44 and 0.45 (thanks robin746/nardo)
  • 13 Feb 09 | 0.5 | Requires smd_lib ; added MLP support (thanks net-carver) ; added support for displaying uncategorised images (thanks xzamen) ; ‘?’ vars expanded to link / image / file / <txp:variable /> and URL variable ; new attributes: escape, html_id, format, gmt, lang (thanks maniqui), strictfields ; improved {object} support and added objectform (thanks tye/rvturnage) ; {title} == {caption} at last! ; removed thumbchange* attributes ; improved support for table extensions (via the columns attribute: thanks RedFox) ; added smd_every syntax to onchange (thanks jakob) ; fixed offset bug (thanks feragnoli)
  • 01 Mar 09 | 0.51 | Added countform and countpos ; fixed {hasthumb} warning
  • 16 Nov 09 | 0.52 | TXP 4.2.0 only ; added database thumbnail height and width support ; added aspect, dimensions, author, extension and imgsize attributes ; fixed quote parsing in escape attribute and warning when using fixed sorting (both thanks maniqui)
  • 01 Jan 10 | 0.53 | Added onchange form capability (thanks MattD)
  • 01 Feb 10 | 0.54 | Multiple images not displayed if multiple categories exist with the same name and different title
  • 01 Mar 10 | 0.55 | Added name filtering
  • 10 Mar 10 | 0.6 | Simplified query to eliminate errors with uncategorised images being omitted from the results; allowed countform ranges ; added grouplimit
  • 03 Apr 10 | 0.61 | Added breakclass (thanks the_ghost)
  • 06 Apr 10 | 0.62 | Fixed {onchange:category_title} and {grouptagend} (thanks jan)


This plugin wouldn’t have existed without the awesome mind of Robert Wetzlmayr. His wet_for_each_image plugin is true genius; this simply stands on the shoulders of that idea and rolls in a souped up version of the thumbnail generation engine from smd_slimbox. To that end, the plugin is also indebted to anyone who has posted features or bug reports to me or the smd_slimbox thread. You’re all marvellous.

Source code

If you’d rather wander aimlessly through thousands of lines of PHP source code, you’ll need to step into the view source page.

Legacy software

If, for some inexplicable reason, you need last century's version of a plugin, it can probably be found on the plugin archive page.

Experimental software

If you’re feeling brave, or fancy chucking your keys in the bowl, you can test out some of my beta code. It can be found on the plugin beta page.