FAQs and tips

Questions are welcome on the PHPTAL mailing list!

How can I prevent escaping of HTML characters (&,<,")?

In most cases use structure expression modifier, e.g.:

<p tal:content="structure variable_with_raw_xhtml" />

You should use this only when you're sure that variable contains safe (filtered), well-formed XHTML.

In <script> PHPTAL will change < to &lt;, because this is required by XML. If you're sending XHTML as HTML (using IE-compatible text/html MIME type), then you need to use alternative, HTML-compatible syntax:

<script type="text/javascript">/*<![CDATA[*/
  1 < 2;
  var hello = ${structure php:json_encode("world!");}
/*]]>*/</script>

Note that <![CDATA[ also disables interpretation of TAL tags, so you have to use ${structure expresssion} syntax. It's also a good idea to use json_encode() to convert PHP strings/arrays to JavaScript strings or arrays.

Output trees recursively (e.g. nested multi-level menus)

Macros work almost like functions and can be used to generate code recursively. Just create macro that calls itself:

<ul metal:define-macro="output_list" tal:condition="list">
    <li tal:repeat="list_item list">
        ${list_item/name}

        <!-- this re-defines list variable
             by assigning the next sub-level of the list to it,
             and then calls this macro again -->
        <tal:block tal:define="list list_item/sublist"
                   metal:use-macro="output_list" />
    </li>
</ul>

<!-- macro definition above isn't automatically run,
     so kick-start the process -->
<tal:block metal:use-macro="output_list" />

The code above will work for structure like this (of course objects could work as well):

<?php
$phptal->list = array(
    array('name'=>'Top level first item', 'sublist'=>array(
        array('name'=>'Second level first item', 'sublist'=>array()),
        array('name'=>'Second level second item', 'sublist'=>array()),
    )),
    array('name'=>'Top level second item', 'sublist'=>array(
        array('name'=>'etc...', 'sublist'=>array(
            array('name'=>'etc...', 'sublist'=>array()),
        )),
    )),
);
?>
How can I force refresh ofphptal:cache? (for example when my news updates)

Manual approach is to tell PHPTAL to delete cached templates:

$phptal = new PHPTAL("templates/news.zpt");
$phptal->cleanUpCache();

A better, fully automatic approach is to put modification date in phptal:cache:

<div phptal:cache="100d per php:news.id . news.last_updated_date">

This means that a separate copy will be cached for every version of every news item. You can use cron to remove outdated copies.

Interpolation error, var "bla/bla/bla" not set

In translated strings you can't use TALES expressions. Only names defined with i18n:name.

This indirection is there to have simple, clear names in translation keys that your translators won't be confused about and won't break :)

How can I translate text generated on the fly?

If you've got code like <p tal:content="some_error_message"/> then change it to <p i18n:translate="some_error_message"/>.

Contents of i18n:translate is an expression that evaluates name of translation key at run time.

How can I translate complex formatted text?

Add structure keyword to the i18n:translate attribute:

<p i18n:translate="structure 'translation-key'">
     <strong>Formatted</strong> text
</p>

And translated text will be used literally, as XHTML code, without escaping (beware that ill-formed XHTML in translations will break your page).

msgid "translation-key"
msgstr "<strong>Formatted</strong> text"

If text contains parts that are dynamic or that you don't want to translate, you can use i18n:name to exclude them. And you can nest i18n:translate:

<p i18n:translate="structure 'translation-key'">
    <strong>Formatted</strong> 
    <a href="…" i18n:name="link">
        <tal:block i18n:translate="">link label</tal:block>
    </a>
</p>
msgid "translation-key"
msgstr "<strong>Formatted</strong> ${link}"
msgid "link label"
msgstr "link label"
How can I add two or more post/pre filters to the template?

Use addPreFilter() instead of setPreFilter(). For post-filters create one wrapper "filter":

class MyBunchOfFilters implements PHPTAL_Filter
{
    function filter($code)
    {
	    foreach($this->myfilters as $f) $code = $f->filter($code);
	    return $code;
    }
}
Avoid error when variables are undefined

If you don't always pass certain variables to your templates, use exists: expression modifier to ensure variable exists:

<div tal:condition="exists:user">Hello ${user/name}!</div>

Alternatively, you can use | operator and nothing keyword in expressions:

<p>Hello ${user/first_name | 'Anonymous'} ${user/last_name | nothing}</p>