Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Smarty templates

Building HTML from strings in PHP is awkward and unsafe. In the PrestaShop front office markup is written in Smarty templates — .tpl files where HTML is mixed with simple commands in curly braces. A module passes variables to a template and gets a ready string back.

Where templates live

Module templates are kept in the views/templates folder, templates for hooks in the hook subfolder. Create the file by hand:

modules/acmehello/
├── acmehello.php
├── logo.png
└── views/
    └── templates/
        └── hook/
            └── home.tpl

The first template

{* modules/acmehello/views/templates/hook/home.tpl *}
<section class="acme-hello">
    <h2>{$greeting}</h2>
</section>

The line in {* *} is a Smarty comment; it does not reach the page. {$greeting} prints a variable.

Rendering the template from a hook

// modules/acmehello/acmehello.php
public function hookDisplayHome(array $params): string
{
    $this->context->smarty->assign([
        'greeting' => 'Welcome!',
    ]);
 
    return $this->fetch('module:acmehello/views/templates/hook/home.tpl');
}

assign() passes variables to the template, fetch() returns the ready HTML. Refresh the home page: the greeting is now inside an h2 heading. There is no need to reset the module — the hook subscription has not changed.

The path starts with module: and the module name. Thanks to that a theme can replace the template with its own — see the lesson on themes.

Conditions and loops

Create a second template — for the reviews block on the product page:

{* modules/acmehello/views/templates/hook/product-reviews.tpl *}
<section class="acme-reviews">
    <h3>Reviews</h3>
 
    {if $reviews}
        <ul>
            {foreach from=$reviews item=review}
                <li>{$review.author}: {$review.rating} out of 5</li>
            {/foreach}
        </ul>
    {else}
        <p>No reviews yet.</p>
    {/if}
</section>
// modules/acmehello/acmehello.php
public function hookDisplayFooterProduct(array $params): string
{
    $this->context->smarty->assign([
        'reviews' => [
            ['author' => 'Anna', 'rating' => 5],
            ['author' => 'Boris', 'rating' => 4],
        ],
    ]);
 
    return $this->fetch('module:acmehello/views/templates/hook/product-reviews.tpl');
}

A list of two reviews appears on the page of any product. For now they are a plain array; in the database lesson a query replaces it.

Syntax

NotationWhat it does
{$name}Prints a variable
{$review.author}An array element or a property
{if $a > 1}...{elseif ...}...{else}...{/if}A condition
{foreach from=$list item=row}...{foreachelse}...{/foreach}A loop; foreachelse runs when the list is empty
{$text|truncate:100}A modifier: cut to 100 characters
{$price|string_format:'%.2f'}A modifier: number format
{include file='module:acmehello/views/templates/hook/stars.tpl'}Insert another template

Ready variables

In the front office every template already has engine variables: $customer, $cart, $currency, $language, $shop, $urls.

{if $customer.is_logged}
    <p>Hello, {$customer.firstname}!</p>
{else}
    <a href="{$urls.pages.authentication}">Sign in</a>
{/if}

A logged-in customer sees their name, a guest sees a link to the sign-in page.

Escaping

In the front office Smarty is configured so that every variable is escaped on output: the < and > characters turn into safe codes, and a review text cannot become a script. To print a variable as HTML, add nofilter:

<div class="acme-text">{$html nofilter}</div>

Only HTML prepared by you or by the core is printed this way. Back office templates have no automatic escaping — there you write {$name|escape:'html':'UTF-8'}. In other people's modules this modifier is also seen in the front office: it is harmless there.

Common mistake

A review text shows up with visible tags, and to "fix" it nofilter is added to the variable. Now a review containing a script runs for every visitor — an XSS vulnerability. nofilter is acceptable only for content that was not entered by a user or that has been sanitised.

Thanks for reading!

Donate to the site — we work hard for you.