PHPTAL is a templating engine for PHP5 that implements brilliant Zope Page Templates syntax:

<div class="item" tal:repeat="item itemsArray">
    <span tal:condition="item/hasDate" tal:replace="item/getDate"/>
    <a href="${item/getUrl}" tal:content="item/getTitle"/>
  <p tal:content="value/getContent"/>

PHPTAL is fast thanks to compiled templates and fine-grained caching. Makes it easy to generate well-formed XML/XHTML (protected against XSS attacks). PHPTAL's code is mature and improving. Released free under LGPL.

See the introduction.


PHPTAL 1.3.0

  • Added support for closures
  • Added support for namespaced classes in TALES modifiers
  • Added default json and urlencode modifiers
  • Added support for Composer: composer require phptal/phptal
  • Improved registering and unregistering of custom TALES modifiers
  • Updated list of HTML5 elements/attributes
  • Improved HTML-compressing prefilter
  • Improved error messages when keys are missing in arrays
  • Fixed edge cases in checks for truthy values
  • Fixed handling of non-UTF-8 encodings in PHP 5.4+
  • Fixed throwing in chained expressions and a bunch of other bugfixes

Download tarball. Upgrading instructions

Status update


Work in progress:

  • Support for PHP5 native DOM for prefilters (so you could easily mix XSLT and XPath with PHPTAL).
  • Refactoring of parser and DOM builder, allowing other parsers in the future (e.g. PHP's native one or your own fantasy syntax if you want)
  • Support for PHP5.3 namespaces and PEAR2. PEAR's official naming scheme requires compatibility break (or at least huge compatibility headache), so I've decided to wait until PEAR2 is ready.

In the meantime, last stable version is still great. If you prefer cutting edge, you can checkout latest not-as-stable SVN version.

On a different note, Per Bernhardt shared his story how he tortured designers before switching to PHPTAL ;)

Source migrated to Git, moved to GitHub


You can now fork PHPTAL. The existing SVN repository will be updated with releases.



Namesco released ZTal — a “glue” that deeply integrates PHPTAL with Zend Framework. This is a very elegant code, released under the Apache License. If you're using Zend Framework, you should definitely check it out.

PHPTAL 1.2.2


Changes since beta are tiny on purpose:

  • Improved HTML compressor.
  • Corrected types of Exception constructor arguments.

Download tarball. Upgrading instructions

Status update


Work in progress:

  • Support for PHP5 native DOM for prefilters (so you could easily mix XSLT and XPath with PHPTAL).
  • Refactoring of parser and DOM builder, allowing other parsers in the future (e.g. PHP's native one or your own fantasy syntax if you want)
  • Support for PHP5.3 namespaces and PEAR2. PEAR's official naming scheme requires compatibility break (or at least huge compatibility headache), so I've decided to wait until PEAR2 is ready.

In the meantime, last stable version is still great. If you prefer cutting edge, you can checkout latest not-as-stable SVN version.

On a different note, Per Bernhardt shared his story how he tortured designers before switching to PHPTAL ;)

Beta of PHPTAL 1.2.2

  • Added HTML compressor which very precisely removes all unnecessary whitespace. To activate it, execute: $phptal->addPreFilter(new PHPTAL_PreFilter_Compress());.
  • Added autoloader and removed most require_once statements.
  • Added custom exception handler which handles fatal PHPTAL errors, if there is no try/catch or other handler set. PHPTAL's handler ensures appropriate HTTP status is set and information is not leaked when display_errors is off.
  • Added support for chained expressions in i18n:translate (patch by Daniel Trebbien)
  • Improved reporting of template file/line in exceptions. phptal:debug is not required any more.
  • Fixed escaping of double quotes in single-quoted attributes. The bug did not affect dynamic data.
  • Fixed bug in 'inheritance' of METAL slots (reported by Ekke Vasli)

PHPTAL 1.2.1 released

  • New addPreFilter() method and PHPTAL_PreFilter base class for filters.

    • You can add multiple prefilters.
    • Prefilters are now able to filter PHPTAL's DOM nodes in addition to just source code. This makes it much easier to implement very reliable and precise filters.
    • PHPTAL->stripComments() has been implemented as a prefilter. It's smarter now – won't remove contents of comments in <script>.
    • Added normalize space prefilter. It replaces all runs of whitespace (including newlines) with single spaces and trims attributes. It skips <pre> and supports xml:space="preserve".

    Old setPreFilter() still works, but hasn't gained any new features.

  • Added methods needed to edit DOM nodes.
  • echoExecute() method for outputting result without buffering.
  • metal:define-slot uses lazy callbacks to avoid buffering.
  • Added workaround for <?xml-stylesheet?> used with PHP short tags (<?) enabled.
  • Fixed reading of properties with same name as protected method.
  • Fixed bug that caused newlines after PHP blocks to be lost (reported by Richard Cernava).
  • Subclass of PHPTAL is preserved when calling external macros (based on patch sent by Jennifer Hulley-Miller).
  • Fixed problem of DOCTYPE being written multiple times if template is reexecuted (reported by Murat Çorlu).
  • Allowed digits in names of expression modifiers.
  • Forbidden empty namespace URI in custom attribute handlers (fixes problem reported by Jacek Karczmarczyk).
  • Fixed forging of line numbers in exceptions for compatibility with XDebug (suggested by Iván -DrSlump- Montes).

CHM version of the manual


Dj Gas has supplied CHM build of the English manual. You can now enjoy searchable reference off-line!

PHPTAL 1.2.0 released


Download tarball or ZIP.

Major changes since 1.1.x:

  • PHPTAL's code has been refactored, reorganized, bugfixed, prettified and commented.
  • HTML5 output mode is now available if you need better compatibility with non-XHTML browsers. You can generate both HTML5 and XHTML from same templates just by switching output mode.
  • XML parser improvements: stricter syntax and encoding checks, better handling of namespaces and entities.
  • <![CDATA[ blocks are added automatically where needed for compatibility with text/html and escaping is CDATA-aware.

Changes since alpha:

  • In HTML5 output mode DOCTYPE is automatically changed to <!DOCTYPE html> and namespace declarations/prefixes are omitted.
  • Better support for SimpleXML objects.


Instructions for alpha version still apply.

To help you find possible incompatibilities and syntax errors there's script. Install PHPTAL 1.2.0 first (PHPTAL.php must be in include_path, or you'll need to modify the script) and then execute:

chmod a+x
./ /path/to/your/templates/directory/

You'll get information which templates failed to parse. Please note that this tool is not 100% accurate, because it does not know about your custom modifiers and prefilters. If your templates require these, you'll need to test them yourself.

Fresh website


New look, bigger text, wider columns, better typography, syntax coloring. Please send complaints/compliments to the mailing list.

PHPTAL has a new home:


A big thanks goes to Levi Stanley from ENE Services LLC who has donated domain to the project!

Another PHPTAL 1.2.0 alpha


Fresh alpha package. Changes since last one:

  • PHPTAL_DIR is gone. PHPTAL now temporarily modifies include_path.

  • DOM-related classes and methods renamed once again.

  • Re-added few basic methods and properties for compatibility with custom attributes written for older PHPTAL versions.

  • GetTextTranslator sets locale's LC_MESSAGES only when LC_ALL doesn't work. This way you don't need full locale installed on the system to use gettext() (you should, however). setLanguage() now returns language that has been set.

  • XML namespace of phptal:* attributes has changed from to

  • &apos; entity is better supported.

  • Lots, lots of code formatting changes and doc comments for conformance with PEAR coding standards.

  • Fixed variable redefinition bug reported by Ciprian Vieru.

  • Fixed parsing of code with class constants and dynamic property names in php: expressions (bug reported by Bobby).

PHPTAL 1.2.0 alpha


This is alpha release (don't use it on live sites!). It includes long overdue fixes to XML parser and PHPTAL's internals which may require some cosmetic changes to templates. Please test it and report problems and bugs you find.


The biggest difference is in handling of entities. Entities are now unescaped before passing to expressions, i.e. ${php:strlen('&quot;')} “sees” just the quote character and returns 1. In previous versions entities were passed as-is to the expressions (and that example would return 6).

  • Newly added unescaping of entities can expose encoding bugs. Make sure your pages declare document encoding:

    • For XHTML it's best to send Content-Type:application/xhtml+xml;charset=UTF-8 or Content-Type:text/html;charset=UTF-8 HTTP headers (here's how.)
    • Don't use text/xml MIME type, use application/xml instead.
    • In HTML add appropriate <meta> tag or send Content-Type:text/html;charset=UTF-8 HTTP header.
  • If you're not using UTF-8 encoding, you must set encoding you use via $phptal->setEncoding('ISO-8859-…') (or just switch to UTF-8 already! :)

    Only some 8-bit-based encodings are supported. If your encoding is not supported, you may get away with setting ISO-8859-1 instead.

  • All constants except PHPTAL_VERSION have been removed. Remove any PHPTAL-specific define()s and use class methods for configuration (e.g. $phptal->setPhpCodeDestination('/tmp/phptal/') for custom temp directory.)

  • Don't include any PHPTAL's files before including PHPTAL.php.


  • Fixed many quirks related to handling of entities in TALES expressions.

  • Fixed escaping in CDATA sections: special characters won't be changed to entities, </ and ]]> will be escaped appropriately for output mode used.

  • Improved XML namespace support. PHPTAL now rejects invalid prefixes and uses namespace URIs internally.

  • Comments are required to be well-formed (-- is not allowed in comments.)

  • HTML5 output mode. There's a bit of controversy around HTML5, so let me be clear: this doesn't allow “tagsoup”. PHPTAL still requires templates to be well-formed XML, and the output aims to be clean and conforming HTML5 text/html syntax.

    HTML5 output mode is optional and enabled by $phptal->setOutputMode(PHPTAL::HTML5). The default output mode is compatible with XHTML/1.x and XHTML5.

  • Ability to add source resolvers. You can easily implement a fake filesystem that e.g. reads templates from the database. This is better than simply using $phptal->setSource(), because it allows external macros to work.

  • Comments starting with <!--! are stripped from output.

  • Better error messages:

    • When document ends prematurely, PHPTAL reports all elements that weren't closed.
    • Exceptions thrown when parsing templates have more accurate file and line (thanks to Wallace McGee for reporting this.)
    • Reworded errors about missing variables in TALES expressions.
  • Small bugs:

    • ${} behaves more like tal:content="".
    • tal:repeat doesn't “leak” variables to outer scope (bug reported by Richard Cernava.)
    • Template cache properly supports change of output mode.
  • Performance improvements:

    • Avoid needless reparsing. If setForceReparse(true) is set, templates are not even saved to disk. Test suite now runs 5-10× faster!
    • Removed redundant includes and require_once. Before and after.
    • Some constants are escaped at compile time.
  • Internal changes:

    • Separated parser from document builder (this will enable custom parsers in the future.)
    • Removed redundant DOM classes.
    • Renamed many DOM classes and methods to use W3C's terminology and be more consistent across PHPTAL's codebase.
    • Much cleaner code for handling of DOM attributes.

Japanese Translation of the Manual


Tetsuya Mito has kindly provided Japanese translation of the PHPTAL manual.

PHPTAL 1.1.16 Released



  • Now templates are reparsed when prefilters are added/removed (when developing a prefilter, you may still need PHPTAL::setForceReparse() to temporarily disable caching.)
  • No need to include Filter.php before using filters.
  • Calls to non-existent macros fail gracefully with exception, rather than PHP Fatal Error.
  • Fixed bug which caused dynamic macro calls from inside macros that were called from another file, to fail.
  • Added various subclasses of PHPTAL_Exception.

PHPTAL 1.1.15 Released


This release improves speed and reliability of PHPTAL. Most notably:

  • NULL value of attribute added via tal:attributes now omits entire attribute in most cases (no more class=""!)
  • Iteration via tal:repeat uses Iterator class exactly the same way foreach() (fixes problem reported by Stas Dovgodko)
  • repeat/…/length is read lazily,
  • allow '-' in external and dynamic macro names (bug spotted by Anton),
  • tal:omit-tag executes condition only once,
  • improvements in parsing of ${…} syntax.

PHPTAL 1.1.14 Released


This release brings sane handling of non-ASCII characters in gettext translation keys. If you use PHPTAL's i18n features and have non-ASCII characters in translation keys (e.g. your application's native language is other than English), you may need to upgrade your .po files or enable backward compatibility mode (see notes below).


  • fixed: non-ASCII characters in translation keys aren't canonicalized by default. setCanonicalize(true) method of PHPTAL_GetTextTranslator enables old behaviour.
  • added: PHPTAL_TranslationService now requires implementation of setEncoding() method. See manual.
  • added: support for structure keyword in i18n:translate, which disables escaping of XML entities, allowing use of XHTML in translation strings.
  • added: objects that implement __call can now throw BadMethodCallException when they don't handle called method, allowing PHPTAL to handle this gracefully.
  • fixed: partially removed support for old tal:define “feature” that caused empty elements to be omitted.
  • fixed: bug in cache purging code caused up-to-date templates to be needlessly reparsed.
  • Improved speed of macro calls across templates.

Upgrade instructions

In 1.1.13 translation key like <p i18n:translate="'żółw'" /> was interpreted as <p i18n:translate="'<C197><C188><C195><C179><C197><C130>w'"> and you had to use msgid "<C197><C188><C195><C179><C197><C130>w" in your .po files.

PHPTAL 1.1.14 stops doing this and keys are now left unchanged. The example above would simply expect msgid "żółw" in the .po file.

If you don't want to change your .po files and want to keep old behaviour, then call setCanonicalize(true) of PHPTAL_GetTextTranslator, e.g.:

$translator = new PHPTAL_GetTextTranslator();
$translator->setCanonicalize(true); // add this line

To upgrade templates, change <Cxxx> back to bytes. This code snippet will do it:


Download .po upgrade script.

Deutsche Übersetzung des Handbuchs


Eine von betreute, deutsche Übersetzung des Handbuchs ist verfügbar.

  • Der 'Template Attribute Language' Abschnitt ist fertig.
  • Dem Teil 'php Integration' fehlen noch einige Teile.

(Axel Zöllich is working on German translation of the manual!)

PHPTAL presentation


During August London Web Standards Meetup I gave presentation about PHPTAL.

The presentation is available for download in Apple Keynote and PDF formats.

PHPTAL 1.1.13 released

  • New template cleanup routines based on patch by Sergio Chersovani and Nicola Aitoro. PHPTAL will now clean up all old template files and will recompile templates also when their timestamp changes to an older one.
  • Added support for PHP constants in TALES.
  • Improved parsing of XML with syntax errors after root node. If you start getting errors about text after root node, wrap your templates in a <tal:block> element.
  • Improved parsing of semicolons in PHP strings, tal:attributes and tal:define.
  • Fixed parsing of backslash escapes in TALES strings (bug reported by Josh Duck)
  • New configuration methods now work properly with external macros (bug reported by Philip Reichenberger)
  • Added workaround for protected __isset/__get (problem reported by Anru Chen)

PHPTAL 1.1.12 released


New RepeatController by Iván “DrSlump” Montes:

  • based on SPL iterators (to simplify the code),
  • added support for string iteration,
  • added support for letter and roman properties,
  • added support for grouping first and last properties,
  • most properties are computed as needed.

PHPTAL is now easier to use as part of a framework or a plug-in:

  • Required files are included from directory pointed by PHPTAL_DIR constant (it's defined automatically). This makes it easier to use multiple copies of PHPTAL, and eliminates need for include_path.
  • Configuration can be changed without using constants (patch by Werner):
    $t = PHPTAL::create('index.xhtml')
      ->set('title', 'My Title')
      ->set('heading', 'My Heading');

These changes are backwards-compatible: PEAR installations are unaffected, configuration constants are still supported.

PHPTAL 1.1.11 released


Handy feature, less bugs.

  • nothing or NULL as last alternative in tal:attributes will cause attribute to be omitted entirely,
  • support for systems on which sys_get_temp_dir() does not include trailing slash,
  • fixed warning when clearing cache.

PHPTAL 1.1.10 released


Hello! My name is Kornel Lesiński and I'm the new maintaner of PHPTAL.

The latest release adds more robust error handling and integrates PHPTAL a bit better with PHP SPL:

  • added support for Countable and ArrayAccess SPL interfaces,
  • added support for superglobals in php: TALES expressions,
  • changed default temp directory to use sys_get_temp_dir() . If this causes trouble, you can override it using define('PHPTAL_PHP_CODE_DESTINATION','/tmp/');
  • added additional safety-checks to code generation and macro execution to prevent invalid templates from triggering PHP errors,
  • fixed small bugs in XML parser,
  • fixed few error messages to be more precise and report proper file/line,
  • changed all exceptions thrown by PHPTAL to inherit PHPTAL_Exception.
pear upgrade

PHPTAL 1.1.9 released


Applied patch from Kornel Lesinski

  • Added phptal:cache that caches HTML of any given tag,
  • Added phptal_tale() which returns chained TAL expressions as a single PHP expression. It's equivalent to phptal_tales(), but can be used in more contexts (i.e. ${foo | bar}),
  • metal:fill-block can fill blocks in parent contexts,
  • slightly improved runtime error messages.

Other svn pending fixes:

  • fixed "not" bug with complex php: expressions,
  • fixed tales string backslash escaping,
  • fixed only escape < and > in PCDATA,
  • fixed php:$foo expression which is evaluated to php:${foo} equals $ctx->{$ctx->foo}.

As announced on the mailing like I don't have the time to maintain PHPTAL anymore, Kornel Lesinski kindly proposed himself to take the head of the project and we will plan the hand over during the following weeks. It was a pleasure to give this library to the community!

Thanks to all PHPTAL users, Laurent Bedubourg

pear upgrade

PHPTAL 1.1.8 released


Fix and patch release

  • applied tal:repeat patch from Moritz Bechler
  • applied tales registry patch from Moritz Bechler
  • applied memory patch from 'smoking_birds_on_moon'
  • fixed ${structure foo} and ${string:hello world}
  • fixed setTemplate() reset existing prepared template (but not the context)
  • added true: modifier support
  • added structure support to tal:attributes
pear upgrade

PHPTAL 1.1.5 released


The 1.1.4 testing is stable and was improved :

  • added: PHPTAL_CommentFilter as a simple and useful demonstration filter
  • added: PHPTAL_PHP_CODE_EXTENSION constant based on William Bailey proposal
  • added: MyClass.myStatic: custom expression modifiers (patch from William Bailey)
  • fixed: ;; bug in string: expressions (patch from William Bailey)
  • some manual documentation concerning local and global keywords

Important: tal:define now fully support global and local take a quick look at the manual for tal:define usage...

pear upgrade

English manual corrections


Many thanks to Dan Sheppard.

PHPTAL 1.1.4 (testing) released


The 1.1 branch has finally been released, here are some changes :

  • added: global local keywords to tal:define
  • fixed: many little errors in the i18n extension
  • fixed: last path in string: not interpolated
  • modif: XHTML empty attributes are now echoed with a value (i.e.: checked="checked")
  • fixed: tal:define and content buffering fixes (patch from William Bailey)
  • fixed: pre filter usage on external macro execution
  • misc: many code refactorings which will lead to a radical library simplification in the future.
pear upgrade

PHPTAL 1.0.10 latest link fixed


The latest phptal download link was broken and linked to 1.0.9 release, this is now fixed.

pear upgrade

PHPTAL 1.0.10


(bug fix release before 1.1 branch)

  • fixed: echoing an object now calls its __toString() method
  • fixed: false booleans are now echoed as 0 instead of '' (css using item/repeat/odd may require an update)
  • fixed: tal:content, tal:replace and tal:attributes chained expression now ignores null, false and ''
  • fixed: <!-- --> comments were evaluating ${foo}
  • fixed: $${foo} were evaluated inside text nodes
  • fixed: doctype and xml declaration discovery inside deep macro calls
  • fixed: filemtime() warning when using setSource() with no path
pear upgrade

PHPTAL 1.0.9

  • when use-macro and define-macro appear in the same tag, slots are shared between macros to allow macro inheritance
  • added PHPTAL::stripComments($bool) which removes xml comments during parsing
  • fixed '0' tag content unexpected behaviour (patch from William Bailey)
  • more tests, minor refactorings and code comments

The next release will include many refactorings which will allow coders to "easily" insert their own namespaces and attributes into PHPTAL.

Pupeno's article (part2) in PHP|Architect


Pupeno's (Jose Pablo Ezequiel Fernandez Silva) second article was published on the april 2005 issue of php|architect.

This article explains common PHPTALES usage and goes deep into websites internationalisation using PHPTAL and gettext.

PHPTAL 1.0.8

  • fixed bug with array/0 paths (patch from William Bailey)
  • fixed stupid lt,gt,eq,... replacement in php:'string not gt foo'

PHPTAL 1.0.7

  • added template string execution PHPTAL::setSource($src, $path=false)
  • fixed tal:attributes and zero values error
  • latest release is now reachable at

PHPTAL manual v1 released


The new PHPTAL for PHP5 manual is available. Corrections, remarks and translations are welcome (join the mailing list).

Pupeno's article in PHP|Architect


Pupeno's (Jose Pablo Ezequiel Fernandez Silva) first article about PHPTAL was published on the issue 3, volume 4 of php|architect.

This article introduces PHPTAL and explains most common TAL attributes with some good examples.

More articles should follow in next issues concerning advanced PHPTAL usage in daily applications.