About Variable Context Tag Parser

Substitutes tags in a given text block with values from a context (or an array of contexts). Each context provider must be an instance of WireData. This means that almost any object from ProcessWire can be used by the parser to do substitutions.

Category Text Formatters
Textformatter modules that provide run-time formatting for blocks of text (typically used with Text/Textarea fields).
Release StateStable
Should be safe for use in production environments. *
Module Version2.2.0
Class NameTextformatterTagParser
Compatibility2.2, 2.4
Date AddedOctober 20, 2012
Last UpdatedJune 24, 2018
Recommended ByNew recommendations may take up to 1 day to appear.


Documentation in the readme on Github.


This module's files should be placed in /site/modules/TextformatterTagParser/
How to install or uninstall modules


Tag Parsing Textformatter Module For ProcessWire

Substitutes tags in a given text block with values from a context (or an array of contexts). Each context provider must be an instance of WireData. This means that almost any object from ProcessWire can be used by the parser to do substitutions.

Version 2.0 adds the ability to semi-randomly generate alternate texts from options embedded within your input.

Given an input string such as:

"Date: {datetime}\nUser: {name}\nIP:   {REMOTE_ADDR}"

…and a user object as context, you might get something like this as the result…

Date: 12th September 2012, 14:45
User: ryan

…of course, your mileage may vary.


  1. Copy TextformatterTagParser.module to your site/modules directory
  2. Login to the admin interface
  3. Navigate to the modules page
  4. Click the “Check for new modules”
  5. Click on the name “TextformatterTagParser” in the message that appears or scroll to the bottom of the screen to locate the correct entry
  6. Click the “Install” button.

Tags In The Input

You can embed tags in the input text block in the positions in which you’d like the parser to make a substitution from the context it has been given. These tags are always formed by matched curly braces and must take one of these forms…

  1. {fieldname}
  2. {context.fieldname}

The first form can be used regardless of how many contexts are setup in the parser, whilst the second form is used to specified which context to extract the fieldname from when using multiple contexts. For example, {page.name} is more specific than just {name}. If no context specifier is used in a tag then contexts will be searched for a match in the order in which they appear in the context array and the first match will be used for the substitution.

The value of fieldname can be any field accessible in any context or from the $_SERVER globals or one of the following special fields…

Special Tag Description
{datetime} The current date & time as formatted according to the dateFormat value in your site’s config.php file.

Special tags override other context fields with the same name so if you want to include the datetime from one of your context objects you need to specify the context in the tag (eg. “{login.datetime}”).

Transformation Of Tag Values

It is possible to have the parser apply a number of transformations to the value used to replace a given tag. You can specify a transformation to perform on the substituted value of a tag by appending it to the end of the tag like this {name>upper} or {page.name>title}.

You can chain transformations so: {page.title>lower>url} which will lowercase the title field value and then URL encode it.

Transformation Description
lower Runs the value through mb_strtolower() or strtolower()
upper Runs the value through mb_strtoupper() or strtoupper()
title Runs the value through mb_convert_case( , MB_CASE_TITLE, ) or ucwords()
url URL encodes the value unless URL encoding is set globally
encode A deprecated alias for the ‘url’ transformation
base64 Base64 encodes the value
strip Runs the value through strip_tags()
email Limits substitution to a single, trimmed line. Several possible line-ending characters are taken into account when splitting the substituted value into a single line.
html Runs the value through htmlspecialchars( , ENT_QUOTES, 'utf-8' )
initial Returns the initial letter of the string
initcap Returns the initial letter of the string capitalised and postfixed with ‘.’
initials Returns the initial letters of each word of the field
initcaps Returns the initial letters of each word of the field capitalised and postfixed with ‘.’
thinspaces Thins out multiple spaces, replacing them with a single space
nospaces Strips spaces from the field.
nl2br Converts newlines to html breaks.
nl2space Converts newlines to spaces; essentially collapsing multiline text.
name Passes the value through TextformatterNameSanitiserEn, if it is installed.
(integer) n Select the nth word from the input string

You can also specify which of the above are to be applied to all the substitutions in a text by setting that transform name to true on the parser (see usage example.)


Getting a parser object:

$parser = wire()->modules->get("TextformatterTagParser"); 

Setting a single context:

$parser->set('context', $user);

If you are only setting a single context then the shorter {fieldname} tag format will be sufficient for the parser.

Setting multiple contexts:

$parser->set('context', array('user'=>$user, 'page'=>$page) );

If you are using multiple contexts, you will probably need to use the {context.fieldname} tag format in your input strings to avoid ambiguity when the parser looks for substitutions.

Parsing a string:

Parsing is done using the format() method.


NB: The string is passed to format() by reference and the value is changed by the parser.

Setting transfomrations for all substitutions:

If you are formatting something that needs all the substitutions to be transformed in a certain manner you just…

$parser->set('url', true);

…and the parser will apply the transformation as it goes. You can set as many or few as needed.

Putting it together:

You can format as many blocks as you want with a given parser & context…

$body = "Hi {firstname>title} and welcome to our service. You can login using your username {name} and password.";
$subject = "Welcome {name>1>title}"; // Show the first word of the name in title case.
$parser = wire()->modules->get("TextformatterTagParser");
    ->set('context', $user)
    ->set('email', true)    // apply the email transformation to all substituted values in the subject to prevent header injections
    ->format($subject)      // make $subject specific to this $user
    ->set('email', false)   // no need to prevent headers in the body
    ->format($body)         // make $body specific to given $user
$sent = @email($user->email, $subject, $body);

You can setup new contexts on a given parser instance between format() calls.

Debug output

If you’d like to see a trail of which transformations were applied by the parser do a $parser->set('debug', true) before you call format().

Spinning Alternate Texts

You can have the tag parser select from a set of alternative strings in your input using the following, regex-or like, syntax…

"Dear {{mum|dad|friend}}, {{How are you|What have you been up to|What's your news}}?"

Spinning happens after contextual substitutions so you can include them in the spinning alternatives…

"...since we saw you. {{Is your phone number still {user.phone}?|Are you still available on {user.phone}?|I think you let
your plan lapse.}}"

Using HannaCode

HannaCode can really help define common alternative blocks that you might want to use repeatedly in your texts. For example, if you wanted to spin some adjectives about size you could setup HannaCode to run before the tag parser and use some substitutions such as…

big** => {{big|huge|massive|gigantic}}
small** => {{small|tiny|microscopic}}

…and then say things like…

"It was a big** event with a small** budget."

…and get results such as…

It was a huge event with a tiny budget.
It was a massive event with a microscopic budget.

Controlling Randomness.

The tag parser allows you to control the degree of randomness used in selecting alternatives used in the spinning process. By default each choice is totally random — every time you visit the page using the tag parser on a field you should see a different spin on the message. However, you can fix the result by setting the spinkey to any integer you like. Once you do this, you will always get the same generated text. Alternatively, you can set the spinkey to the value returned from the $_SERVER[HTTP_REFERER] variable so that visitors from sites linking to your site get one spin and visitors coming in from elsewhere get a different spin. Please note that any querystring or fragment parts of the URL will influence the spinning of text too unless you pass the referrer URL through the parser’s UrlToKey() method first.

Helper Module

There is a small test module available that allows you to experiment with this module from within a ProcessWire installation.