X-Cart 5.3 will use Twig templates instead of the dated Flexy templates. Twig is a modern, secure and extremely flexible templating engine. To read more about using the Twig, visit the official documentation.

To make the transition smooth for our developer community, we provide a tooling to automate this process. In order to convert your custom .tpl files to .twig install the flexy-to-twig npm package and run flexy-to-twig template.tpl > template.twig. More detailed instructions are provided at the flexy-to-twig npm package page.

Alternatively, you can use our online converter if you have just a couple of templates or just want to play around with it.

Read more about the key differences between the Flexy and Twig template engines in the relevant section.

Online converter

Paste your Flexy code below

<p>{t(#Product#)}</p> <widget class="XLite\View\Widget" param1="value1" param2="value2" /> <widget template="other.tpl" /> <list name="product.details" param1="value1" param2="value2" /> <a IF="!item.isDeleted()&item.isActive()" href="{item.getURL()}">{item.name:h}</a> {foreach:getGlobalGroups(),group} <widget class="XLite\Module\XC\ProductFilter\View\Filter\AttributeList" group="{group}" /> {end:} <widget class="XLite\View\Form\Import" name="importform" /> … <widget name="importform" end />

Twig code

Flexy and Twig key differences

Apart from the obvious syntactical changes (refer to Twig documentation) there is a list of key differences that the template designer should know:

  1. Template file extension is changed from .tpl to .twig. This also affects View classes that define template file names.
  2. The View object that is rendering the template is available via a special this variable. It means that Flexy's {getProductUrl()} corresponds to Twig's {{ this.getProductUrl() }}. In Twig there is a difference between the local variables ({{ product }}) and the properties/methods of the bound View object ({{ this.product }}).
  3. Flexy's <widget class="XLite\View\Widget" param1="value1" param2="value2" /> construct maps to {{ widget('XLite\\View\\Widget', param1='value1', param2='value2') }} Twig function call. Note the doubled backslashes in class names, these are required in Twig.
  4. <widget template="other.tpl" /> converts to a simple template inclusion: {% include 'other.tpl' %}. All local variables (for example, those that were introduces by a {% for %} loop) will be available in the included template as a local {{ variable }}. Note that this is different from accessing the View object property: {{ this.variable }}.
  5. Flexy's <list name="product.details" param1="value1" param2="value2" /> converts to {{ widget_list('product.details', param1='value1', param2='value2') }} Twig function call.
  6. <widget class="XLite\View\Form\Import" name="importform" /> … <widget name="importform" end /> in Twig is expressed as {% form 'XLite\\View\\Form\\Import' %} … {% endform %} . The advantage is that Twig checks at template compile time that opening and closing tags are correctly balanced.
  7. Twig function {{ t('Product name') }} translates strings just as Flexy's {t(#Product name#)}.
  8. Twig function {{ url(...) }} provides a shortcut to AView::buildURL.

* If some of the widget parameters contain dashes (or other non-alphanumeric and non-underscore characters), Twig will not compile widget function call with such arguments and will throw an error: {{ widget('XLite\\View\\Widget', weird-param-name='value1', other-param='value2') }}. In order to work around this syntax limitation, you can use an alternate widget call syntax: {{ widget('XLite\\View\\Widget', {'weird-param-name': 'value1', 'other-param': 'value2'}) }}. However we strongly advise you to use only camel-cased parameter names as this is the recommended naming convention: {{ widget('XLite\\View\\Widget', weirdParamName='value1', otherParam='value2') }}
The above also applies to widget_list function parameters.


Feel free to ask any questions at our community forum.