Tutoriel override Prestashop partie 1: Surcharge de classe et controller CMS

Prestashop 1.4Pour commencer nous allons nous rendre dans le back office de prestashop afin de créer des pages CMS.

L’astuce ici consiste à utiliser les sous catégories de pages CMS comme des références à des marques de votre catalogue. (ATTENTION, cela détourne la fonctionnalité première des catégories de CMS de prestashop).

Etant donné que la catégorie 1 existe déjà et ne peut pas être supprimée (c’est la catégorie d’accueil), il faudra bien faire attention de ne pas créer de marque avec l’identifiant 1 (ou du moins penser à désactiver cette marque).

Je vais donc créer en premier lieu une sous catégorie 2, portant le nom « Ma marque » puis je vais lui rattacher 3 pages CMS que je vais également créer. Une fois cela fait, je vais pouvoir commencer mes overrides.

Nous allons tout d’abord surcharger la classe CMSCore afin de lui ajouter une méthode (getFirstCMSPage()), qui nous permettra de savoir quelle est la première page CMS rattachée à notre marque. Nous nous en servirons dans le CMSController afin de rediriger vers la page CMS récupérée. Voici le code :

<?php
class CMS extends CMSCore
{
 
	public static function getFirstCMSPage($id_lang = NULL, $id_cms_category = NULL, $active = true)
	{
		return Db::getInstance()->ExecuteS('
		SELECT *
		FROM `'._DB_PREFIX_.'cms` c
		JOIN `'._DB_PREFIX_.'cms_lang` l ON (c.id_cms = l.id_cms)'.
		(isset($id_cms_category) ? 'WHERE `id_cms_category` = '.(int)($id_cms_category) : '').
		($active ? ' AND c.`active` = 1 ' : '').'
		AND l.id_lang = '.(int)($id_lang).'
		ORDER BY `position`
		LIMIT 0, 1');
	}
 
}

Comme indiqué dans mon premier tuto sur l’override de classes prestashop, pour surcharger cette classe CMS, vous devrez enregistrer ce fichier sous le nom « CMS.php » dans le répertoire « override/classes« .
Maintenant, allons surcharger le CMSController afin de pouvoir afficher des infos sur la marque en entête de page et afficher également le listing des pages CMS rattachées à ce Manufacturer.

<?php
class CmsController extends CmsControllerCore
{
	public $php_self = 'cms.php';
 
	public $assignCase;
	public $manufacturer;
	public $cms;
	public $cms_category;
 
	public function preProcess()
	{
		if ($id_cms = (int)Tools::getValue('id_cms')) {
		    $this->cms = new CMS($id_cms, self::$cookie->id_lang);
		    $this->manufacturer = new Manufacturer($this->cms->id_cms_category, self::$cookie->id_lang);
		}
		$this->canonicalRedirection();
 
		parent::preProcess();
 
		/* assignCase (1 = CMS page, 2 = CMS category) */
		if (Validate::isLoadedObject($this->cms) AND ($this->cms->active OR (Tools::getValue('adtoken') == Tools::encrypt('PreviewCMS'.$this->cms->id) AND file_exists(dirname(__FILE__).'/../'.Tools::getValue('ad').'/ajax.php'))))
			$this->assignCase = 1;
		else
			Tools::display404Error('404.php');
	}
 
	public function process()
	{
		global $link;
		$pipe = Configuration::get('PS_NAVIGATION_PIPE');
		if (empty($pipe))
			$pipe = '>';
		FrontControllerCore::process();
		$parent_cat = new CMSCategory(1, (int)(self::$cookie->id_lang));
		self::$smarty->assign('id_current_lang', self::$cookie->id_lang);
		self::$smarty->assign('home_title', $parent_cat->name);
 
		if ($this->assignCase == 1)
		{
			$path = '<a title="'.htmlentities($this->manufacturer->name, ENT_NOQUOTES, 'UTF-8').
				'" href="%27%20.%20%20%09%09%09%09Tools::safeOutput%28$link-%3EgetManufacturerLink%28%28int%29$this-%3Emanufacturer-%3Eid_manufacturer%29%29.%0A%09%09%09%09%27">' . $this->manufacturer->name . '</a>'. $pipe. '';
			self::$smarty->assign(array(
				'cms' => $this->cms,
				'content_only' => (int)(Tools::getValue('content_only')),
				'path' => $path . Tools::getFullPath(1, $this->cms->meta_title, 'CMS'),
				'cms_pages' => CMS::getCMSPages((int)(self::$cookie->id_lang), (int)($this->cms->id_cms_category) )
			));
		}
		if (Validate::isLoadedObject($this->manufacturer) AND $this->manufacturer->active)
		{
			self::$smarty->assign(array(
				'manufacturer' => $this->manufacturer));
		}
	}
 
	public function displayContent()
	{
		FrontControllerCore::displayContent();
		self::$smarty->display(_PS_THEME_DIR_.'manufacturer-cms.tpl');
	}
}

Maintenant, décrivons ce que nous venons de faire : comme expliqué en introduction, nous avons besoin d’un Manufacturer pour pouvoir afficher les infos en entete de page et mettre un lien vers ses produits. C’est ce que nous faisons à la ligne 10 en initialisant un objet Manufacturer avec l’identifiant de category de notre page CMS en cours :

$this->manufacturer = new Manufacturer($this->cms->id_cms_category, self::$cookie->id_lang);

Puis, nous avons besoin des autres pages CMS rattachées à notre marque pour pouvoir les afficher dans notre menu, c’est ce que fait cette ligne :

'cms_pages' => CMS::getCMSPages((int)(self::$cookie->id_lang), (int)($this->cms->id_cms_category) )

Vous remarquerez au passage que nous avons complètement enlevé les lignes de code faisant référence aux sous catégories de CMS (assignCase == 2).

Je passe rapidement sur l’initialisation du fil d’ariane (ou chemin de fer) que l’on aurait certainement pu gérer autrement. Nous afficherons juste le nom de la marque entre la page Accueil et le nom de la page CMS en cours.

$pipe = Configuration::get('PS_NAVIGATION_PIPE');
		if (empty($pipe))
			$pipe = '>';
$path = '<a title="'.htmlentities($this->manufacturer->name, ENT_NOQUOTES, 'UTF-8').
				'" href="%27%20.%20%20%09%09%09%09Tools::safeOutput%28$link-%3EgetManufacturerLink%28%28int%29$this-%3Emanufacturer-%3Eid_manufacturer%29%29.%0A%09%09%09%09%27">' . $this->manufacturer->name . '</a>'. $pipe. '';
'path' => $path . Tools::getFullPath(1, $this->cms->meta_title, 'CMS'),

Attention également à bien appeler la méthode « process()« , non pas du parent mais du FrontController (pour éviter d’appeler 2 fois les mêmes choses vu que votre Controller hérite de CMSControllerCore):

FrontControllerCore::process();

Idem dans la méthode « displayContent()« , pensez bien à appeler la méthode de FrontControllerCore.

Voici le code du fichier manufacturer-cms.tpl pour ceux que cela intéresse :

{include file="$tpl_dir./breadcrumb.tpl"}
{include file="$tpl_dir./manufacturer-header.tpl"}	
{if isset($cms) && !isset($category)}
<div class="rte{if $content_only} content_only{/if}">
<div id="left">{$cms->content}</div>
&nbsp;
<div id="right">{if isset($cms_pages) & !empty($cms_pages)} 
<ul class="bullet">
<ul class="bullet">{foreach from=$cms_pages item=cmspages} id} class='actif'{/if}></ul>
</ul>
<a href="{$link->getCMSLink($cmspages.id_cms, $cmspages.link_rewrite)|escape:'htmlall':'UTF-8'}#anchor">{if $cmspages.meta_keywords}{$cmspages.meta_keywords|escape:'htmlall':'UTF-8'}{else}{$cmspages.meta_title|escape:'htmlall':'UTF-8'}{/if}</a>{/foreach}
 
{/if}
 
</div>
</div>
{else} {l s='This page does not exist.'} {/if}

Et également le code de manufacturer-header.tpl utilisé dans manufacturer-cms.tpl et manufacturer.tpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<div id="imgprod"><img src="{$img_manu_dir}{$manufacturer->id}.jpg"></div>
<div id="infoprod">
	<h1>{$manufacturer->name}</h1>
	<h2>{$manufacturer->title}</h2>
	<div id="adresse">
	<p>{l s='Address :'}</p>
	<address>
	{$manufacturer->address1}
	{$manufacturer->address2}
	{$manufacturer->postcode}
	{$manufacturer->city}
	</address>
	</div>
	<div id="infocontact">
    <ul>
    	<li>	
		<p>{l s='Phone :'}</p>
		{$manufacturer->phone}
		</li>
	</ul>
	</div>
</div>
<hr class="clearhr" />
<a name="anchor"></a>
<ul id="sousnav"> 
{if isset($first_cms_page)}
	{foreach from=$first_cms_page item=cmspage}
   	<li><a href="{$link->getCMSLink($cmspage.id_cms, $cmspage.link_rewrite)|escape:'htmlall':'UTF-8'}#anchor"{if $smarty.server.SCRIPT_NAME == "/cms.php"} class="actif"{/if}>{l s='Presentation'}</a></li>
    {/foreach}
{else}
    <li><a{if $smarty.server.SCRIPT_NAME == "/cms.php"} class="actif"{/if}>{l s='Presentation'}</a></li>
{/if}
 
	<li><a href="{$link->getManufacturerProductsLink($manufacturer)}#anchor"{if ($smarty.server.SCRIPT_NAME == "/manufacturer.php" && $smarty.get.param == "products") || $smarty.server.SCRIPT_NAME == "/product.php"} class="actif"{/if}>{l s='Our products'}</a></li>
</ul>

Et voilà pour notre surcharge de CMSController, nos pages CMS sont prêtes à être affichées, nous pouvons maintenant travailler sur les pages Manufacturer et le controller Manufacturer :

Tutoriel override prestashop partie 2 : surcharge du controller ManufacturerController

Vous pouvez répondre, ou faire un trackback depuis votre propre site web.

6 Réponses sur “Tutoriel override Prestashop partie 1: Surcharge de classe et controller CMS”

  1. Dardanelli Laurent dit :

    Bonjour
    Merci beaucoup pour ce tutoriel. L’exemple pris est exactement ce que je souhaite faire.
    Pour le moment, chez moi cela ne marche pas, mais je suppose que c’est parce que le fichier manufacturer-cms.tpl n’existe pas.
    Auriez vous un exemple de ce type de fichier pour savoir si c’est bien ça la source du problème ou s’il faut que je cherche ailleurs…
    Merci d’avance
    Cdt
    Laurent Dardanelli

    • admin dit :

      Bonjour,

      je viens de mettre le code du fichier tpl en ligne sur l’article afin que vous ayez une idée du fonctionnement.
      Quelle est l’erreur affichée ?

      Cordialement
      Michel

      • Dardanelli Laurent dit :

        Bonjour,
        Je mets un peu de temps à vous répondre, tellement de chose à faire à côté…
        Lorsque j’introduis Link.php, voici le message d’erreur :

        class Link extends LinkCore { public function getManufacturerProductsLink($id_manufacturer, $alias = NULL, $id_lang = NULL) { return $this->getManufacturerWithParamLink($id_manufacturer, ‘products’, $alias, $id_lang); } public function getManufacturerWithParamLink($id_manufacturer, $param = ‘products’, $alias = NULL, $id_lang = NULL) { if (is_object($id_manufacturer)) return ($this->allow == 1) ? (_PS_BASE_URL_.__PS_BASE_URI__.$param.’/’.$this->getLangLink((int)($id_lang)).(int)($id_manufacturer->id).’_’.$id_manufacturer->link_rewrite) : (_PS_BASE_URL_.__PS_BASE_URI__.’manufacturer.php?id_manufacturer=’.(int)($id_manufacturer->id).’¶m=’.$param); if ($alias) return ($this->allow == 1) ? (_PS_BASE_URL_.__PS_BASE_URI__.$param.’/’.$this->getLangLink((int)($id_lang)).(int)($id_manufacturer).’_’.$alias) : (_PS_BASE_URL_.__PS_BASE_URI__.’manufacturer.php?id_manufacturer=’.(int)($id_manufacturer).’¶m=’.$param); return _PS_BASE_URL_.__PS_BASE_URI__.’manufacturer.php?id_manufacturer=’.(int)($id_manufacturer).’¶m=’.$param; } }

        Dans l’attente de votre retour
        Cordialement
        Laurent

        • Michel dit :

          Bonjour,

          je pense qu’il vous manque la balise d’ouverture php <?php en début de fichier que je n’ai pas inséré dans mon code. Je vais corriger l’erreur.
          Il faut faire de même pour tous les fichiers php que je donne dans le tuto.

          Cordialement
          Michel

          • Dardanelli Laurent dit :

            Merci beaucoup,
            Maintenant ma page CMS s’affiche lorsque je clique sur le lien du fabricant. C’est un bon début pour moi.
            Par contre, les liens vers les produits ni vers les autres pages.
            Est-ce que c’est « manufacturer-header.tpl » qui permet leur affichage? Pourriez vous nous le montrer également?
            Ensuite, j’ai une remarque plus sur le fonctionnement.
            Vous l’avez compris je ne suis pas technicien donc je ne cerne surement pas tout…
            Le lien entre le fabricant et les pages CMS se fait grâce à un identifiant identique, c’est bien ça?
            Or comme à moins d’intervenir dans la base de données, on ne peut pas choisir l’id du cms, ne pourrait-on pas faire le lien à partir du nom du fabricant (à nous de bien nommer les deux de façon identique).
            Cordialement
            Laurent

          • Michel dit :

            Effectivement, les liens vers les autres pages sont présents dans le manufacturer-header.tpl.
            Je vais donner le code dans l’article afin que vous ayez un exemple.
            Concernant le lien entre les pages CMS et le fabricant, il aurait bien sur été possible de lier les pages en utilisant un prefixe commun comme le nom du fabricant. Par exemple, créer une page cms portant le nom « nom-du-fabricant-nom-de-la-page-cms » (et faire de même sur toutes autres pages CMS reliées au fabricant).
            Cependant, il me parait plus simple techniquement d’associer l’identifiant de catégorie des CMS à l’identifiant du Manufacturer. Alors, oui, comme je le dis dans l’introduction, on detourne l’utilité de cette fonction de prestashop mais jusqu’à présent, je ne me suis pas encore servi de celle ci de façon « normale ».
            Et en plus cela permet d’avoir un moyen « simple » de faire l’association depuis l’admin de prestashop, car il suffit de créer les catégories de page CMS avec les noms des fabricants pour pouvoir ensuite les voir remonter automatiquement sur la page associée.
            Cordialement
            Michel

Donner votre avis