A Tiny Post Content Template Interpreter

Although this plugin is still actively supported it is no longer being actively developed. The reason for this is that I now believe that the rendition logic should run in the front-end client not in the back-end server. I think the future of WordPress is as a back-end REST server for a front-end Backbone.js client.

A post content template is text made of HTML, WordPress shortcodes and template variables of the form $#alpha#. Template variables will have string values. A template is instantiated by replacing template variables with their string values. Template variables can be assigned a value by using a HTML comment as an assignment statement:

<!-- $#alpha# = "beta"; -->

The instantiation of the following template:

[mt_template]
    <!-- $#alpha# = "This is the value of alpha."; -->
    <h1>$#alpha#</h1>
[/mt_template]

is the HTML:

<h1>This is the value of alpha.</h1>

You can try this for yourself by entering this into your post content and viewing the page or try the convenient Shortcode Tester. N.B. the post content editor must be in “Text” mode not “Visual” mode when entering templates. More usefully template variables can be assigned the value of a custom field by using an assignment statement of the form:

<!-- $#alpha# = beta; -->

Here the unquoted string beta is the name of a custom field and the value of the template variable $#alpha# will be set to the value of the custom field beta. (If beta is a multi-valued custom field then the value of $#alpha# will be set to the comma separated concatenation of the values of beta. Later you will see how iterators and indexes will allow you to access the values of beta individually.)

WordPress allows you to store anything as a value in custom fields. However, this post content template interpreter is designed to work only with custom field values that are simple scalars or an array of simple scalars – either as values from multiple rows in the MySQL table “wp_postmeta” with the same “meta_key” and “post_id” or from a custom field value that is a serialized array of simple scalars.

 

From version 1.2 the right hand side of an assignment may be an expression consisting of integers, single or double quoted strings and custom field names (with optional filter suffix) joined by an operator ‘*’, ‘/’, ‘%’, ‘+’, ‘-‘ or ‘&’ ( ‘&’ is the concatenation operator since ‘.’ is already the member operator ) and grouped by possibly nested parenthesis. The operator precedence is given by the order ( ‘*’, ‘/’, ‘%’ ), ( ‘+’, ‘-‘ ) and ‘&’ where operators in the same parenthetical group have the same precedence. Note that this is slightly different from PHP where ‘+’ and ‘&’ have the same preference. Associativity is always left associative. If an intermediate result is numeric the result is stored as an integer otherwise the result is stored as a string. The final result is always returned as a string.

<!-- $#alpha# = 'abc' & ( ( 1 + 10 ) + 100 ) * 8; -->

Here the value of $#alpha# is ‘abc888’. If abc was unquoted then abc would be interpreted as the name of a custom field and the value of that custom field would replace abc.

Template Shortcode

A post content template can be saved and used in multiple posts. For example you can save the post content template:

<!-- $#title# = page_title; -->
<h1>$#title#</h1>


with name “show_page_title” and instantiate this template in a post by using the shortcode:

[mt_template name="show_page_title"][/mt_template]


Since each instantiation will use the value of the custom field page_title specific to each post each instantiation will be customized for each post. Although, WordPress does not require the end tag “[/mt_template]” the post content interpreter which may also parse the post content does require the end tag.

The mt_template shortcode allows you to assign string values to template variables in the named post content template using shortcode attributes:

[mt_template name="alpha" beta="gamma" delta="epsilon"][/mt_template]


Here the string values “gamma” and “epsilon” are assigned to the template variables $#beta# and $#delta#, respectively. The attribute values in a shortcode are strings (not custom field names) but can contain previously assigned template variables which will be interpolated, e.g., the following is valid:

<!-- $#alpha# = beta; -->
[mt_template name="gamma" delta="$#alpha# is an epsilon"][/mt_template]


Since WordPress converts all attribute names to lowercase, you should use only lowercase letters, numbers and the underscore in template variable names. If a template variable is assigned a value as a shortcode attribute and also assigned a value using an HTML comment then the assignment as a shortcode attribute has precedence. The easiest way to enter the shortcode of a previously saved post content template is to use the “Insert Template” dialog box.

Iterators

To use the values of custom fields in attribute values the mt_template shortcode has an iterator attribute:

[mt_template name="alpha" iterator="beta:gamma"][/mt_template]


Here beta is a template variable in the post content template with name “alpha” and gamma is the name of a custom field. If the custom field gamma has a single value then the template will be instantiated once with the template variable $#beta# assigned to the value of the custom field gamma. However, if the custom field gamma has multiple values then the template will be instantiated multiple times with the template variable $#beta# assigned to each value of the custom field gamma in turn. Although a template shortcode can have at most one iterator attribute nested iterations can be achieved by nesting template shortcodes.

The "iterator" shortcode attribute has a another format that allows you to iterate over a list of strings:

[mt_template name="alpha" it="beta:'red';'green';'blue'"][/mt_template]


Here the template named "alpha" will be instantiated three times with the template variable "$#beta#" set to the string "red" then the string "green" and finally the string "blue". The interpreter accepts "it" as an abbreviation for "iterator".

Inline Templates

Instead of using a previously saved post content template a template shortcode can use an inline post content template by enclosing the template between the “[mt_template]” and “[\mt_template]” shortcode tags.

[mt_template iterator="i:alpha"]
    [mt_template1 iterator="j:$#i#" k="$#i#"]
        <li>$#k#: $#j#<li>
    [/mt_template1]
[/mt_template]


In this contrived example the values of the custom field alpha are assumed to be a list of custom field names. Since, WordPress cannot parse nested shortcodes the inner shortcode is “mt_template1” instead of “mt_template”. Shortcodes “mt_template1” to “mt_template9” can be used. Each template has its own variable scope. In this example the variable i from the outer template is not visible inside the inner template. However, the value of i is passed to the inner template through the inner template variable k.

Conditional Text Inclusion

Post content templates support conditional text inclusion using a if construct.

#if($#alpha#)#
HTML to include if condition is true
#else#
HTML to include if condition is false
#endif#


The condition is true if the template variable alpha exists and its value is not the empty string. A condition can also be an equality expression of the following forms:

#if( $#alpha#=$#beta# )#

#if($#alpha# = "gamma")#

#if($#alpha#='gamma')#


The first expression compares the values of the template variables alpha and beta. The other expressions compares the value of the template variable alpha with the string “gamma”. Spaces before and after the equal sign and parenthesis are optional. The #else# clause is optional and if constructs can be nested. From version 1.1 the comparison operators !=, <, <=, > and >= are also valid. From version 1.1.1 the condition can be a boolean combination of comparison expressions, e.g.

#if( $#alpha#="1" && $#beta#!="2" || $#gamma#>="3" || $#delta# )#

Filters

A filter is a function that is used to modify the value of a custom field. A filter function has two arguments – the custom field name and the custom field value and returns the modified value.

function field_name( $field_name, $field_value ) {
    return $field_name;
}

This filter returns the field name instead of the field value and is available as a predefined filter. A filter is applied to a custom field by appending the suffix “@filter_name” to a custom field.

<-- $#alpha# = beta@field_name; -->

The value of the template variable alpha will be set to name of the custom field beta instead of the value of the custom field beta which is in this contrived example just the string “beta”. (A more useful but not as simple example would have the right hand side of the assignment as “$#beta#@field_name”.) You can define and apply your own filters. The interpreter implements the following predefined filters:

filter name filter returns
@field_name field name
@count number of values in a multi-valued field
@indexes (or @indices) numeric indexes of a multi-valued field, e.g., if a field has 3 values then 0, 1, 2 is returned
@<0>, @<1>, @<2>, … @<n> returns the nth value of a multi-valued field. N.B., “<” not “[” since “[” punctuates shortcodes.

The filters “@indexes”, “@<0>”, “@<1>”, “@<2>”, … allow you to reference the individual values of a multi-valued custom field.

[mt_template it="i:alpha@indexes"]
    <!-- $#value# = alpha@<$#i#>; -->
    <li>alpha[$#i#] is $#value#.</li>
[/mt_template]


Note that the right hand side of an assignment statement can contain template variables. These will be interpolated before the assignment.

From version 1.1 negative indexes are allowed and specify offsets relative to the end of the array, e.g. alpha@<-1> is the last value of the multi-valued custom field alpha. @first and @last are aliases for @<0> and @<-1>, respectively.

From version 1.1 filters can have optional parameters, e.g.,

alpha@sprintf('The value is: %s',$)
beta@number_format($,2,'.',',')
gamma@substr($,0,5)


where $ specifies the value to be filtered. The optional parameters must be either a quoted string or an integer.

You can specify a chain of filters:

<!-- $#alpha# = beta@<-1>@substr($,3); -->


If you specify a chain of filters which includes an index filter the index filter should be the first filter as in the example above.

The Post Shortcode Attribute

Normally a post content template is evaluated in the context of the current post, i.e., the custom fields referenced by the template are the resolved using the current post. The shortcode attribute “post” allows you to specify a different post to use as the context to resolve the custom fields referenced by the template.

[mt_template post="117"]
    <!-- $#alpha# = beta; -->
    $#alpha#
[/mt_template]


Here the value of the template variable $#alpha# is set to the value of the custom field beta in the post with id 117 instead of value of the custom field beta in the current post. Instead of the literal numeric post id “117” you could have specified a template variable which would be interpolated, e.g., post=”$#alpha#”. However, if the current post has a custom field whose value is a post id then you can directly use that custom field.

[mt_template post="gamma"]
    <!-- $#alpha# = beta; -->
    $#alpha#
[/mt_template]


Assuming the value of custom field gamma in the current post is a post id then the value of the template variable $#alpha# is set to the value of the custom field beta in the post with post id equal to the value of the custom field gamma in the current post. If the custom field gamma is a multi-valued custom field then the template will be instantiated multiple times once for each post id in gamma.

The Post Member Operator

Alternatively, you can use the post member operator “.” to reference custom fields in a different post.

<!-- $#alpha# = beta.gamma; -->
<span>$#alpha#</span>


Assuming the value of the custom field beta is a post id then the value of the template variable $#alpha# will be set to the value of the custom field gamma in the post with id equal to the value of the custom field beta in the current post. The value of the custom field beta must be a single post id. If the custom field beta is multi-valued you can use the index filter to reference an individual value, e.g., “beta@<3>.gamma”

Download

The stable version can be downloaded from the WordPress repository. Version 1.2 can be downloaded from GitHub.

Known Problems

The WordPress "the_content" filter wptexturize sometimes texturizes the quote marks of shortcode parameters i.e. changes the straight quote marks to curly quote marks. This can break the parsers in the template interpreter. From version 1.1 you can optionally disable the filter wptexturize.