Textpattern gets QR codes

n: smd_qr_code | v: 0.31 | f: /

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

Plugin list buttonPlugin download buttonCompressed plugin download button


Create Quick Response 2-D barcodes on the fly containing a variety of data: text, URL links, contact details, geographical location data, wifi hotspot requests, or your own custom formats. Choose to embed the barcode directly on your page or offer it as a download.

Author / credits

Written by Stef Dawson. Credits also go to the awesome Google Charts API. Many thanks to all involved.

Installation / uninstallation

Requires TXP 4.4.0+, PHP 5 (with CURL) and Internet access

Download the plugin from either textpattern.org, or the software page, paste the code into the TXP Admin -> Plugins pane, install and enable the plugin. To uninstall, delete from the Admin -> Plugins page.

Visit the forum thread for more info or to report on the success or otherwise of the plugin.

Usage: <txp:smd_qr_code />

The plugin adds one tag, which you can use to embed a QR code on your page. It has a variety of attributes.

Data attributes

  • type : the type of QR code to generate. Define your own, or use one of the built-in formats:
    • text : the default
    • link : a hyperlink. The http[s]:// prefix is optional and will be added if omitted
    • bookmark
    • sms : send a text message
    • phone
    • email
    • contact : a MECARD
    • vcard : a compact version of the full vcard spec
    • geo : geographical location (decimal latitude, longitude and height above the earth’s surface)
    • wifi : wifi hotspot login credentials (WEP or WPA protocols supported)
  • data : the information to put in the QR code. The data is dependent on the type — see the data table for details on the quantity and order of information you put in this attribute for the built-in types. Delimit each piece of data with a pipe character (though this can be changed with the delim attribute, if required). For example, type="bookmark" data="20,000 Leagues under the Sea|www.jules-verne.co.uk/". The limit of the data attribute is about 2KB
  • delim : the delimiter to use between data items. Default: | (pipe)
  • escape : Escape HTML entities such as <, > and &. Use escape="html" to switch this on. Default: unset

Output / display attributes

  • format : whether you wish to view the barcode inline (inside an <img> tag), force it to download, or output the raw link so you can craft your own use for it. Default: view
  • width : width of the code, in pixels. Defaut: 200
  • height : height of the code, in pixels. Default: 200
  • quality : the amount of error correction that the barcode can tolerate:
    • L — Low: 7% (default)
    • M — Medium: 15%
    • Q — Quartile: 25%
    • H — High: 30%
  • margin : the margin (in QR code “rows”) around the image. Default: 4. Note that, depending on the quality and size settings, some adjacent values don’t appear to ‘do’ anything. For example, a 200×200 ‘L’ quality image looks the same whether you pick a margin of 0, 1 or 2. The margin steps up a size for 3, 4 and 5, then up again for 6-10, and so on. This is an idiosyncracy of Google’s Charts API (or the QR code spec?), not a fault with the plugin
  • bgcol : background colour as an RGB hex code (without the #). Default: unset
  • alpha : alpha transparency as a hex value from 00 (transparent) to FF (solid). Default: unset
  • wraptag : the (X)HTML tag — specified without angle brackets — to wrap around the output. Default: unset
  • class : the CSS classname to apply to the wraptag (if present) or the <img> tag if you have chosen format="view". Default: unset
  • html_id : the HTML id to apply to the wraptag (if present) or the <img> tag if you have chosen format="view". Default: unset
  • title : Set the <img> tag’s title attribute (often used as a tooltip). Only of use when format="view". Default: unset

Validation attributes

  • validate : whether to validate all fields (1, the default), no fields (0) or the given list of data fields. The list is delimited by validelim (default: comma). Consult the data table for details on the names of the fields you can use. After each field you may also add a delim character and then a regular expression to validate this field against, which will override the built-in regex. See example 5.
    If you specify one or two fields to validate — perhaps you just want to adjust a single regex to taste — you’ll find that the remaining fields are “switched off” and not validated. To save you having to list them all, you can use a shortcut: just specify 1 as one of your list items and the remaining fields will be included in the validation with their original regexes.
    You may also copy regexes if you don’t wish to define them again. Specify the field as usual and then the special code SMD_REGEX_name_of_field_to_copy.
  • validelim : the delimiter to use between your list of items to validate. Default: , (comma)

Customisation attributes

  • layout : define your own custom layout system. Use {name-of-variable} in your definition to have the data value injected at runtime. See custom types
  • transform : define your own custom transformation to apply to particular data items. Specify type.field|name-of-function|optional|args|.... See custom transforms
  • prefix : prefix for new parameters that are created by your transformations. Default: SMD_QR_

The plugin checks that you supply all information for your chosen type and, if validate is set validates each field with a regular expression. Any deviation will result in an error being triggered.

Note that if you wish to designate an item as ‘empty’ (i.e. you don’t want to supply that parameter) you can put in the special code {smd_empty}. It is not enough to simply leave it blank because the plugin expects all fields to be filled in with something. The QR code will still contain the field, it will just have no data assigned to it. If you don’t like the built-in formats, create your own.

The code should be cached by your browser for 24 hours.

Data table for default types

Here are all the types available and the fields they require in the data attribute, from left to right. The names used here are the names you refer to the fields when listing them in your validate attribute.

type data attributes
text text
link url
bookmark title url
sms phone text
phone phone
email email subject message
contact name address phone email
vcard name email url address phone
geo lat lon height
wifi wifi_protocol ssid pass

Custom types

You may create your own custom data formats for your QR codes. As well as being able to designate a custom regular expression to validate the data value, you can also specify callbacks to transform the data value prior to its validation. This allows you to do things like tidy up links, add suffixes, sanitize data, etc.

Let’s say you don’t like the built-in vcard implementation and wanted to drop the ADR property, while adding the CELL property. You can define your own by using the following attributes (line breaks added only for clarity: they should not be in your definition) :

type="my_vcard" layout="BEGIN:VCARD\r\n

A few things to note:

  • You can name the type anything you like (even the same name as one of the existing types: your version will be used instead)
  • The vcard spec (certainly v3+) states that the N: property is mandatory. It’s merely a reformatted version of the FN: so, to save you having to add it manually, the plugin applies a custom transform called splitrevjoin (more info in the custom transforms section). Because it’s a computed field, the plugin designates it with an SMD_QR_ prefix. If you wanted to flaunt the spec and omit this value, just remove that entry from your layout
  • The {cell} replacement variable isn’t one of the built-in supported formats (i.e. one of the parameters listed in the data table). To help you out, the plugin assigns a default regular expression “one or more characters” to any new parameters, but if you wish to tighten this you can specify your own regex via the validate attribute
  • Any URLs are reformatted to begin with http:// if you omit the prefix. This is another built-in transform which you can override or suppress if you prefer

With this custom format in place you can specify a data attribute like this (again, newlines are for clarity only) :

data="Stef Dawson
     | some@mail.com
     | stefdawson.com
     | +44 (0)1234 567 890
     | +44 (0)7777 098 765"

Your QR code would be generated with the above data in it. If you wanted to use the same format across a number of codes, you could define your format in a <txp:variable /> and use TXP’s standard tag-in-attribute syntax to reuse it.

Since the new field ‘cell’ will be validated using the most permissive regex and we already have a perfectly good expression defined for ‘phone’ it’d be a shame to have to repeat ourselves. So you can do this:

validate="1, cell:SMD_REGEX_PHONE"

to copy the ‘phone’ regex over to the ‘cell’ field. The ‘1’ just makes sure that all the remaining fields are validated as normal. Without that, only the cell and any other fields you explicitly defined in the list would be validated. If you would like to see a list of the built-in regexes, use debug="1" (or 2 for more verbose output).

Custom transforms

Before validation, each piece of data may be put through a mangle to reformat it. You could use this to sanitize data, prefix it, suffix it, fetch other data, or create new entries by twisting a given data parameter. The following default transforms are built-in:

  • linkify : prefix any URL that does not begin with http://
  • splitrevjoin : takes someone’s name, splits it at space, reverses the order of the data, and then recombines it with a semicolon between each field. Thus Stef Dawson becomes Dawson;Stef

Transformations can be applied to any data parameter. You choose which by using the following syntax:


So to capitalize the vcard’s ‘name’ you could use PHP’s built-in function strtoupper() like this:


You can use a shorthand ‘wildcard’ notation if you wish to apply the same transform to the same parameter in different types (though admittedly, this has limited use). The plugin uses this with its default URL transformation by using: *.url|linkify.

If you try the above though you will receive a plugin warning Invalid or unregistered transform function. That’s a security message because only registered functions are permitted to run transformations. To register a function, use Textpattern’s register_callback() function in some PHP:

register_callback('strtoupper', 'smd_qr_code', 'add_transform');

You can of course use your own functions if you wish. The signature of your function should be:

  1. (string) Data value to transform
  2. (array) Optional values that your transform needs

The additional parameters are passed, in order, from the transform attribute. Note that you can only use functions (either your own, or PHP/TXP functions) if they either take a single string or a string plus an array as arguments. Trying to use any more complicated functions or attributes of the wrong type will likely result in warnings or errors being thrown.

If your custom function returns a single string value, that will become the parameter’s new value. If, however, you return an array of idx => values then any idx that matches the name of the parameter will replace the original. Any additional idx values become new parameters, prefixed with SMD_QR_. Let’s look at the built-in splitrevjoin() function:

public function splitrevjoin($item, $args=array()) {
   // $args: 0 = variable name, 1 = split char, 2 = join char
   if (count($args) == 3) {
      $outval = join(
           , array_reverse(
              explode( $args[1], $item )
      return array($args[0] => $outval);
   } else {
      return $item;

In this function, we have assumed that the transform’s parameters are:

  • $item : the data value
  • $args[0] : the name of the new parameter
  • $args[1] : the split character
  • $args[2] : the rejoin character

All these values are passed in like this: vcard.name|splitrevjoin|formatted_name| |; which means we’re telling the transform to process the $item and return a new parameter called formatted_name after splitting the $item at space and reconstituting the parts as a string, delimited by a semicolon.

If we’d returned name instead of formatted_name, the existing parameter would have been overwritten. Since the goal of this function is to reformat the person’s name into a form suitable for the vcard’s N: attribute, we’re leaving the original intact and making a new value.

Finally, to distinguish the input values from computed values such as this one, the plugin will automatically prefix all new parameters with SMD_QR_. Thus to use it in your layout, remember you need to specify {SMD_QR_formatted_name}. The prefix can be changed via the plugin’s prefix attribute.


Example 1: Bookmark permlinks

In your default Form put a QR code alongside your article heading so people can bookmark the article by taking a picture with their smart phone:

<h1 class="entry-title">
   <txp:permlink><txp:title /></txp:permlink>
   <txp:smd_qr_code type="bookmark"
     data='<txp:title />|<txp:permlink />'
     width="50" height="50"
     quality="Q" />

Notice that since the image size has been reduced to fit alongside the title, the quality (error detection/correction) has been increased to compensate.

Example 2: Author contact details

If you have smd_bio installed you could add the following code to the ‘published by’ segment of your articles. It will display a QR code for the contact details of the article’s author, thus visitors can scan the barcode and have the author’s MECARD added directly to their address books:

<p class="published">
   <txp:posted /> by <txp:author title="0" />
   <txp:smd_qr_code type="contact"
     data='<txp:author />
        | <txp:smd_bio_info items="address" label="" />
        | <txp:smd_bio_info items="phone" label="" />
        | <txp:smd_bio_info items="email" label="" /> />'
     bgcol="bea7d0" margin="1" />

This one has a natty, thin purple border too courtesy of the bgcol and margin attributes.

Alternatively, in VCARD format:

     items="address" label="" /></txp:variable>
<p class="published">
   <txp:posted /> by <txp:author title="0" />
   <txp:smd_qr_code type="vcard"
     data='<txp:author />
        | <txp:smd_bio_info items="email" label="" /> />'
        | <txp:smd_bio_info items="website" label="" />
        | <txp:if_variable
               value="">{smd_empty}<txp:else /><txp:variable
               name="address" /></txp:if_variable>
        | <txp:smd_bio_info items="phone" label="" />
     bgcol="bea7d0" margin="1" />

Note in this case we have checked if the address is empty and supplied the {smd_empty} parameter as a convenience. You would probably enforce this upstream at data collection point, but this serves to demonstrate that you can defensively prevent smd_qr_code validation errors by employing similar techniques on certain optional fields.

Example 3: Geographic location

Organising a flashmob on Mount Kilimanjaro? Make sure people can find you by publishing a QR code on your site:

<txp:smd_qr_code type="geo"
     data="-3.07583 | 37.35333 | 5895" />

Example 4: Raw links

<a href="<txp:smd_qr_code
     type="link" data="myfabsite.com/vouchers"
     format="raw" />">Download your voucher</a>

While this one is just a boring URL link there’s nothing to stop you generating a personal voucher code, perhaps after they have submitted their contact details via zem_contact_reborn, and tacking it onto the end of the URL.

Example 5: Overriding regexes

     type="bookmark" delim="#"
     validate="title, url#%^(file://|http://|ftp://).+$%"
     data="Bookmark me # ftp://stefdawson.com" />

A few things to note about this one:

  • The delimiter has been changed because the regular expression uses pipe symbols in its definition
  • The title is still being validated, and will use the built-in regular expression
  • The ‘url’ regex is going to be validated using the given regex including start/end delimiters. Normally we’d use a / but in this case we have chosen % as the start/end character because we’re using /s in the regex itself, which means we don’t have to escape them


31 Mar 11 | 0.10 | Initial public release
02 Apr 11 | 0.20 | Added title attribute for the <img> tag ; added vcard type (thanks gomedia) ; added validate and validelim to allow regex overrides ; fixed url regex ; improved error reporting ; permitted debug to aid in tracking down regex / validation errors
04 Apr 11 | 0.30 | Wrote more flexible, custom interface to Google Charts API ; added layout, transform and prefix attributes ; improved validate attribute
05 Apr 11 | 0.31 | Double-quotes not single quotes for proper backslashing ; fixed callback warning when no plugin callbacks defined (both thanks gomedia)

Source code

If you’d rather dig for buried treasure, you’ll need to step into the view source page.

Legacy software

If, for some inexplicable reason, you need the un-current version of a plugin, it can probably be found on the plugin archive page.

Experimental software

If you’re feeling brave, or fancy going bareback, you can test out some of my beta code. It can be found on the plugin beta page.