Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Twig templates

A template is a file with the HTML of a page, where the places for data are marked with special tags. OpenCart uses the Twig template language. The controller prepares an array of data, the template turns it into HTML.

Where it lives

Storefront templates are in catalog/view/template/, files have the .twig extension. The path repeats the path of the controller:

catalog/
├── controller/information/hello.php
└── view/template/information/hello.twig

Creating the template

Create catalog/view/template/information/hello.twig by hand:

{# catalog/view/template/information/hello.twig #}
<h1>{{ heading_title }}</h1>
<p>{{ text_welcome }}</p>

Double curly braces print a variable. The first line is a Twig comment, it does not reach the page.

Rendering from the controller

// catalog/controller/information/hello.php
public function index(): void
{
    $this->load->language('information/hello');
 
    $data = [];
 
    $this->response->setOutput($this->load->view('information/hello', $data));
}

Open index.php?route=information/hello — the page shows the heading and the welcome text. load->view() takes the path of the template without the extension and the data array. The texts were not put into $data: all strings of the loaded language files become template variables by themselves.

Variables

Each key of $data becomes a variable:

$data['name'] = $this->request->get['name'] ?? '';
$data['products'] = [
    ['name' => 'Mug', 'price' => '$8.00'],
    ['name' => 'T-shirt', 'price' => '$15.00'],
];

Conditions and loops

{% if name %}
  <p>Hello, {{ name }}!</p>
{% else %}
  <p>{{ text_welcome }}</p>
{% endif %}
 
<ul>
  {% for product in products %}
    <li>{{ product.name }} — {{ product.price }}</li>
  {% else %}
    <li>No products.</li>
  {% endfor %}
</ul>

Tags with a percent sign contain logic. An array element is read through a dot. The else branch of for is shown when the array is empty.

SyntaxMeaning
{{ name }}Print a variable
{% if ... %}Condition
{% for item in items %}Loop
{{ name|upper }}Filter: change the value before printing
{# ... #}Comment

The controller calls the header and footer controllers and passes their HTML to the template:

$data['header'] = $this->load->controller('common/header');
$data['column_left'] = $this->load->controller('common/column_left');
$data['footer'] = $this->load->controller('common/footer');
{{ header }}
<div id="information-hello" class="container">
  <div class="row">{{ column_left }}
    <div id="content" class="col">
      <h1>{{ heading_title }}</h1>
      <p>{{ text_welcome }}</p>
    </div>
  </div>
</div>
{{ footer }}

The page now has the shop menu, the left column with modules and the footer. This skeleton is the same in all storefront templates of the core.

Common mistake

Twig in OpenCart does not escape variables: automatic escaping is turned off, because templates receive ready HTML of the header and the footer. Data that did not come through $this->request — from an import, an external API — must be escaped by hand: {{ name|escape }}.

Thanks for reading!

Donate to the site — we work hard for you.