LogoLogo
Homepage
  • Documentations for PrestaShop 1.5
  • English documentation 1.5
    • About PrestaShop 1.5
    • New features in PrestaShop 1.5
    • Getting Started
      • What you need to get started
      • Installing PrestaShop
      • Installing PrestaShop using the command line
      • Updating & Uninstalling
      • Misc. information
    • Updating PrestaShop
      • Automatic update
      • Manual update
      • Making and restoring your own backup
      • In case of issues
    • User Guide
      • Training
      • Customizing your shop
      • Browsing the front-office
      • Connecting to the PrestaShop back-office
      • First steps with PrestaShop 1.5
      • Adding Products and Product Categories
      • A Look Inside the Catalog
      • Managing Orders
      • Managing Customers
      • Creating Price Rules and Vouchers
      • Managing Shipping
      • Understanding Local Settings
      • Managing Modules and Themes
      • Making the Native Modules Work
      • Understanding the Preferences
      • Understanding the Advanced Parameters
      • Administering the Back-Office
      • Understanding Statistics
      • Advanced Stock Management
      • Managing Multiple Shops
    • Developer Guide
      • Developer tutorials
        • Using the PrestaShop Web Service
          • Webservice one-page documentation
          • Chapter 1 - Creating Access to Back Office
          • Chapter 2 - Discovery - Testing access to the web service with the browser
          • Chapter 3 - First steps - Access the Web service and list client
          • Chapter 4 - Retrieve Data - Retrieving a Client
          • Chapter 5 - Modification - Update client
          • Chapter 6 - Creation - Remote Online Form
          • Chapter 7 - Removal - Remove customer accounts from the database
          • Chapter 8 - Advanced Use
          • Chapter 9 - Image management
          • Chapter 10 - Price management
          • Cheat-sheet - Concepts outlined in this tutorial
          • Web service reference
        • Helpers
          • HelperForm
          • HelperOptions
          • HelperList
          • Using helpers to overload a back-office template
        • New Developers Features In PrestaShop 1.5
        • Using the Context Object
        • DB class best practices
        • Public and overloadable methods
        • Overriding default behaviors
        • Using addJquery(), addJqueryPlugin() and addJqueryUI()
        • Handling special characters in links
        • Auto-updating modules
        • Front-Office Controllers
        • Controllers correspondence table
        • Specifics of multistore module development
        • Developer tips and tricks
        • PrestaShop's developer tools
        • Using the backward compatibility toolkit
      • Fundamentals
      • Coding Standards
      • Setting up your local development environment
      • Diving into PrestaShop Core development
      • Creating a PrestaShop module
      • Creating a front-office module
      • Creating a module with both front-end and back-end controllers
      • Hooks in PrestaShop 1.5
      • Translations in PrestaShop 1.5
      • How to use the Forge to contribute to PrestaShop
      • How to write a commit message
      • Contributing code to PrestaShop
    • Designer Guide
      • Theme development fundamentals
      • Integrating content in a page using hooks
      • Characteristics of a front-office theme
      • Characteristics of a back-office theme
      • Creating your own theme
      • Theme templates and Smarty
      • Using jQuery and Ajax
      • Best practices
      • Designer tutorials
        • Changes in version 1.5 which impact theme development
        • Changing a 1.4 theme to support gift products
        • Implementing layered navigation in a theme
    • System Administrator Guide
    • Merchant's Guide
      • Our advices
      • Sample price rules
    • FAQ
      • Using PrestaShop with WordPress
    • Troubleshooting
  • Documentation française 1.5
    • À propos de PrestaShop 1.5
    • Nouveautés de PrestaShop 1.5
    • Guide de démarrage
      • Ce dont vous avez besoin
      • Installer PrestaShop
      • Installer PrestaShop en ligne de commande
      • Mettre PrestaShop à jour
      • Informations diverses
    • Guide de mise à jour
      • Mise à jour automatique
      • Mise à jour manuelle
      • Faire une sauvegarde et la restaurer
      • En cas de problème
    • Guide de l'utilisateur
      • Formations
      • Personnaliser votre boutique
      • Parcourir le front-office
      • Se connecter au back-office de Prestashop
      • Premiers pas avec PrestaShop 1.5
      • Ajouter des produits et des catégories de produits
      • Un aperçu du catalogue
      • Gérer les commandes
      • Gérer les clients
      • Mettre en place des promotions
      • Gérer les transporteurs
      • Comprendre les réglages locaux
      • Gérer les modules et les thèmes
      • Configurer les modules natifs
      • Comprendre les préférences
      • Comprendre les paramètres avancés
      • Administrer le back-office
      • Comprendre les statistiques
      • Gestion avancée des stocks
      • Gérer plusieurs boutiques
    • Guide du développeur
      • Fondamentaux
      • Norme de développement
      • Mettre en place votre environnement de développement
      • Plonger dans le développement PrestaShop
      • Créer un module PrestaShop
      • Les hooks de PrestaShop 1.5
      • Les traductions dans PrestaShop 1.5
      • Comment utiliser la Forge pour contribuer à PrestaShop
      • Comment écrire un descriptif de modification
    • Guide de l'intégrateur
      • Fondamentaux de la création de thème
      • Intégrer du contenu dans une page à l'aide de hooks
      • Caractéristiques d'un thème front-office
      • Caractéristiques d'un thème back-office
      • Template de thème et Smarty
      • Utiliser jQuery et Ajax
      • Bonnes pratiques
    • Guide de l'administrateur système
    • Guide du vendeur
      • Exemples de promotions
      • Nos bons conseils
    • Questions fréquentes
    • Dépannage
  • Documentación española 1.5
    • Acerca de PrestaShop 1.5
    • Introducción
      • Lo que necesita para empezar
    • Guía del usuario
      • Formación
      • Personalización de su tienda
      • Exploración del front-office
      • Conexión al back-office de PrestaShop
      • Primeros pasos con PrestaShop 1.5
      • Añadir productos y categorías de productos
      • Una mirada interna al catálogo
      • Gestionar pedidos
      • Gestionar clientes
      • Crear reglas de precios y cupones
      • Gestionar el transporte
      • Comprender la Configuración Local
      • Gestionar módulos y temas
      • Configurar los Módulos Nativos
      • Comprender las Preferencias
      • Comprender los Parámetros avanzados
      • Administrar el Back-Office
      • Comprender las estadísticas
      • Gestión avanzada de stock
      • Gestionar varias tiendas
    • Guía del Desarrollador
      • Tutoriales para Desarrolladores
        • Uso del Web Service de Prestashop
          • Capítulo 1 - Creación de acceso al Back Office
  • Документация на русском языке 1.5
    • Информация о PrestaShop 1.5
    • Новые функции в PrestaShop 1.5
    • Приступая к работе
      • Что нужно чтобы приступить к работе
      • Установка PrestaShop
      • Установка PrestaShop при помощи командной строки
      • Обновление и удаление PrestaShop
      • Прочая информация
    • Руководство пользователя
      • Обучение
      • Настройка вашего магазина
      • Изучение публичной части сайта
      • Бэк-офис PrestaShop
      • Первые шаги в PrestaShop 1.5
      • Добавление товаров и товарных категорий
      • Внутри каталога
      • Управление заказами
      • Работа с клиентами
      • Создание правил ценообразования корзины и ваучеров
      • Управление доставкой
      • Ориентация в локальных настройках
      • Управление модулями и темами
      • Настойка встроенных модулей
      • Ориентация в настройках
      • Ориентация в расширенных параметрах
      • Администрирование Back-Office
      • Ориентация в статистике
      • Расширенное управление запасами
      • Управление мультимагазином
Powered by GitBook
On this page
  • Changes in version 1.5 which impact theme development
  • Foreword
  • getPageLink
  • B2B
  • Layered navigation
  • Product attributes
  • Changes to be applied to a 1.4 theme in order use per-combination unique product URLs
  • New cart summary
  • Social titles
  • New template
  • Dynamic template
  • General considerations theme URLs and form action

Was this helpful?

  1. English documentation 1.5
  2. Designer Guide
  3. Designer tutorials

Changes in version 1.5 which impact theme development

PreviousDesigner tutorialsNextChanging a 1.4 theme to support gift products

Last updated 4 years ago

Was this helpful?

Table of content

/*<![CDATA[*/ div.rbtoc1597308501610 {padding: 0px;} div.rbtoc1597308501610 ul {list-style: disc;margin-left: 0px;} div.rbtoc1597308501610 li {margin-left: 0px;padding-left: 0px;} /*]]>*/

Changes in version 1.5 which impact theme development

Foreword

A lot has changed between the Theme API in PrestaShop 1.4 and the one available in version 1.5. Wholes sections have been rewritten while others have been added, mostly to take into account new features from PrestaShop 1.5, such as the cart rules system et the partial delivery/multishipping one.

But in general, it is highly advisable not to adapt a 1.4 theme to PrestaShop, but rather start with the default theme and adapt your HTML and CSS files to it. This way, you will ensure that all the new features from PrestaShop 1.5 will be included in your theme out of the box.

getPageLink

The way getPageLink() works has been changed. The first parameter should no longer be the controller's file, but instead the controller name.

In 1.4:

{$link->getPageLink('order-slip.php', true)}

In 1.5:

{$link->getPageLink('order-slip', true)}

B2B

New fields are now available for the sign-up page. See authentication.tpl in the default theme.

{if $b2b_enable}
<fieldset class="account_creation">
	<h3>{l s='Your company information'}</h3>
	<p class="text">
		<label for="">{l s='Company'}</label>
		<input type="text" class="text" id="company" name="company" value="{if isset($smarty.post.company)}{$smarty.post.company}{/if}" />
	</p>
	<p class="text">
		<label for="siret">{l s='SIRET'}</label>
		<input type="text" class="text" id="siret" name="siret" value="{if isset($smarty.post.siret)}{$smarty.post.siret}{/if}" />
	</p>
	<p class="text">
		<label for="ape">{l s='APE'}</label>
		<input type="text" class="text" id="ape" name="ape" value="{if isset($smarty.post.ape)}{$smarty.post.ape}{/if}" />
	</p>
	<p class="text">
		<label for="website">{l s='Website'}</label>
		<input type="text" class="text" id="website" name="website" value="{if isset($smarty.post.website)}{$smarty.post.website}{/if}" />
	</p>
</fieldset>
{/if}

Layered navigation

Whenever possible, you should use the TPL files from the default theme, and refrain from editing them. This is true for all modules, but doubly so for the layered navigation one.

When adding layered navigation to a non-official theme, two things tend to break:

  • The H1 tag update.

  • The "available quantities" update.

You can fix these by following the following steps.

The H1 tag

In the category.tpl template file, you must add the $categoryNameComplement variable after the category name:

{$category->name|escape:'htmlall':'UTF-8'}

...becomes...

{$category->name|escape:'htmlall':'UTF-8'} {$categoryNameComplement|escape:'htmlall':'UTF-8'}

Available quantities

Still in category.tpl, you must remove the section displaying the number of products, and put it in a new template, named category-count.tpl.

For instance, with the default PrestaShop tempalte:

<h1>
  {strip}
    {$category->name|escape:'htmlall':'UTF-8'} {$categoryNameComplement|escape:'htmlall':'UTF-8'}
    <span class="category-product-count">
      {if $category->id == 1 OR $nb_products == 0}{l s='There are no products.'}
      {else}
        {if $nb_products == 1}{l s='There is'}{else}{l s='There are'}{/if}
          {$nb_products}
        {if $nb_products == 1}{l s='product.'}{else}{l s='products.'}{/if}
      {/if}
    </span>
  {/strip}
</h1>

...becomes...

<h1>
  {strip}
    {$category->name|escape:'htmlall':'UTF-8'} {$categoryNameComplement|escape:'htmlall':'UTF-8'}
    <span class="category-product-count">
      {include file="$tpl_dir./category-count.tpl"}
    </span>
  {/strip}
</h1>

The new category-count.tpl template file contains the lines that were removed from category.tpl:

{if $category->id == 1 OR $nb_products == 0}{l s='There are no products.'}
{else}
  {if $nb_products == 1}{l s='There is'}{else}{l s='There are'}{/if}
  {$nb_products}
  {if $nb_products == 1}{l s='product.'}{else}{l s='products.'}{/if}
{/if}

Product attributes

Attribute types are now generic. Therefore, the way they are displayed has been changed in product.tpl.

In 1.4:

{if isset($groups)}
	<!-- attributes -->
	<div id="attributes">
	{foreach from=$groups key=id_attribute_group item=group}
	{if $group.attributes|@count}
	<p>
		<label for="group_{$id_attribute_group|intval}">{$group.name|escape:'htmlall':'UTF-8'} :</label>
		{assign var="groupName" value="group_$id_attribute_group"}
		<select name="{$groupName}" id="group_{$id_attribute_group|intval}" onchange="javascript:findCombination();{if $colors|@count > 0}$('#wrapResetImages').show('slow');{/if};">
			{foreach from=$group.attributes key=id_attribute item=group_attribute}
				<option value="{$id_attribute|intval}"{if (isset($smarty.get.$groupName) && $smarty.get.$groupName|intval == $id_attribute) || $group.default == $id_attribute} selected="selected"{/if} title="{$group_attribute|escape:'htmlall':'UTF-8'}">{$group_attribute|escape:'htmlall':'UTF-8'}</option>
			{/foreach}
		</select>
	</p>
	{/if}
	{/foreach}
	</div>
{/if}

In 1.5:

{if isset($groups)}
	<!-- attributes -->
	<div id="attributes">
	{foreach from=$groups key=id_attribute_group item=group}
		{if $group.attributes|@count}
			<fieldset class="attribute_fieldset">
				<label class="attribute_label" for="group_{$id_attribute_group|intval}">{$group.name|escape:'htmlall':'UTF-8'} :</label>
				{assign var="groupName" value="group_$id_attribute_group"}
				<div class="attribute_list">
				{if ($group.group_type == 'select')}
					<select name="{$groupName}" id="group_{$id_attribute_group|intval}" class="attribute_select" onchange="findCombination();getProductAttribute();{if $colors|@count > 0}$('#wrapResetImages').show('slow');{/if};">
						{foreach from=$group.attributes key=id_attribute item=group_attribute}
							<option value="{$id_attribute|intval}"{if (isset($smarty.get.$groupName) && $smarty.get.$groupName|intval == $id_attribute) || $group.default == $id_attribute} selected="selected"{/if} title="{$group_attribute|escape:'htmlall':'UTF-8'}">{$group_attribute|escape:'htmlall':'UTF-8'}</option>
						{/foreach}
					</select>
				{elseif ($group.group_type == 'color')}
					<ul id="color_to_pick_list" class="clearfix">
						{assign var="default_colorpicker" value=""}
						{foreach from=$group.attributes key=id_attribute item=group_attribute}
						<li>
							<a id="color_{$id_attribute|intval}" class="color_pick{if ($group.default == $id_attribute)} selected{/if}" style="background: {$colors.$id_attribute.value};" title="{$colors.$id_attribute.name}" onclick="colorPickerClick(this);getProductAttribute();{if $colors|@count > 0}$('#wrapResetImages').show('slow');{/if}">
								{if file_exists($col_img_dir|cat:$id_attribute|cat:'.jpg')}
									<img src="{$img_col_dir}{$id_attribute}.jpg" alt="{$colors.$id_attribute.name}" width="20" height="20" /><br>
								{/if}
							</a>
						</li>
						{if ($group.default == $id_attribute)}
							{$default_colorpicker = $id_attribute}
						{/if}
						{/foreach}
					</ul>
					<input type="hidden" id="color_pick_hidden" name="{$groupName}" value="{$default_colorpicker}" />
				{elseif ($group.group_type == 'radio')}
					{foreach from=$group.attributes key=id_attribute item=group_attribute}
						<input type="radio" class="attribute_radio" name="{$groupName}" value="{$id_attribute}" {if ($group.default == $id_attribute)} checked="checked"{/if} onclick="findCombination();getProductAttribute();{if $colors|@count > 0}$('#wrapResetImages').show('slow');{/if}">
						{$group_attribute|escape:'htmlall':'UTF-8'}<br/>
					{/foreach}
				{/if}
				</div>
			</fieldset>
		{/if}
	{/foreach}
	</div>
{/if}

Changes to be applied to a 1.4 theme in order use per-combination unique product URLs

There are only a couple of changes to apply, but they take quite a bit code. Fortunately, it is mostly copy/pasting of code we provide.

In product.tpl

The product.tpl has some changes that are need in its JavaScript code.

First, you have to add a call to the getProductAttribute() method on the onClick event of any input tag targeting attributes (select, radio or color). This method will be defined in the section.

You also need to add the following code this file's JavaScript section:

{if isset($attributesCombinations)}
    // Combinations attributes informations
    var attributesCombinations = new Array();
    {foreach from=$attributesCombinations key=id item=aC}
        tabInfos = new Array();
        tabInfos['id_attribute'] = '{$aC.id_attribute|intval}';
        tabInfos['attribute'] = '{$aC.attribute}';
        tabInfos['group'] = '{$aC.group}';
        tabInfos['id_attribute_group'] = '{$aC.id_attribute_group|intval}';
        attributesCombinations.push(tabInfos);
    {/foreach}
{/if}

In js/product.js

Here you should put the new getProductAttribute() method:

function getProductAttribute(){
    // get product attribute id
    product_attribute_id = $('#idCombination').val();
    product_id = $('#product_page_product_id').val();
 
    // get every attributes values
    request = '';
    //create a temporary 'tab_attributes' array containing the choices of the customer
    var tab_attributes = new Array();
    $('div#attributes select, div#attributes input[type=hidden], div#attributes input[type=radio]:checked').each(function(){
        tab_attributes.push($(this).val());
    });
 
    // build new request
    for (i in attributesCombinations)
        for (a in tab_attributes)
            if (attributesCombinations[i]['id_attribute'] == tab_attributes[a])
                request += '&'+attributesCombinations[i]['group']+'='+attributesCombinations[i]['attribute'];
    request = request.replace(request.substring(0, 1), '#');
    url = window.location+'';
 
    // redirection
    if (url.indexOf('#') != -1)
        url = url.substring(0, url.indexOf('#'));
    window.location = url+request;
}
 
$(document).ready(function(){
    url = window.location+'';
    // if we need to load a specific combination
    if (url.indexOf('#') != -1)
    {
        // get the params to fill
        params = url.substring(url.indexOf('#') + 1, url.length);
        tabParams = params.split('&');
        tabValues = new Array();
        for (i in tabParams)
            tabValues.push(tabParams[i].split('='));
        product_id = $('#product_page_product_id').val();
        // fill html with values
        $('.color_pick').removeClass('selected');
        count = 0;
        for (z in tabValues)
            for (a in attributesCombinations)
                if (attributesCombinations[a]['group'] == tabValues[z][0]
                    && attributesCombinations[a]['attribute'] == tabValues[z][1])
                {
                    count++;
                    // add class 'selected' to the selected color
                    $('#color_'+attributesCombinations[a]['id_attribute']).addClass('selected');
                    $('input:radio[value='+attributesCombinations[a]['id_attribute']+']').attr('checked', 'checked');
                    $('input:hidden[name=group_'+attributesCombinations[a]['id_attribute_group']+']').val(attributesCombinations[a]['id_attribute']);
                    $('select[name=group_'+attributesCombinations[a]['id_attribute_group']+']').val(attributesCombinations[a]['id_attribute']);
                }
        // find combination
        if (count == tabValues.length)
            findCombination();
        // no combination found = removing attributes from url
        else
            window.location = url.substring(0, url.indexOf('#'));
    }
});

New cart summary

This is a new addition to order-payment.tpl. See the original file from the default theme.

{if !$opc}
<div id="order-detail-content" class="table_block">
	<table id="cart_summary" class="std">
		<thead>
			<tr>
				<th class="cart_product first_item">{l s='Product'}</th>
				<th class="cart_description item">{l s='Description'}</th>
				<th class="cart_availability item">{l s='Avail.'}</th>
				<th class="cart_unit item">{l s='Unit price'}</th>
				<th class="cart_quantity item">{l s='Qty'}</th>
				<th class="cart_total last_item">{l s='Total'}</th>
			</tr>
		</thead>
		<tfoot>
			{if $use_taxes}
				{if $priceDisplay}
					<tr class="cart_total_price">
						<td colspan="5">{if $display_tax_label}{l s='Total products (tax excl.):'}{else}{l s='Total products:'}{/if}</td>
						<td class="price" id="total_product">{displayPrice price=$total_products}</td>
					</tr>
				{else}
					<tr class="cart_total_price">
						<td colspan="5">{if $display_tax_label}{l s='Total products (tax incl.):'}{else}{l s='Total products:'}{/if}</td>
						<td class="price" id="total_product">{displayPrice price=$total_products_wt}</td>
					</tr>
				{/if}
			{else}
				<tr class="cart_total_price">
					<td colspan="5">{l s='Total products:'}</td>
					<td class="price" id="total_product">{displayPrice price=$total_products}</td>
				</tr>
			{/if}
			<tr class="cart_total_voucher" {if $total_discounts == 0}style="display: none;"{/if}>
				<td colspan="5">
				{if $use_taxes}
					{if $priceDisplay}
						{if $display_tax_label}{l s='Total vouchers (tax excl.):'}{else}{l s='Total vouchers:'}{/if}
					{else}
						{if $display_tax_label}{l s='Total vouchers (tax incl.):'}{else}{l s='Total vouchers:'}{/if}
					{/if}
				{else}
					{l s='Total vouchers:'}
				{/if}
				</td>
				<td class="price-discount price" id="total_discount">
				{if $use_taxes}
					{if $priceDisplay}
						{displayPrice price=$total_discounts_tax_exc}
					{else}
						{displayPrice price=$total_discounts}
					{/if}
				{else}
					{displayPrice price=$total_discounts_tax_exc}
				{/if}
				</td>
			</tr>
			<tr class="cart_total_voucher" {if $total_wrapping == 0}style="display: none;"{/if}>
				<td colspan="5">
				{if $use_taxes}
					{if $priceDisplay}
						{if $display_tax_label}{l s='Total gift-wrapping (tax excl.):'}{else}{l s='Total gift-wrapping:'}{/if}
					{else}
						{if $display_tax_label}{l s='Total gift-wrapping (tax incl.):'}{else}{l s='Total gift-wrapping:'}{/if}
					{/if}
				{else}
					{l s='Total gift-wrapping:'}
				{/if}
				</td>
				<td class="price-discount price" id="total_wrapping">
				{if $use_taxes}
					{if $priceDisplay}
						{displayPrice price=$total_wrapping_tax_exc}
					{else}
						{displayPrice price=$total_wrapping}
					{/if}
				{else}
					{displayPrice price=$total_wrapping_tax_exc}
				{/if}
				</td>
			</tr>
			{if $total_shipping_tax_exc <= 0 && !isset($virtualCart)}
				<tr class="cart_total_delivery">
					<td colspan="5">{l s='Shipping:'}</td>
					<td class="price" id="total_shipping">{l s='Free Shipping!'}</td>
				</tr>
			{else}
				{if $use_taxes}
					{if $priceDisplay}
						<tr class="cart_total_delivery" {if $shippingCost <= 0} style="display:none;"{/if}>
							<td colspan="5">{if $display_tax_label}{l s='Total shipping (tax excl.):'}{else}{l s='Total shipping:'}{/if}}</td>
							<td class="price" id="total_shipping">{displayPrice price=$shippingCostTaxExc}</td>
						</tr>
					{else}
						<tr class="cart_total_delivery"{if $shippingCost <= 0} style="display:none;"{/if}>
							<td colspan="5">{if $display_tax_label}{l s='Total shipping (tax incl.):'}{else}{l s='Total shipping:'}{/if}</td>
							<td class="price" id="total_shipping" >{displayPrice price=$shippingCost}</td>
						</tr>
					{/if}
				{else}
					<tr class="cart_total_delivery"{if $shippingCost <= 0} style="display:none;"{/if}>
						<td colspan="5">{l s='Total shipping:'}</td>
						<td class="price" id="total_shipping" >{displayPrice price=$shippingCostTaxExc}</td>
					</tr>
				{/if}
			{/if}

			{if $use_taxes}
			<tr class="cart_total_price">
				<td colspan="5" id="cart_voucher" class="cart_voucher">
				{if $voucherAllowed}
					{if isset($errors_discount) && $errors_discount}
						<ul class="error">
						{foreach from=$errors_discount key=k item=error}
							<li>{$error|escape:'htmlall':'UTF-8'}</li>
						{/foreach}
						</ul>
					{/if}
				{/if}
				</td>
				<td colspan="2" class="price total_price_container" id="total_price_container">
					<p>{l s='Total:'}</p>
					<span>{displayPrice price=$total_price}</span>
				</td>
			</tr>
			{else}
			<tr class="cart_total_price">
				<td colspan="5" id="cart_voucher" class="cart_voucher">
				{if $voucherAllowed}
				<div id="cart_voucher" class="table_block">
					{if isset($errors_discount) && $errors_discount}
						<ul class="error">
						{foreach from=$errors_discount key=k item=error}
							<li>{$error|escape:'htmlall':'UTF-8'}</li>
						{/foreach}
						</ul>
					{/if}
					{if $voucherAllowed}
					<form action="{if $opc}{$link->getPageLink('order-opc.php', true)}{else}{$link->getPageLink('order.php', true)}{/if}" method="post" id="voucher">
						<fieldset>
							<h4><label for="discount_name">{l s='Vouchers'}</label></h4>
							<p>
								<input type="text" id="discount_name" name="discount_name" value="{if isset($discount_name) && $discount_name}{$discount_name}{/if}" />
							</p>
							<p class="submit"><input type="hidden" name="submitDiscount" /><input type="submit" name="submitAddDiscount" value="{l s='ok'}" class="button" /></p>
						{if $displayVouchers}
							<h4 class="title_offers">{l s='Take advantage of our offers:'}</h4>
							<div id="display_cart_vouchers">
							{foreach from=$displayVouchers item=voucher}
								<span onclick="$('#discount_name').val('{$voucher.name}');return false;" class="voucher_name">{$voucher.name}</span> - {$voucher.description} <br />
							{/foreach}
							</div>
						{/if}
						</fieldset>
					</form>
					{/if}
				</div>
				{/if}
				</td>
				<td colspan="2" class="price total_price_container" id="total_price_container">
					<p>{l s='Total:'}</p>
					<span id="total_price">{displayPrice price=$total_price_without_tax}</span>
				</td>
			</tr>
			{/if}
		</tfoot>
		<tbody>
		{foreach from=$products item=product name=productLoop}
			{assign var='productId' value=$product.id_product}
			{assign var='productAttributeId' value=$product.id_product_attribute}
			{assign var='quantityDisplayed' value=0}
			{assign var='cannotModify' value=1}
			{assign var='odd' value=$product@iteration%2}
			{assign var='noDeleteButton' value=1}
			{* Display the product line *}
			{include file="$tpl_dir./shopping-cart-product-line.tpl"}
			{* Then the customized datas ones*}
			{if isset($customizedDatas.$productId.$productAttributeId)}
				{foreach from=$customizedDatas.$productId.$productAttributeId[$product.id_address_delivery] key='id_customization' item='customization'}
					<tr id="product_{$product.id_product}_{$product.id_product_attribute}_{$id_customization}" class="alternate_item cart_item">
						<td colspan="4">
							{foreach from=$customization.datas key='type' item='datas'}
								{if $type == $CUSTOMIZE_FILE}
									<div class="customizationUploaded">
										<ul class="customizationUploaded">
											{foreach from=$datas item='picture'}
												<li>
													<img src="{$pic_dir}{$picture.value}_small" alt="" class="customizationUploaded" />
												</li>
											{/foreach}
										</ul>
									</div>
								{elseif $type == $CUSTOMIZE_TEXTFIELD}
									<ul class="typedText">
										{foreach from=$datas item='textField' name='typedText'}
											<li>
												{if $textField.name}
													{l s='%s:' sprintf=$textField.name}
												{else}
													{l s='Text #%s:' sprintf=$smarty.foreach.typedText.index+1}
												{/if}
												{$textField.value}
											</li>
										{/foreach}
									</ul>
								{/if}
							{/foreach}
						</td>
						<td class="cart_quantity">
							{if isset($cannotModify) AND $cannotModify == 1}
								<span style="float:left">{if $quantityDisplayed == 0 AND isset($customizedDatas.$productId.$productAttributeId)}{$customizedDatas.$productId.$productAttributeId|@count}{else}{$product.cart_quantity-$quantityDisplayed}{/if}</span>
							{else}
								<div style="float:right">
									<a rel="nofollow" class="cart_quantity_delete" id="{$product.id_product}_{$product.id_product_attribute}_{$id_customization}" href="{$link->getPageLink('cart', true, NULL, "delete&amp;id_product={$product.id_product|intval}&amp;ipa={$product.id_product_attribute|intval}&amp;id_customization={$id_customization}&amp;token={$token_cart}")}"><img src="{$img_dir}icon/delete.gif" alt="{l s='Delete'}" title="{l s='Delete this customization'}" width="11" height="13" class="icon" /></a>
								</div>
								<div id="cart_quantity_button" style="float:left">
								<a rel="nofollow" class="cart_quantity_up" id="cart_quantity_up_{$product.id_product}_{$product.id_product_attribute}_{$id_customization}" href="{$link->getPageLink('cart', true, NULL, "add&amp;id_product={$product.id_product|intval}&amp;ipa={$product.id_product_attribute|intval}&amp;id_customization={$id_customization}&amp;token={$token_cart}")}" title="{l s='Add'}"><img src="{$img_dir}icon/quantity_up.gif" alt="{l s='Add'}" width="14" height="9" /></a><br />
								{if $product.minimal_quantity < ($customization.quantity -$quantityDisplayed) OR $product.minimal_quantity <= 1}
								<a rel="nofollow" class="cart_quantity_down" id="cart_quantity_down_{$product.id_product}_{$product.id_product_attribute}_{$id_customization}" href="{$link->getPageLink('cart', true, NULL, "add&amp;id_product={$product.id_product|intval}&amp;ipa={$product.id_product_attribute|intval}&amp;id_customization={$id_customization}&amp;op=down&amp;token={$token_cart}")}" title="{l s='Subtract'}">
									<img src="{$img_dir}icon/quantity_down.gif" alt="{l s='Subtract'}" width="14" height="9" />
								</a>
								{else}
								<a class="cart_quantity_down" style="opacity: 0.3;" id="cart_quantity_down_{$product.id_product}_{$product.id_product_attribute}_{$id_customization}" href="#" title="{l s='Subtract'}">
									<img src="{$img_dir}icon/quantity_down.gif" alt="{l s='Subtract'}" width="14" height="9" />
								</a>
								{/if}
								</div>
								<input type="hidden" value="{$customization.quantity}" name="quantity_{$product.id_product}_{$product.id_product_attribute}_{$id_customization}_hidden"/>
								<input size="2" type="text" value="{$customization.quantity}" class="cart_quantity_input" name="quantity_{$product.id_product}_{$product.id_product_attribute}_{$id_customization}"/>
							{/if}
						</td>
						<td class="cart_total"></td>
					</tr>
					{assign var='quantityDisplayed' value=$quantityDisplayed+$customization.quantity}
				{/foreach}
				{* If it exists also some uncustomized products *}
				{if $product.quantity-$quantityDisplayed > 0}{include file="$tpl_dir./shopping-cart-product-line.tpl"}{/if}
			{/if}
		{/foreach}
		{assign var='last_was_odd' value=$product@iteration%2}
		{foreach $gift_products as $product}
			{assign var='productId' value=$product.id_product}
			{assign var='productAttributeId' value=$product.id_product_attribute}
			{assign var='quantityDisplayed' value=0}
			{assign var='odd' value=($product@iteration+$last_was_odd)%2}
			{assign var='ignoreProductLast' value=isset($customizedDatas.$productId.$productAttributeId)}
			{assign var='cannotModify' value=1}
			{* Display the gift product line *}
			{include file="./shopping-cart-product-line.tpl" productLast=$product@last productFirst=$product@first}
		{/foreach}
		</tbody>
	{if count($discounts)}
		<tbody>
		{foreach from=$discounts item=discount name=discountLoop}
			<tr class="cart_discount {if $smarty.foreach.discountLoop.last}last_item{elseif $smarty.foreach.discountLoop.first}first_item{else}item{/if}" id="cart_discount_{$discount.id_discount}">
				<td class="cart_discount_name" colspan="2">{$discount.name}</td>
				<td class="cart_discount_description" colspan="3">{$discount.description}</td>
				<td class="cart_discount_price">
					<span class="price-discount">
						{if $discount.value_real > 0}
							{if !$priceDisplay}
								{displayPrice price=$discount.value_real*-1}
							{else}
								{displayPrice price=$discount.value_tax_exc*-1}
							{/if}
						{/if}
					</span>
				</td>
			</tr>
		{/foreach}
		</tbody>
	{/if}
	</table>
</div>
{/if}

Social titles

Social titles, such as Mr or Ms, are now generic in PrestaShop 1.5. The authentication.tpl and identity.tpl files have been changed to take this into account.

In 1.4:

<input type="radio" name="id_gender" id="id_gender1" value="1" 
  {if isset($smarty.post.id_gender) && $smarty.post.id_gender == 1}checked="checked"{/if} />
<label for="id_gender1" class="top">{l s='Mr.'}</label>
<input type="radio" name="id_gender" id="id_gender2" value="2" 
  {if isset($smarty.post.id_gender) && $smarty.post.id_gender == 2}checked="checked"{/if} />
<label for="id_gender2" class="top">{l s='Ms.'}</label>

In 1.5:

{foreach from=$genders key=k item=gender}
  <input type="radio" name="id_gender" id="id_gender{$gender->id}" value="{$gender->id}" 
    {if isset($smarty.post.id_gender) && $smarty.post.id_gender == $gender->id}checked="checked"{/if} />
  <label for="id_gender{$gender->id}" class="top">{$gender->name}</label>
{/foreach}

New template

The file layout.tpl should be taken into account.

This file is defined (by default) as follows:

  • Include header.tpl file (if we display the contents)

  • Include the desired template file

  • Include footer.tpl file (if we display the contents)

  • Include "Live Edit"

You can modify the contents of this file based on an entity type or entity itself.

Type of entity

When you want to change the layout as an entity type such as categories, you can define a file layout-EntityType.tpl defined as follows:

{if !empty($display_header)}
    {include file='../header.tpl' HOOK_HEADER=$HOOK_HEADER}
{/if}
{* Your template start here *}
{if !empty($display_footer)}
    {include file='../footer.tpl'}
{/if}
{if !empty($live_edit)}
    {$live_edit}
{/if}

This file will be placed in: /themes/default/override/layout-category.tpl (For the category entity )

N.B.: a controller is an entity type. This means that you can use this feature for the supplier, stores, product, category, and many others entities.

By entity

When you want to change the layout according to a particular entity (e.g. for the product entity with ID 1) you can define a file-layout-EntityType-ID.tpl defined as:

{if !empty($display_header)}
    {include file='../header.tpl' HOOK_HEADER=$HOOK_HEADER}
{/if}
{* Your template start here *}
{if !empty($display_footer)}
    {include file='../footer.tpl'}
{/if}
{if !empty($live_edit)}
    {$live_edit}
{/if}

This file will be placed in: /themes/default/override/layout-product-1.tpl (For the product entity with ID 1)

Dynamic template

It's possible to override the getOverrideTemplate from a FrontController to dynamically change the template.

General considerations theme URLs and form action

Many template files have been modified in the default theme in order to make use of the new feature of 1.5:

  • shopping-cart-product-line.tpl. Many modifications in order to integrate multishipping and cart rules.

  • shopping-cart.tpl. Many modification in order to integrate multishipping and cart rules.

  • order-address-multishipping-products.tpl. Whole new template (multishipping).

  • order-address-multishipping.tpl. Whole new template (multishipping).

  • order-address-product-line.tpl. Whole new template (multishipping).

  • order-confirmation.tpl. Links have been changed.

  • order-follow.tpl. Links have been changed.

  • order-payment.tpl. Added the cart summary.

  • order-return.tpl. Various changes.

  • order-slip.tpl. Links have been changed.

  • order-steps.tpl. Links have been changed.

  • cart-summary.js. the whole file has been rewritten. If you intend to update a 1.4 theme, you should directly use the 1.5 version.

  • order-opt.js. Same as cart-summary.js above.

  • product.js. Some ne JavaScript functions, such as displayDiscounts(combination), getProductAttribute(), colorPickerClick(elt) or checkUrl()

  • tools.js. Same as cart-summary.js above.

  • order-address.js. Reworked to make use of multishipping.

order-address.tpl

Two new variables:

var addressMultishippingUrl = "{$link->getPageLink('address', true, NULL, "back={$back_order_page}?step=1{'&multi-shipping=1'|urlencode}{if $back}&mod={$back|urlencode}{/if}")}";
var addressUrl = "{$link->getPageLink('address', true, NULL, "back={$back_order_page}?step=1{if $back}&mod={$back}{/if}")}";

End of main code block in 1.4:

{else}
  <div id="opc_account" class="opc-main-block">
    <div id="opc_account-overlay" class="opc-overlay" style="display:none;"></div>
{/if}

End of main code block in 1.5:

{else}
{if {Configuration::get('PS_ALLOW_MULTISHIPPING')} && !$cart->isVirtualCart()}
<div class="address-form-multishipping">
  <div class="button_multishipping_mode" id="multishipping_mode_box">
    <div class="title">{l s='Multi-shipping'}</div>
    <div class="description">
	  <input type="checkbox" id="multishipping_mode_checkbox" onchange="multishippingMode(this); return false;"/><label for="multishipping_mode_checkbox">{l s='I want to specify a delivery address for each product I order.'}</label>
    </div>
    <div class="description_off">
	  <a href="{$link->getPageLink('order-opc', true, NULL, 'ajax=1&multi-shipping=1&method=multishipping')}" id="link_multishipping_form" title="{l s='Choose the delivery addresses'}">
	    {l s='Specify a delivery address for each product.'}
      </a>
    </div>
  </div>
  <script type="text/javascript">
    {if $is_multi_address_delivery}
	var multishipping_mode = true;
    {else}
	var multishipping_mode = false;
    {/if}
    var open_multishipping_fancybox = {$open_multishipping_fancybox|intval};
  </script>
</div>
{/if}
<div id="opc_account" class="opc-main-block">
<div id="opc_account-overlay" class="opc-overlay" style="display: none;"></div>
{/if}

order-carrier.tpl

Note that the HOOK_EXTRACARRIER hook can now be used multiple times when multiple shipping is used:

  • In 1.4:Extract from order-carrier.tpl in v1.4

    ...
    <tr id="HOOK_EXTRACARRIER">{$HOOK_EXTRACARRIER}</tr>
    ...
  • In 1.5:Extract from order-carrier.tpl in v1.5

    ...
    <div class="hook_extracarrier" id="HOOK_EXTRACARRIER_{$id_address}">{if isset($HOOK_EXTRACARRIER_ADDR) && isset($HOOK_EXTRACARRIER_ADDR.$id_address)}{$HOOK_EXTRACARRIER_ADDR.$id_address}{/if}</div>
    {foreachelse}
    <p class="warning" id="noCarrierWarning">
      {foreach $cart->getDeliveryAddressesWithoutCarriers(true) as $address}
        {if empty($address->alias)}
          {l s='No carriers available.'}
        {else}
          {l s='No carriers available for the address "%s".' sprintf=$address->alias}
        {/if}
        {if !$address@last}
          <br />
        {/if}
      {/foreach}
    </p>
    {/foreach}
    ...

order-detail.tpl

The following lines have been added in v1.5 in order to enable displaying the number of returned products directly in the order summary (order details):

{if $order->hasProductReturned()}
  <th class="item">
    {l s='Returned'}
  </th>
{/if}
{if $order->hasProductReturned()}
  <td>
    {$product['qty_returned']}
  </td>
{/if}

The following new lines make it possible for your shop to give the customers details about the delivery, for instance its tracking number which can prove invaluable when multishipping is used.

<div class="table_block">
  {if $order->getShipping()|count > 0}
    <table class="std">
      <thead>
        <tr>
          <th class="first_item">{l s='Date'}</th>
          <th class="item">{l s='Carrier'}</th>
          <th class="item">{l s='Weight'}</th>
          <th class="item">{l s='Shipping cost'}</th>
          <th class="last_item">{l s='Tracking number'}</th>
        </tr>
      </thead>
      <tbody>
      {foreach from=$order->getShipping() item=line}
        <tr class="item">
          <td>{$line.date_add}</td>
          <td>{$line.state_name}</td>
          <td>{if $line.weight > 0}{$line.weight|string_format:"%.3f"} {Configuration::get('PS_WEIGHT_UNIT')}{else}-{/if}</td>
          <td>{if $order->getTaxCalculationMethod() == $smarty.const.PS_TAX_INC}{displayPrice price=$line.shipping_cost_tax_incl currency=$currency->id}{else}{displayPrice price=$line.shipping_cost_tax_excl currency=$currency->id}{/if}</td>
          <td>
            <span id="shipping_number_show">{if $line.tracking_number}{if $line.url && $line.tracking_number}<a href="{$line.url|replace:'@':$line.tracking_number}">{$line.tracking_number}</a>{else}{$line.tracking_number}{/if}{else}-{/if}</span>
          </td>
        </tr>
      {/foreach}
      </tbody>
    </table>
  {/if}
</div>

order-opc.tpl

New 'back' parameter added to addressUrl JavaScript variable:

{if $opc}
  {assign var="back_order_page" value="order-opc.php"}
{else}
  {assign var="back_order_page" value="order.php"}
{/if}

...then in the JavaScript code:

var addressUrl = '{$link->getPageLink("address", true, NULL, "back={$back_order_page}")}';

Also, the file has a new JavaScript variable:

var txtSelectAnAddressFirst = "{l s='Please start by selecting an address'}";

The main data table has been heavily reworked, see the corresponding file in the default theme. You could also perfom a diff on this file in its 1.4 and 1.5 incarnations, for instance using .

http://www.quickdiff.com/
Changes in version 1.5 which impact theme development
Foreword
getPageLink
B2B
Layered navigation
Product attributes
Changes to be applied to a 1.4 theme in order use per-combination unique product URLs
New cart summary
Social titles
New template
Dynamic template
General considerations theme URLs and form action