Making your plugins 4.7-aware

19 August 2017

We all remember the plugin breakage panic provoked by some changes (mainly registration and null date defaults) in txp 4.6. Fortunately, the most popular plugins are patched now, so it’s time to make them 4.7-ready.

The good news is that a vast majority of 4.6-compatible (public-side) plugins should work in 4.7 without any problem. But, to be sure, or if you want your favorite plugin to enjoy new possibilities, please read what follows.

An important new feature of the upcoming txp 4.7 are global attributes. Roughly speaking, any plugin can register one or more global attributes that will be valid for any (core or plugin) tag and applied to its output.

Let us consider a basic example. Suppose that we need a plugin that replaces all the occurrences of from string to to string. In 4.6 we would do it this way:

// TXP 4.6 tag registration
if (class_exists('\Textpattern\Tag\Registry')) {
	Txp::get('\Textpattern\Tag\Registry')->register('abc_replace');
}

function abc_replace($atts, $thing = null)
{
	extract(lAtts(array(
		'from' => 'foo',
		'to' => 'bar'
	), $atts, false));

	return str_replace($from, $to, $thing);
}

Now, the new abc_replace tag can be used as container:

<txp:abc_replace from="wordpress" to="textpattern">
	<txp:body />
</txp:abc_replace>

In 4.7 we get new powers: implement our plugin as attribute:

// TXP 4.7 tag registration
if (class_exists('\Textpattern\Tag\Registry')) {
	Txp::get('\Textpattern\Tag\Registry')->register('abc_replace'); //container mode
	if(method_exists('\Textpattern\Tag\Registry', 'registerAttr'))    //attribute mode
		Txp::get('\Textpattern\Tag\Registry')->registerAttr('abc_replace', 'from')->registerAttr('abc_replace', 'to');
}

function abc_replace($atts, $thing = null) { ... }

And voilà, now every tag also accepts from and to attributes:

<txp:body from="wordpress" to="textpattern" />

Some of the commonly used attributes (wraptag, class, etc) have been registered by core, so plugins don’t have to implement them anymore. But if you wish, you can override the core behavior and treat them yourself. For this, it is important to call lAtts() function somewhere inside your plugin:

  • bad way: $wraptag = $atts['wraptag'];
  • good way: extract(lAtts(array('wraptag' => ''), $atts));

This will inform the core that the plugin has its own wraptag attribute, so the global one will not be applied. Fortunately, most plugins adhere to this rule, but if yours starts to wrap its output twice, you know what to do now.

To resume, a public-side plugin:

  • does not need to implement wraptag, class, html_id, atts, label, labeltag and escape attributes if it treats them in the usual way;
  • otherwise, ensure that they are passed through lAtts() filter;
  • if you register a global attribute, don’t give it a txp- prefixed name, they are reserved for core;
  • additionally, parse(EvalElse($thing, $condition)) is deprecated, replace it with parse($thing, $condition).

I leave the eventual admin-side plugins patching with Stef and Phil. Happy coding!