Multi target HAML (HAML for PHP, Twig, )


Multi target HAML

Build Status

MtHaml is a PHP implementation of the HAML language which can target multiple languages.

Currently supported targets are PHP and Twig, and new ones can be added easily.

Mt-Haml implements the exact same syntax as ruby-haml; the only difference is that any supported language can be used everywhere HAML expects Ruby code:


  - for user in users
      Email: #{}
      %a(href=user.url) Home page


<ul id="users">
  {% for user in users %}
    <li class="user">
      {{ }}
      Email: {{ }}
      <a href="{{ user.url }}">Home page</a>
  {% endfor %}


  - foreach($users as $user)
      = $user->getName()
      Email: #{$user->getEmail()}
      %a(href=$user->getUrl()) Home page


<ul id="users">
  <?php foreach($users as $user) { ?>
    <li class="user">
      <?php echo $user->getName(); ?>
      Email: <?php echo $user->getEmail(); ?>
      <a href="<?php echo $user->getUrl(); ?>">Home page</a>
  <?php } ?>



$haml = new MtHaml\Environment('php');
$executor = new MtHaml\Support\Php\Executor($haml, array(
    'cache' => sys_get_temp_dir().'/haml',

// Compiles and executes the HAML template, with variables given as second
// argument
$executor->display('template.haml', array(
    'var' => 'value',


$haml = new MtHaml\Environment('twig', array('enable_escaper' => false));

// Use a custom loader, whose responsibility is to convert HAML templates
// to Twig syntax, before handing them out to Twig:
$hamlLoader = new MtHaml\Support\Twig\Loader($haml, $twig->getLoader());

// Register the Twig extension before executing a HAML template
$twig->addExtension(new MtHaml\Support\Twig\Extension());

// Render templates as usual
$twig->render('template.haml', ...);

See examples and MtHaml with Twig


MtHaml escapes everything by default. Since Twig already supports auto escaping it is recommended to enable it in Twig and disable it in MtHaml:

new MtHaml\Environment('twig', array('enable_escaper' => false));

HAML/PHP is rendered like this when auto escaping is enabled:

Email #{$user->getEmail()}
%a(href=$user->getUrl()) Home page
Email <?php echo htmlspecialchars($user->getEmail(), ENT_QUOTES, 'UTF-8'); ?>
<a href="<?php echo htmlspecialchars($user->getUrl(), ENT_QUOTES, 'UTF-8'); ?>">Home page</a>


Using Twig in HAML gives more control over what can be executed, what variables and functions are exposed to the templates, etc. This also allows to use all of Twig's awesome features like template inheritance, macros, blocks, filters, functions, tests, ...

- extends "some-template.haml"

- macro printSomething()
  %p something

- block body
  %h1 Title
  = _self.printSomething()

Integration in Twig

MtHaml comes with an example Twig_Loader that will automatically convert HAML into Twig at loading time (Twig will then compile the resulting Twig script and cache it). Templates with a .haml extension, or whose source starts with {% haml %} will be converted, and the others will be left untouched.

The loader acts as a proxy and takes an other loader as parameter:


$haml = new MtHaml\Environment(...);

$twig_loader = new Twig_Loader_Filesystem(...);
$twig_loader = new MtHaml\Support\Twig\Loader($haml, $twig_loader);

Runtime support

Compiled MtHaml/Twig templates need support from MtHaml at runtime in some cases. Because of this, a Twig extension must be loaded before executing the templates.

// Register the MtHaml extension before executing the template:
$twig->addExtension(new MtHaml\Support\Twig\Extension());


The syntax is the same as HAML/Ruby's syntax, except that PHP or Twig have to be used where Ruby is expected.

See the tutorial and the reference


MtHaml converts HAML to PHP or Twig code. The resulting code can be cached and executed any number of times, and doesn't depend on HAML at runtime.

MtHaml has no runtime overhead.


Helpers in HAML/Ruby are just ruby functions exposed to templates. Any function can be made available to HAML templates by the target language (the function only have to be available at runtime).

In HAML/Twig you can use all of Twig's functions, filters, and tags. In HAML/PHP, you can use all PHP functions.


Filters take plain text input (with support for #{...} interpolations) and transform it, or wrap it.

Example with the javascript filter:

%p something
<script type="text/javascript">
  some.javascript.code("{{ var|escape('js') }}");

The following filters are available:

  • css: wraps with style tags
  • cdata: wraps with CDATA markup
  • coffee*: compiles coffeescript to javascript
  • escaped: html escapes
  • javascript: wraps with script tags
  • less*: compiles as Lesscss
  • markdown*: converts markdown to html
  • php: executes the input as php code
  • plain: does not parse the filtered text
  • preseve: preserves preformatted text
  • scss*: converts scss to css
  • twig: executes the input as twig code

Filter marked with * have runtime dependencies and are not enabled by default. Such filters need to be provided to MtHaml\Environment explicitly.

Example with the Coffee filter:


$coffeeFilter = new MtHaml\Filter\CoffeeScript(new CoffeeScript\Compiler);

$env = new MtHaml\Environment('twig', array(
    'enable_escaper' => false,
), array(
    'coffee' => $coffeeFilter,


Sass can be used in PHP projects without problem. It only depends on Ruby and does not need to be installed on production servers. So MtHaml will not re-implement Sass.

Frameworks and CMS support

Add yours:


MtHaml is released under the MIT license (same as HAML/Ruby).

  • Allow line breaking after commas

    Allow line breaking after commas

    Vanilla Haml allows line breaking after commas:

    %script{:type => "text/javascript",
            :src  => "javascripts/script_#{2 + 7}"}

    This allows breaking long lines (sometimes with nested objects) into multiple lines.

    It drastically improves readability and prevents horizontal scrolling.

    opened by lolmaus 12
  • Error on `switch` syntax

    Error on `switch` syntax

    A switch block like below

    - switch ($this->params['action']):
        - case 'edit'
            = $this->Html->tag('label', 'Username')
            = $this->Html->tag('p', $this->data['User']['username'])
            - break
        - case 'add'
            = $this->Form->input('username')
            = $this->Form->input('password')
            - break
    - endswitch

    is being rendered to

    <?php switch ($this->params['action']): { ?>
    <?php case 'edit' { ?>
      <?php echo $this->Html->tag('label', 'Username'); ?>
      <?php echo $this->Html->tag('p', $this->data['User']['username']); ?>
      <?php break; ?>
    <?php } ?>
    <?php case 'add' { ?>
      <?php echo $this->Form->input('username'); ?>
      <?php echo $this->Form->input('password'); ?>
      <?php break; ?>
    <?php } ?>
    <?php } ?>
    <?php endswitch; ?>

    which is produce a fatal error.

    If switch syntax is not supported yet, I would like to patch a fix for that. Please give me some clue on where should I start.

    opened by williamn 10
  • Laravel service provider

    Laravel service provider

    Hello folks,

    for easy integration with the Laravel framework's view system, we'd need two classes: a compiler adapter for Laravel's compiler interface, and a "service provider" to set up the necessary instances (compiler and an instance of MtHaml\Environment).

    That would allow for people adding this to their Laravel 4 projects just by adding one line to their composer.json and one line to their config file.

    I've got this working locally - if you're interested, I can submit a pull request.

    Great package! =)

    opened by franzliedke 8
  • Modular Filters implementation proposal

    Modular Filters implementation proposal

    A proposition to add user filters, see #19

    As a proposition, i haven't wrote test right now...

    Anatomy of a filter class

    Filters should at least implements the MtHaml\Filter\FilterInterface. The best way is to extends your filter from MtHaml\Filter\FilterAbstract.

    class PhpFilter extends  MtHaml\Filter\FilterAbstract {
        protected $name = 'php';
        // The renderer is the current renderer instance
        // $options are the environment options
        public function enter($renderer, $options)
         * The parser call this method on each new line.
         * Depending on what you returns:
         * - NodeAbstract Object: the parser will treat "as it is"
         * - String: the Parser will compare the current buffer line and
         *  the string value, then replace the buffer line if String is different
         * - Void: The default parser behavior.
        public function line($buffer, $options)
            // The line will be treated as "raw" text.
            return new Text($buffer->getPosition(), $buffer->getLine());
        // Close the filter
        public function leave($renderer, $options)
            $renderer->write(' ?>'.PHP_EOL)->undent();
    // Add the filter, The filter will be available under :css
    $env = new Environment('php');
    $env->addFilter(new PhpFilter);

    Adding Filters

    1. Through environment configuration:
    $filters = array('textile' => 'Path\To\Class', 'saas' => new Saas);
    $env = new Environment('php', array(), filters);
    1. Through addFilter() method:
    // Add filter by class name: the class will be instanciated if filter is used
    $env->addFilter('saas', 'Project\\Saas');
    // Add filter by instance:
    $env->addFilter(new Saas);
    // you can override the instance filter name like this:
    $env->addFilter('custom', new Saas);
    opened by ronan-gloo 8
  • The function

    The function "mthaml_attributes" does not exist

    I think I got it - I understand how it works now ! It's a nice job, but I'm still not completely sure I understand ...

    I get this exception : External exception (app/themes/yuuki/views/News/index.html.taml) : The function "mthaml_attributes" does not exist in "layouts/layout.html" at line 21

    This is my layouts/layout.html file :

    Thanks for your fast answer ;)

    opened by vendethiel 7
  • Providing attributes as a variable results in dropping predefined classnames: `.foo{$atts}` removes the `foo` class

    Providing attributes as a variable results in dropping predefined classnames: `.foo{$atts}` removes the `foo` class

    Example of correct behavior


    - $class = 'bar'
    .foo{'class' => $class} Baz


    <div class="foo bar">Baz</div>

    Example of buggy behavior


    - $attrs = array('class' = 'bar')
    .foo{$attrs} Baz

    Expected output:

    <div class="foo bar">Baz</div>

    This is how vanilla Haml works:

    Actual output:

    <div class="bar">Baz</div>
    opened by lolmaus 6
  • Attributes are always escaped

    Attributes are always escaped

    Even when disabling escaper and setting escape_attrs to false, dynamic attributes are always escaped in resultant php/html file. Here is my environment options:

    array('enable_escaper' => false, 'escape_attrs' => false)

    Haml: %div(class="#{body_class()}") %p test

    Output: <div <?php echo MtHaml\Runtime::renderAttributes(array(array('class', (body_class()))), 'html5', 'UTF-8'); ?>> <p>test</p> </div>

    I would expect it to work just as disabling escaper worked, where the echo is left in directly. So the output would be closer to <div class="<?php echo body_class(); ?>">

    opened by withjam 6
  • Add scalar, object ref name override and auto id incrementation support

    Add scalar, object ref name override and auto id incrementation support

    Some changes in Object Reference implementation:

    1. Scalars are supported, in order to follow original Ruby implementation:
    $str = 'hello';
    $int = 12;
    %div[$str] // generates <div class="string" id="string_hello">
    %div[$int] // generates <div class="integer" id="integer_12">
    1. Object ids are auto-incremented if there is no id methods. The aim is to prevent html ids collisions. Incrementation is based on class name:
    $std = new stdClass;
    %div[$std] // generates <div class="std_class" id="std_class_1">
    %div[$std] // generates <div class="sdt_class" id="std_class_2">
    $foo = new Foo();
    %div[$std] // generates <div class="foo" id="foo_1">
    1. Object Reference id can be overwritten with hamlObjectRef() method (see #23):
    class foo {
      public function hamlObjectRef() {
        return 'customId';

    4; Uses of is_callable() instead of method_exists(), in order to be sure that method is really callable in given context.

    opened by ronan-gloo 6
  • Won't compile on Linux

    Won't compile on Linux

    Hi! Yesterday I'm trying to complie very simple template:

        %title test

    On Windows it's compiles, but on Ubuntu (XAMPP for Linux 1.8.1) I've got:

    preg_match(): Compilation failed: internal error: previously-checked referenced subpattern not found at offset 358 /opt/lampp/htdocs/modules/haml/vendor/MtHaml/Parser/Buffer.php ... 74 if ($count = preg_match($pattern, $this->line, $match, PREG_OFFSET_CAPTURE)) { ...

    opened by kahurangitama 5
  • Introduce safe_functions in PHP environments

    Introduce safe_functions in PHP environments

    Currently with PHP environments, it's really difficult to use helpers that already return escaped HTML, for example:

          echo link_to("a", "b");

    This PR adds an environment option safe_functions which, for PHP environments, defines a list of functions which will not automatically be htmlspecialcharsd. By default this list is empty. This makes HAML templates much shorter and much more familiar to Ruby developers:

    new MtHaml\Environment('php', array('safe_functions' => array('link_to')));
      %li =link_to("a", "b")
    opened by soundasleep 4
  • Twig: Missing endblock in empty block

    Twig: Missing endblock in empty block

    - block content

    renders to

    {% block content %}

    instead of

    {% block content %}
    {% endblock %}

    This works however:

    - block content

    renders to

    {% block content %}
    {% endblock %}


    - block content
    - endblock
    opened by muja 4
  • Update links in README

    Update links in README

    • update haml url, and there was no redirect from old site ( ->
    • twig url has moved, but there is a redirect still ( ->
    • update all links to use https
    opened by srpatel 1
  • Compiler adding line numbers to twig output

    Compiler adding line numbers to twig output

    If I have a HAML file that looks like this:

    - block body
          %title = fn('wp_title')
          - if not fn('is_page','cv')

    MtHaml will compile it to this:

    {% block body %}
      <!DOCTYPE html>
          <title>{{ fn('wp_title') }}</title>
    {% line 7 %}      {% if not fn('is_page','cv') %}
          {% endif %}
    {% endblock %}

    MtHaml is adding these line numbers in places, like {% line 7 %}.

    opened by morgannunan 0
  • Nested hash-style error

    Nested hash-style error

    When using HAML and Twig together , HAML like the following fails :

    - set styles = loadStyles(["bootstrap" , "main" , "other_css" , "fontawesome"])
    !!! 5
        %meta(name="description" content="Free Web tutorials")
        %meta(name="keywords" content="HTML,CSS,XML,JavaScript")
        %meta(name="author" content="My name")
        %meta(name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no")
          Page Title
        - for style in styles
          = style
        -# Navbar section start

                %img(src="#{getImageUrl('logo.png')}" alt="#{getBlogInfo('name')}")
              %button.navbar-toggler(type="button" ){:data => {:toggle => "collapse" , :target => "#navbarSupportedContent"} ,
                                                     :aria => {:controls => "navbarSupportedContent" , :expanded => "false" , :lable => "Toggle navigation"}}

    The resulting exception is : Fatal error: Uncaught Twig\Error\SyntaxError: A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "punctuation" of value ":" in "main.haml" at line 21. in path\vendor\twig\twig\src\ExpressionParser.php on line 386

    opened by morteza-jamali 0
  • XSS in Twig templates

    XSS in Twig templates

    When using HAML and Twig to render our templates, we have run into an issue that allows XSS.

    - set name = '"><script>alert(1);</script>'

    The compiled template is:

    {% set name = '"><script>alert(1);</script>' %}
    <input {{ mthaml_attributes([['value', name]], 'html5', 'UTF-8', false)|raw }}>

    We are using the Symfony bundle, which disables escaping by default.

    Is there anything we need to do to prevent this?

    opened by chadtomkiss-tbp 1
  • nesting within interpolated string is illegal in site

    nesting within interpolated string is illegal in site

    I'm using Laravel 5.7 clean installation, and while trying to add this package with composer, add it to the app.php as Service Provider. The template is giving: "a nesting within interpolated string is illegal in site". Any ideas how to solve this? It seems php 7.1 related.

    opened by dcnl1980 2
  • Using class constant fails

    Using class constant fails

    HAML like the following fails:

    %a(href="#{Namespace\ClassName\::CLASS_CONSTANT}") Label

    The resulting exception is MtHaml\Exception\SyntaxErrorException in vendor/mthaml/mthaml/lib/MtHaml/Parser.php on line 844 with message: Unexpected '"', expected target language expression in /var/www/content-vendor/app/templates/generic/components/topbar.haml on line x, column xx

    opened by Bonscho 1
Arnaud Le Blanc
Arnaud Le Blanc
Twig Template Engine to Phalcon PHP

Twig Template Engine to Phalcon PHP

Vinicius 4 Oct 7, 2022
Experimental ActiveRecord layer on top of Doctrine2 using the Twig templating engine

This is an experiment for building ActiveRecord functionality on top of Doctrine2 using the Twig templating engine. Whether it is called Propel2 or not is irrelevant.

Francois Zaninotto 85 Dec 5, 2022
PHP Template Attribute Language — template engine for XSS-proof well-formed XHTML and HTML5 pages

PHPTAL - Template Attribute Language for PHP Requirements If you want to use the builtin internationalisation system (I18N), the php-gettext extension

PHPTAL 175 Dec 13, 2022
Provides TemplateView and TwoStepView using PHP as the templating language, with support for partials, sections, and helpers.

Aura View This package provides an implementation of the TemplateView and TwoStepView patterns using PHP itself as the templating language. It support

Aura for PHP 83 Jan 3, 2023
A complete and fully-functional implementation of the Jade template language for PHP

Tale Jade for PHP Finally a fully-functional, complete and clean port of the Jade language to PHP — Abraham Lincoln The Tale Jade Template Engine brin

Talesoft 91 Dec 27, 2022
Prosebot is a template-based natural language generation application

Prosebot is a template-based natural language generation application. Throughout the last years, ZOS has been developing Prosebot, alongside their collaboration with FEUP, as part of the project.

Zerozero 12 Dec 15, 2022
The free-to-use template for your Imagehost-website made with PHP, HTML and CSS!

The free-to-use template for your Imagehost-website made with PHP, HTML and CSS! Some information before we start This repo is only code related, to a

Ilian 6 Jul 22, 2022
The free-to-use template for your Imagehost-website made with PHP, HTML and CSS!

The free-to-use template for your Imagehost-website made with PHP, HTML and CSS! Some information before we start This repo is only code related, to a

Ilian 6 Jul 22, 2022
PHP template engine for native PHP templates

FOIL PHP template engine, for PHP templates. Foil brings all the flexibility and power of modern template engines to native PHP templates. Write simpl

Foil PHP 167 Dec 3, 2022
A PHP project template with PHP 8.1, Laminas Framework and Doctrine

A PHP project template with PHP 8.1, Laminas Framework and Doctrine

Henrik Thesing 3 Mar 8, 2022
A Mustache implementation in PHP.

Mustache.php A Mustache implementation in PHP. Usage A quick example: <?php $m = new Mustache_Engine(array('entity_flags' => ENT_QUOTES)); echo $m->re

Justin Hileman 3.2k Dec 24, 2022
Smarty is a template engine for PHP, facilitating the separation of presentation (HTML/CSS) from application logic.

Smarty 3 template engine Documentation For documentation see Requirements Smarty can be run with PHP 5.2 to PHP 7.4

Smarty PHP Template Engine 2.1k Jan 1, 2023
Native PHP template system

Plates Plates is a native PHP template system that's fast, easy to use and easy to extend. It's inspired by the excellent Twig template engine and str

The League of Extraordinary Packages 1.3k Jan 7, 2023
☕ Latte: the intuitive and fast template engine for those who want the most secure PHP sites.

Latte: amazing template engine for PHP Introduction Latte is a template engine for PHP which eases your work and ensures the output is protected again

Nette Foundation 898 Dec 25, 2022
View template engine of PHP extracted from Laravel

Blade 【简体中文】 This is a view templating engine which is extracted from Laravel. It's independent without relying on Laravel's Container or any others.

刘小乐 143 Dec 13, 2022
PHP 5.3 Mustache implementation

Phly\Mustache MOVED! This package has moved to phly/phly-mustache, and the package name has changed to phly/phly-mustache. I have updated packagist to

phly 123 Jan 11, 2022
TextGenerator is a PHP package that aims to generate automated texts from data.

TextGenerator TextGenerator is a PHP package that aims to generate automated texts from data. Feel free to comment and contribute. Features Text gener

Vincent Brouté 89 Dec 26, 2022
A faster, safer templating library for PHP

Brainy Brainy is a replacement for the popular Smarty templating language. It is a fork from the Smarty 3 trunk. Brainy is still very new and it's lik

Box 66 Jan 3, 2023
A ready-to-use Model View Controller template in PHP

PHP-MVC-Template A ready-to-use Model View Controller template in PHP Use this repo as a template! (Or clone it) Start to configure your MVC file Afte

Loule | Louis 20 Dec 26, 2022