<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Passing Curiosity: Posts tagged tags</title>
    <link href="https://passingcuriosity.com/tags/tags/tags.xml" rel="self" />
    <link href="https://passingcuriosity.com" />
    <id>https://passingcuriosity.com/tags/tags/tags.xml</id>
    <author>
        <name>Thomas Sutton</name>
        
        <email>me@thomas-sutton.id.au</email>
        
    </author>
    <updated>2008-11-19T00:00:00Z</updated>
    <entry>
    <title>Creating custom tags for SPIP - Static tags</title>
    <link href="https://passingcuriosity.com/2008/creating-custom-tags-spip-static/" />
    <id>https://passingcuriosity.com/2008/creating-custom-tags-spip-static/</id>
    <published>2008-11-19T00:00:00Z</published>
    <updated>2008-11-19T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>The SPIP template language has two constructions: loops (which determine the
objects to be “output”) and tags (which actually output particular values).
The reasonably simple syntax of tags – most look like ’‘#THE_TAG’’ – belies
their power and flexibility and the ease with which we can use them to extend
SPIP with additional features and integrate it with other PHP-based packages.</p>
<p>In this post, I’ll describe how to create your own static SPIP tags. In a
future post, I’ll cover dynamic tags, and how to package your tags (and other
code) as a plug-in. Before reading this post, you should be familiar with
<a href="http://www.spip.net/">SPIP</a> and it’s <a href="/2008/spip-template-languag/">template
language</a>, and with programming in PHP.</p>
<p>SPIP tags are used to “output” a “value”. For many tags, this value is taken
from the context in which it is called: the title of the “current” article,
for example, or the logo the “current” news item. Others output global values
like the name of the web-site, or the version of the software. Still more tags
allow users to interact with the site (e.g. <code>#LOGIN_PUBLIC</code> which outputs a
log-in form <em>and</em> processes the log-in request when the user submits it) and a
few (like ’‘#SET’’ and ’‘#GET’’) implement the features of a general purpose
programming language and producing output is only a side effect. All of these
effects are achieved using the same relatively simple syntax and mechanism.</p>
<p>Tags can be divided into two groups based on their behaviour. <em>Static</em> tags
are those that output some statically determined value – one that does not
necessarily change from one evaluation to another. The title of an article,
for example, will not <em>necessarily</em> change between one page view and another.
It <em>may</em>, but not necessarily. <em>Dynamic</em> tags are those that generate dynamic
output – values that necessarily change between invocations. The current date
and time, for example. Implementing a static tag is significantly easier than
a dynamic tag, so we’ll look at that first and leave dynamic tags to a later
post.</p>
<h2 id="static-tags">Static tags</h2>
<p>Static tags are those that output a “static” value. That is, a value that is
not expected to change over any particular time period. This means that SPIP
can evaluate a static tag once and then cache the result and reuse it in
future requests.</p>
<p>Like many aspects of SPIP, a tag (for the rest of this section, you can assume
that “tag” means “static tag”) is a function<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> with a special name – the
name of the tag appended to “balise_”. For example a tag called <code>#FOO</code> will be
implemented by a function called <code>balise_FOO</code>. Like much of SPIP, these
functions can be overridden by plug-ins, or site-specific files. When it sees
a <code>#FOO</code> tag, SPIP will first look for a function called <code>balise_FOO</code>, then
one called <code>balise_FOO_dist</code>, and then decide that the tag doesn’t exist.</p>
<p>Rather than blather on, I’ll give you a trivial example: the <code>#HELLO_WORLD</code>
tag. This tag simply outputs the string “Hello World!” (To use the code,
simply copy the function into the file <code>mes_fonctions.php</code> in the root of your
SPIP installation):</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode php"><code class="sourceCode php"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">&lt;?php</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span> balise_HELLO_WORLD(<span class="va">$p</span>) {</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="va">$p</span>-&gt;code <span class="op">=</span> <span class="st">&quot;'Hello World!'&quot;</span><span class="ot">;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="va">$p</span><span class="ot">;</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>As you can see there are a few more details than just the name, namely, this
<code>$p</code> thing. The parameter to the function implementing the tag is a reference
to the abstract syntax tree node for that tag. This contains all of the
information about the tag that SPIP has about the tag, the filters called on
it, the brackets around it, the context, etc., etc., etc. All that is missing
is the value itself, which is where our function comes into play. After SPIP
has analysed the templates and handled everything <em>it</em> can, it calls the
function responsible for each tag to fill in the gaps.</p>
<p>There a numerous fields in the <code>Champ</code> object (the class is defined in
<a href="http://trac.rezo.net/trac/spip/browser/spip/ecrire/public/interfaces.php"><code>ecrire/public/interfaces.php</code></a>
but the definition isn’t particularly edifying), but most of them are best
left alone and accessed by way of helper functions:</p>
<ul>
<li><p><code>type</code> – a string describing the type of AST node. Should be <code>"champ"</code> for
tags.</p></li>
<li><p><code>nom_champ</code> – the name of the tag without the <code>#</code>.</p></li>
<li><p><code>nom_boucle</code> – the name of the loop. Tags aren’t loops, so this will be
empty.</p></li>
<li><p><code>avant</code> – a list of preceding nodes that are conditional on this one.</p></li>
<li><p><code>apres</code> – a list of succeeding nodes that are conditional on this one.</p></li>
<li><p><code>etoile</code> – “star”. The tag was called like <code>#HELLO_WORLD*</code> and, thus,
should output raw, as opposed to HTML safe, values.</p></li>
<li><p><code>param</code> – a list of parameters and filters to the tag call. This is pretty
complex.</p></li>
<li><p><code>fonctions</code> – similar to <code>param</code> but structured differently.</p></li>
<li><p><code>id_boucle</code> – the name of the loop within which this tag occurs.</p></li>
<li><p><code>boucles</code> – an array of AST nodes for the loops (“boulces”) in the
template.</p></li>
<li><p><code>type_requete</code> – no idea.</p></li>
<li><p><code>code</code> – the PHP code which, when <code>eval()</code>d, produces the value of the tag.</p></li>
<li><p><code>interdire_scripts</code> – whether “scripts” will be interpreted. No idea.</p></li>
<li><p><code>ramasser_miettes</code> – whether to “collect the crumbs”. No idea.</p></li>
<li><p><code>descr</code> – an array of values describing the AST node, the file it came
from, etc.</p></li>
<li><p><code>ligne</code> – the line number of the tag call in the template.</p></li>
</ul>
<p><strong>An example</strong> Replacing the contents of your <code>dist/sommaire.html</code> template
with this:</p>
<pre><code>[before (#HELLO_WORLD{arg1}|strtoupper) after]</code></pre>
<p>might result in the following AST being passed to <code>balise_HELLO_WORLD</code> above
(<a href="/files/2008/11/spip-ast-example.txt">download the full SPIP AST</a>):</p>
<pre><code>type =&gt; &quot;champ&quot;
nom_champ =&gt; &quot;HELLO_WORLD&quot;
avant =&gt; the node/s for &quot;before&quot;, ...
apres =&gt; the node/s for &quot;after&quot;, ...
etoile =&gt; 
param =&gt; [
        0 =&gt; &quot;arg1&quot; is in here, ...
        1 =&gt; &quot;strtoupper&quot; is in here, ...
        ]
fonctions =&gt; [
        0 =&gt; &quot;{arg1}&quot; is also in here, ...
        1 =&gt; &quot;strtoupper&quot; is also in here, ...
        ]</code></pre>
<p>Thankfully, you can ignore almost all of this and trust to the helpers. The
function <a href="http://doc.spip.org/@interprete_argument_balise" title="fonction interprete_argument_balise"><code>interprete_argument_balise</code>
(FR)</a> is particularly useful:
<code>interprete_argument_balise(1, $p)</code> returns the first argument in the AST node
<code>$p</code>.</p>
<p>Using what I’ve described so far, it’s pretty to write a <code>#HELLO</code> tag which
output’s a message “Hello <em>name</em>” when given a name, and “Hello World!”
otherwise (again, this code goes in <code>mes_fonctions.php</code>):</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode php"><code class="sourceCode php"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">&lt;?php</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span> balise_HELLO(<span class="va">$p</span>) {</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="va">$name</span> <span class="op">=</span> interprete_argument_balise(<span class="dv">1</span><span class="ot">,</span> <span class="va">$p</span>)<span class="ot">;</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> (<span class="op">!</span> <span class="va">$name</span>) {</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>        <span class="va">$name</span> <span class="op">=</span> <span class="st">&quot;World!&quot;</span><span class="ot">;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    <span class="va">$p</span>-&gt;code <span class="op">=</span> <span class="st">&quot;'Hello </span><span class="va">$name</span><span class="st">'&quot;</span><span class="ot">;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="va">$p</span><span class="ot">;</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>There are a number of other issues involved in writing static templates. It’s
good practice to make sure that your tags (and everything else, for that
matter) supports translation, especially if you’re going to be distributing it
to others. Doing so is reasonably easy using the <a href="http://doc.spip.org/@Les-chaines-de-langue" title="Les chaines de langue"><code>_T</code>
(FR)</a>
function and “lang” files. Getting data from a loop (article titles, section
IDs, etc.) is also reasonably straightforward with <a href="http://doc.spip.org/@champ_sql"><code>champ_sql</code>
(FR)</a>.</p>
<p>For more examples, you can have a look at the code for some of SPIP’s built-in
tags in the code of <a href="http://doc.spip.org/balises-php"><code>ecrire/public/balises.php</code>
(FR)</a> (I rather like
<a href="http://doc.spip.org/@balise_INTRODUCTION_dist"><code>balise_INTRODUTION_dist</code>
(FR)</a>). If you do look to the
SPIP source code for examples, you should be aware that a lot of the built-in
tags are not implemented using this mechanism, but are magically drawn from
database columns with the same name. If you extend the database this magic
will work for you too, but that is beyond the scope of this post and will have
to wait for my post/s about writing SPIP plug-ins.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>In one sense, this is not entirely true: the function just manipulates
the abstract syntax tree node for the tag which will then be processed by SPIP
to generate the tag. For more on this see <a href="http://doc.spip.org/@details-sur-l-AST" title="dÈtails sur líAST">details of the AST
(FR)</a>.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></summary>
</entry>

</feed>
