Gérer des routes particulières sur PrestaShop

PrestaShop permet à ses utilisateurs disposant d'un serveur web supportant l'URL rewriting de gérer les URLs de leur boutique d'une manière assez complète : il suffit de modifier, directement dans le back-office, les masques correspondant à tel ou tel type d'URL pour voir toute la structure de son site se mettre à jour automatiquement, et tout cela est bien beau.

Mais qu'advient-il le jour où, pris de folie, vous vous rendez compte que vous avez besoin de gérer une URL spécifique pour une page ? Prenons l'exemple d'une catégorie : d'un point de vue technique, PrestaShop vous oblige à faire figurer l'id de ladite catégorie dans son URL. Comment faire pour s'en débarrasser sans casser tout le fonctionnement du routeur interne ?

La solution que je vous propose aujourd'hui consiste en une simple surcharge de la classe Dispatcher :

<?php

class Dispatcher extends DispatcherCore
{
// On définit des routes particulières, qui auront la priorité sur le processus de routage basique
// À gauche, l'URL actuelle ; à droite, l'URL souhaitée

public $special_routes = array(
'/3-my-category' => '/my-awesome-url'
);



public function dispatch()
{
// On démarre une session PHP classique pour la persistence des données POST,
// étant donné que PrestaShop lui-même n'en fait pas usage
session_start();

$this->getController();
$request_uri = explode('?', $this->request_uri);

// Si on a sauvegardé des données POST avant redirection, on les récupère
if (isset($_SESSION['_POST'])) {
$_POST = $_SESSION['_POST'];
unset($_SESSION['_POST']);
}

foreach ($this->special_routes as $old_url => $new_url) {
if ($request_uri[0] == $new_url) {
// Une "nouvelle" URL est demandée :
// on passe la requête à sa contrepartie originelle

$_GET['controller'] = false;
$this->controller = false;
$request_uri[0] = $old_url;
$this->request_uri = implode('?', $request_uri);
break;
} else if ($request_uri[0] == $old_url) {
// Une "ancienne" URL est demandée :
// on sauvegarde les données POST s'il y en a,
// et on redirige vers l'URL voulue

$_SESSION['_POST'] = $_POST;
$request_uri[0] = $new_url;
header('Status: 301 Moved Permanently', false, 301);
header('Location: '.implode('?', $request_uri));
die;
}
}

parent::dispatch();
}



// On fait maintenant en sorte que le générateur d'URLs utilise les nôtres
// Cela nous permet de gagner du temps et de nous assurer de la réussite des requêtes AJAX

public function createUrl($route_id, $id_lang = null, array $params = array(), $force_routes = false, $anchor = '', $id_shop = null) {
$url = '/'.parent::createUrl($route_id, $id_lang, $params, $force_routes, $anchor, $id_shop);
return ltrim((isset($this->special_routes[$url]) ? $this->special_routes[$url] : $url), '/');
}
}

Ainsi, dans cet exemple, naviguer vers /my-awesome-url fera apparaître la catégorie voulue ; et si on se rend directement à cette dernière via /3-my-category, on sera redirigé. Les éventuels paramètres GET et POST seront conservés.

Pour que ceci fonctionne, vous devez désactiver l'option de redirection canonique native dans le back-office de PrestaShop (dans Préférences > SEO & URLs). Soyez sûr·e d'avoir conscience des conséquences !