[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"theme-db":3,"$fctThDwH-CAg21kYQJrLlkPqye21YPtJeegGEEybm94E":22,"megamenu":60,"$fKnz2vuX4bZz1LbUTiuFsvSZ3e07l5_5fqNYp4Tzdhi8":130,"header-db":198,"$fUD0nTQyOF-_w3_xNbJj3gv-U6akkru6vY_M307xZ3ac":211,"footer-db":225},{"theme":4},{"colors":5,"typography":13,"ui":17,"defaultColorMode":21},{"primary":6,"secondary":7,"background":8,"foreground":9,"muted":10,"headerBg":11,"footerBg":12,"topBarBg":9,"topBarText":11},"#4F46E5","#0D9488","#F9FAFB","#111827","#6B7280","#ffffff","#020617",{"fontFamily":14,"fontUrl":15,"baseFontSize":16},"Inter, system-ui, sans-serif","https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Inter:wght@400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,700;0,800;0,900;1,400;1,700&display=swap","16px",{"borderRadius":18,"contentWidth":19,"shadow":20},"lg","7xl",true,"light",{"title":23,"slug":24,"metaDescription":25,"category":26,"tags":27,"difficulty":33,"psVersions":34,"content":38,"faq":39,"tldr":55,"readingTime":56,"generatedAt":57,"publishDate":57,"relatedArticles":58,"sourceCategory":59},"Ajouter un champ image personnalisé aux catégories PrestaShop","ajouter-champ-image-personnalise-categories-prestashop","Guide complet pour ajouter un second champ image aux catégories PrestaShop 1.7 et 8.x : override de classe, migration SQL, back-office et affichage front.","developpement",[28,29,30,31,32],"override","catégories","personnalisation","back-office","images","avance",[35,36,37],"1.6","1.7","8.x","\u003Ch2>Pourquoi ajouter une seconde image aux catégories ?\u003C\u002Fh2>\n\u003Cp>Le système natif de PrestaShop ne propose qu'une seule image par catégorie, accompagnée éventuellement d'une vignette (thumbnail). C'est souvent insuffisant pour les besoins de webdesign modernes : image de fond pleine largeur dans le header, visuel d'ambiance distinct de la vignette de navigation, bannière promotionnelle saisonnière…\u003C\u002Fp>\n\u003Cp>L'ajout d'un champ \u003Ccode>id_image2\u003C\u002Fcode> aux catégories permet de gérer deux visuels indépendants directement depuis le back-office, sans recourir à un module tiers. Ce tutoriel détaille chaque étape, du schéma SQL jusqu'à l'affichage front-end.\u003C\u002Fp>\n\u003Ch2>Prérequis et préparation\u003C\u002Fh2>\n\u003Cp>Avant toute modification structurelle :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>**Activez le mode debug** pour ne jamais rester bloqué sur une page blanche sans message d'erreur\u003C\u002Fli>\n\u003Cli>Sauvegardez votre base de données\u003C\u002Fli>\n\u003Cli>Travaillez sur un environnement de développement ou de préprod\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Activer le mode développeur\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>PrestaShop 1.6 :\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F config\u002Fdefines.inc.php\nif (!defined('_PS_MODE_DEV_'))\n    define('_PS_MODE_DEV_', true);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>PrestaShop 1.7 \u002F 8.x :\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F .env ou app\u002Fconfig\u002Fparameters.php\n\u002F\u002F Passez PS_DEV_MODE à true\ndefine('_PS_MODE_DEV_', true);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Sur PrestaShop 8.x, vous pouvez également utiliser le fichier \u003Ccode>.env\u003C\u002Fcode> à la racine :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-\">\nAPP_DEBUG=1\nAPP_ENV=dev\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Cette activation est \u003Cstrong>indispensable\u003C\u002Fstrong> : sans elle, une erreur PHP produit une page blanche inexploitable.\u003C\u002Fp>\n\u003Ch2>Étape 1 : Modification de la base de données\u003C\u002Fh2>\n\u003Cp>Ajoutez la colonne \u003Ccode>id_image2\u003C\u002Fcode> à la table des catégories :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">\nALTER TABLE `ps_category`\n  ADD `id_image2` INT(10) UNSIGNED DEFAULT NULL AFTER `id_parent`;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Cette colonne stockera l'identifiant de la seconde image. Le préfixe \u003Ccode>ps_\u003C\u002Fcode> correspond au préfixe par défaut de vos tables — adaptez-le si nécessaire.\u003C\u002Fp>\n\u003Ch2>Étape 2 : Override de la classe Category\u003C\u002Fh2>\n\u003Cp>Créez le fichier d'override pour étendre le modèle \u003Ccode>Category\u003C\u002Fcode> avec la gestion de la nouvelle image.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Chemin :\u003C\u002Fstrong> \u003Ccode>override\u002Fclasses\u002FCategory.php\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\n\u002F**\n * Override Category - Ajout d'un second champ image\n *\u002F\nclass Category extends CategoryCore\n{\n    \u002F** @var int|null Identifiant de la seconde image *\u002F\n    public $id_image2;\n\n    \u002F**\n     * Définition enrichie avec le nouveau champ\n     *\u002F\n    public function __construct($id_category = null, $id_lang = null, $id_shop = null)\n    {\n        \u002F\u002F Déclaration du champ avant l'appel parent\n        self::$definition['fields']['id_image2'] = [\n            'type' =&gt; self::TYPE_INT,\n            'validate' =&gt; 'isUnsignedId',\n        ];\n\n        parent::__construct($id_category, $id_lang, $id_shop);\n    }\n\n    \u002F**\n     * Ajoute (upload) la seconde image\n     *\n     * @return bool\n     *\u002F\n    public function addImage2()\n    {\n        if (!isset($_FILES['image2']) || $_FILES['image2']['error'] !== UPLOAD_ERR_OK) {\n            return false;\n        }\n\n        $tmp_name = $_FILES['image2']['tmp_name'];\n        $target_dir = _PS_CAT_IMG_DIR_;\n        $image_name = (int)$this-&gt;id . '-2';\n\n        \u002F\u002F Génération des différents formats d'image\n        $image_types = ImageType::getImagesTypes('categories');\n\n        if (!ImageManager::resize($tmp_name, $target_dir . $image_name . '.jpg')) {\n            return false;\n        }\n\n        foreach ($image_types as $image_type) {\n            ImageManager::resize(\n                $tmp_name,\n                $target_dir . $image_name . '-' . stripslashes($image_type['name']) . '.jpg',\n                (int)$image_type['width'],\n                (int)$image_type['height']\n            );\n        }\n\n        \u002F\u002F Mise à jour de l'identifiant en base\n        $this-&gt;id_image2 = 1;\n        return $this-&gt;update();\n    }\n\n    \u002F**\n     * Supprime la seconde image et toutes ses déclinaisons\n     *\n     * @return bool\n     *\u002F\n    public function deleteImage2()\n    {\n        $target_dir = _PS_CAT_IMG_DIR_;\n        $image_name = (int)$this-&gt;id . '-2';\n\n        \u002F\u002F Suppression de l'image originale\n        $path = $target_dir . $image_name . '.jpg';\n        if (file_exists($path)) {\n            @unlink($path);\n        }\n\n        \u002F\u002F Suppression des déclinaisons\n        $image_types = ImageType::getImagesTypes('categories');\n        foreach ($image_types as $image_type) {\n            $path = $target_dir . $image_name . '-' . stripslashes($image_type['name']) . '.jpg';\n            if (file_exists($path)) {\n                @unlink($path);\n            }\n        }\n\n        $this-&gt;id_image2 = null;\n        return $this-&gt;update();\n    }\n\n    \u002F**\n     * Retourne le chemin de la seconde image\n     *\n     * @param string $type Format d'image (ex: 'medium_default')\n     * @return string|false\n     *\u002F\n    public function getImage2Url($type = 'category_default')\n    {\n        $path = _PS_CAT_IMG_DIR_ . (int)$this-&gt;id . '-2-' . $type . '.jpg';\n        if (file_exists($path)) {\n            return _THEME_CAT_DIR_ . (int)$this-&gt;id . '-2-' . $type . '.jpg';\n        }\n        return false;\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Point critique : le cache des classes\u003C\u002Fh3>\n\u003Cp>Après avoir créé ou modifié un override, vous \u003Cstrong>devez\u003C\u002Fstrong> supprimer le fichier d'index des classes pour que PrestaShop prenne en compte vos modifications :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">\n# PrestaShop 1.6\nrm var\u002Fcache\u002F*\u002Fclass_index.php\n\n# PrestaShop 1.7 \u002F 8.x\nrm var\u002Fcache\u002Fdev\u002Fclass_index.php\nrm var\u002Fcache\u002Fprod\u002Fclass_index.php\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Sans cette suppression, vous obtiendrez l'erreur :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-\">\nCall to undefined method Category::deleteImage2\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Cette erreur signifie que PHP utilise encore la classe \u003Ccode>CategoryCore\u003C\u002Fcode> en cache au lieu de votre override. C'est le piège le plus fréquent de cette manipulation.\u003C\u002Fp>\n\u003Ch2>Étape 3 : Modification du back-office\u003C\u002Fh2>\n\u003Cp>Pour que l'administrateur puisse uploader la seconde image, il faut ajouter le champ dans le formulaire de gestion des catégories.\u003C\u002Fp>\n\u003Ch3>PrestaShop 1.6 (AdminCategoriesController)\u003C\u002Fh3>\n\u003Cp>Créez l'override du contrôleur :\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Chemin :\u003C\u002Fstrong> \u003Ccode>override\u002Fcontrollers\u002Fadmin\u002FAdminCategoriesController.php\u003C\u002Fcode>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\nclass AdminCategoriesController extends AdminCategoriesControllerCore\n{\n    public function renderForm()\n    {\n        \u002F\u002F Appel du formulaire parent\n        $form = parent::renderForm();\n\n        \u002F\u002F Injection du champ image2 dans le HTML\n        \u002F\u002F (méthode simplifiée — en production, utilisez le système de hooks)\n        $image2_field = '&lt;div class=\"form-group\"&gt;';\n        $image2_field .= '&lt;label class=\"control-label col-lg-3\"&gt;Image secondaire&lt;\u002Flabel&gt;';\n        $image2_field .= '&lt;div class=\"col-lg-9\"&gt;';\n        $image2_field .= '&lt;input type=\"file\" name=\"image2\" accept=\"image\u002F*\" \u002F&gt;';\n\n        if ($this-&gt;object && $this-&gt;object-&gt;id_image2) {\n            $image2_field .= '&lt;p class=\"help-block\"&gt;&lt;img src=\"'\n                . _THEME_CAT_DIR_ . (int)$this-&gt;object-&gt;id . '-2-medium_default.jpg'\n                . '\" style=\"max-width:200px\" \u002F&gt;&lt;\u002Fp&gt;';\n        }\n\n        $image2_field .= '&lt;\u002Fdiv&gt;&lt;\u002Fdiv&gt;';\n\n        \u002F\u002F Insertion avant le bouton de soumission\n        $form = str_replace('id=\"category_form_submit_btn\"', $image2_field . 'id=\"category_form_submit_btn\"', $form);\n\n        return $form;\n    }\n\n    public function postProcess()\n    {\n        parent::postProcess();\n\n        if (Tools::isSubmit('submitAddcategory') || Tools::isSubmit('submitAddcategoryAndStay')) {\n            $category = new Category((int)Tools::getValue('id_category'));\n            if (Validate::isLoadedObject($category)) {\n                $category-&gt;addImage2();\n            }\n        }\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>PrestaShop 8.x (Symfony)\u003C\u002Fh3>\n\u003Cp>Sur PrestaShop 8.x, le back-office utilise Symfony. L'approche recommandée est de créer un \u003Cstrong>module\u003C\u002Fstrong> qui utilise les hooks de formulaire :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\n\u002F\u002F modules\u002Fmymodule\u002Fmymodule.php (extrait)\n\npublic function hookActionCategoryFormBuilderModifier(array $params)\n{\n    \u002F** @var FormBuilderInterface $formBuilder *\u002F\n    $formBuilder = $params['form_builder'];\n\n    $formBuilder-&gt;add('image2', FileType::class, [\n        'label' =&gt; $this-&gt;trans('Image secondaire', [], 'Modules.Mymodule.Admin'),\n        'required' =&gt; false,\n        'attr' =&gt; ['accept' =&gt; 'image\u002F*'],\n    ]);\n\n    \u002F\u002F Pré-remplissage si l'image existe\n    $categoryId = $params['id'];\n    $params['data']['image2'] = null;\n    $formBuilder-&gt;setData($params['data']);\n}\n\npublic function hookActionAfterUpdateCategoryFormHandler(array $params)\n{\n    $this-&gt;handleImage2Upload($params);\n}\n\npublic function hookActionAfterCreateCategoryFormHandler(array $params)\n{\n    $this-&gt;handleImage2Upload($params);\n}\n\nprivate function handleImage2Upload(array $params)\n{\n    $categoryId = $params['id'];\n    $category = new Category((int)$categoryId);\n\n    if (Validate::isLoadedObject($category)) {\n        $category-&gt;addImage2();\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Cette approche par module est nettement plus propre et survivra aux mises à jour de PrestaShop.\u003C\u002Fp>\n\u003Ch2>Étape 4 : Affichage front-end\u003C\u002Fh2>\n\u003Ch3>Affichage dans le template de catégorie\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>PrestaShop 1.6 (Smarty) :\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-smarty\">\n{* Image secondaire de la catégorie courante *}\n{if $category-&gt;id_image2}\n    &lt;img\n        class=\"category-header-bg\"\n        src=\"{$link-&gt;getCatImageLink($category-&gt;link_rewrite, $category-&gt;id_image2, 'category_default')|escape:'html':'UTF-8'}\"\n        alt=\"{$category-&gt;name|escape:'html':'UTF-8'}\"\n        loading=\"lazy\"\n    \u002F&gt;\n{\u002Fif}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>Attention\u003C\u002Fstrong> à la variable utilisée : \u003Ccode>$category\u003C\u002Fcode> pour la catégorie en cours, \u003Ccode>$subcategory\u003C\u002Fcode> dans une boucle sur les sous-catégories. Confondre les deux est une source d'erreur classique :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-smarty\">\n{* CORRECT — dans une boucle de sous-catégories *}\n{foreach from=$subcategories item=subcategory}\n    &lt;div class=\"subcategory-card\"&gt;\n        {* Image principale *}\n        &lt;img src=\"{$link-&gt;getCatImageLink($subcategory.link_rewrite, $subcategory.id_image, 'medium_default')|escape:'html':'UTF-8'}\" alt=\"{$subcategory.name|escape:'html':'UTF-8'}\" \u002F&gt;\n\n        {* Image secondaire *}\n        {if isset($subcategory.id_image2) && $subcategory.id_image2}\n            &lt;img src=\"{$link-&gt;getCatImageLink($subcategory.link_rewrite, $subcategory.id_image2, 'medium_default')|escape:'html':'UTF-8'}\" alt=\"\" \u002F&gt;\n        {\u002Fif}\n    &lt;\u002Fdiv&gt;\n{\u002Fforeach}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>PrestaShop 8.x (Twig) :\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>Sur les versions modernes, l'image peut être exposée via un module qui enrichit les variables de template :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-twig\">\n{# templates\u002Fcatalog\u002Flisting\u002Fcategory.html.twig #}\n{% if category.image2_url is defined and category.image2_url %}\n    &lt;div class=\"category-banner\"&gt;\n        &lt;img\n            src=\"{{ category.image2_url }}\"\n            alt=\"{{ category.name }}\"\n            loading=\"lazy\"\n            class=\"img-fluid\"\n        \u002F&gt;\n    &lt;\u002Fdiv&gt;\n{% endif %}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Étape 5 : Convention de nommage des fichiers image\u003C\u002Fh2>\n\u003Cp>Les images sont stockées dans \u003Ccode>\u002Fimg\u002Fc\u002F\u003C\u002Fcode> avec la convention suivante :\u003C\u002Fp>\n\u003Ctr>\u003Cth>Fichier\u003C\u002Fth>\u003Cth>Description\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`{id}-2.jpg`\u003C\u002Fth>\u003Cth>Image secondaire originale\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`{id}-2-category_default.jpg`\u003C\u002Fth>\u003Cth>Format catégorie par défaut\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`{id}-2-medium_default.jpg`\u003C\u002Fth>\u003Cth>Format moyen\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`{id}-2-small_default.jpg`\u003C\u002Fth>\u003Cth>Format miniature\u003C\u002Fth>\u003C\u002Ftr>\n\u003Cp>Par exemple, pour la catégorie 5 : \u003Ccode>5-2.jpg\u003C\u002Fcode>, \u003Ccode>5-2-category_default.jpg\u003C\u002Fcode>, etc.\u003C\u002Fp>\n\u003Ch2>Bonnes pratiques et pièges à éviter\u003C\u002Fh2>\n\u003Ch3>1. Toujours vider le cache des classes\u003C\u002Fh3>\n\u003Cp>L'erreur \u003Ccode>Call to undefined method\u003C\u002Fcode> après un override est quasi systématique lors du premier essai. Supprimez \u003Ccode>class_index.php\u003C\u002Fcode> dans tous les dossiers de cache.\u003C\u002Fp>\n\u003Ch3>2. Gestion robuste des uploads\u003C\u002Fh3>\n\u003Cp>Vérifiez toujours la validité du fichier uploadé (type MIME, taille, dimensions) avant traitement. Utilisez \u003Ccode>ImageManager::validateUpload()\u003C\u002Fcode> fourni par PrestaShop.\u003C\u002Fp>\n\u003Ch3>3. Privilégiez un module sur PrestaShop 8.x\u003C\u002Fh3>\n\u003Cp>Les overrides fonctionnent encore sur PS 8.x, mais la tendance est à leur suppression progressive. Pour un projet pérenne, encapsulez cette fonctionnalité dans un module dédié utilisant les hooks Symfony.\u003C\u002Fp>\n\u003Ch3>4. Ne confondez pas $category et $subcategory\u003C\u002Fh3>\n\u003Cp>Dans les templates Smarty, \u003Ccode>$category\u003C\u002Fcode> désigne la catégorie courante (la page consultée), tandis que \u003Ccode>$subcategory\u003C\u002Fcode> est l'itérateur dans un \u003Ccode>foreach\u003C\u002Fcode> sur les sous-catégories. Utiliser l'un à la place de l'autre affichera la mauvaise image — ou rien du tout.\u003C\u002Fp>\n\u003Ch3>5. Régénération des miniatures\u003C\u002Fh3>\n\u003Cp>Après avoir ajouté les images, pensez à régénérer les miniatures depuis \u003Cstrong>Préférences > Images\u003C\u002Fstrong> dans le back-office, ou via la ligne de commande :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">\n# PrestaShop 8.x\nphp bin\u002Fconsole prestashop:image:regenerate --type=categories\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Aller plus loin : image WebP et lazy loading\u003C\u002Fh2>\n\u003Cp>Sur PrestaShop 8.x, le support natif du format WebP est activable. Pour vos images secondaires, appliquez la même logique :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F Génération WebP en plus du JPEG\nif (function_exists('imagewebp')) {\n    ImageManager::resize(\n        $tmp_name,\n        $target_dir . $image_name . '-' . $image_type['name'] . '.webp',\n        (int)$image_type['width'],\n        (int)$image_type['height'],\n        'webp'\n    );\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Combinez avec l'élément \u003Ccode>\u003Cpicture>\u003C\u002Fcode> en front pour servir le format optimal :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-html\">\n&lt;picture&gt;\n    &lt;source srcset=\"\u002Fimg\u002Fc\u002F5-2-category_default.webp\" type=\"image\u002Fwebp\"&gt;\n    &lt;img src=\"\u002Fimg\u002Fc\u002F5-2-category_default.jpg\" alt=\"\" loading=\"lazy\"&gt;\n&lt;\u002Fpicture&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>",[40,43,46,49,52],{"q":41,"a":42},"Comment résoudre l'erreur « Call to undefined method Category::deleteImage2 » ?","Cette erreur signifie que PrestaShop utilise encore la classe Category en cache sans votre override. Supprimez le fichier class_index.php dans var\u002Fcache\u002Fdev\u002F et var\u002Fcache\u002Fprod\u002F (ou app\u002Fcache\u002F selon votre version). Videz ensuite le cache depuis le back-office. Vérifiez également que votre fichier d'override est bien placé dans override\u002Fclasses\u002FCategory.php et que la syntaxe PHP est correcte.",{"q":44,"a":45},"Faut-il utiliser un override ou un module pour ajouter un champ image aux catégories ?","Sur PrestaShop 1.6 et 1.7, un override de la classe Category est la méthode la plus directe. Sur PrestaShop 8.x, il est préférable de créer un module utilisant les hooks Symfony (actionCategoryFormBuilderModifier) car les overrides sont progressivement dépréciés. Un module offre aussi l'avantage d'être désactivable et portable entre boutiques.",{"q":47,"a":48},"Comment afficher la seconde image dans un thème personnalisé ?","Dans un thème Smarty (PS 1.6\u002F1.7), utilisez la variable {$category->id_image2} avec la méthode getCatImageLink du Link object. Veillez à bien distinguer $category (catégorie courante) et $subcategory (dans une boucle foreach). Sur PS 8.x avec Twig, exposez l'URL de l'image via un module hook et utilisez-la dans votre template avec la syntaxe {{ category.image2_url }}.",{"q":50,"a":51},"Pourquoi ma page devient blanche après la modification de Category.php ?","Une page blanche indique une erreur fatale PHP masquée. Activez le mode debug en définissant _PS_MODE_DEV_ à true dans config\u002Fdefines.inc.php (PS 1.6) ou dans le fichier .env avec APP_DEBUG=1 (PS 8.x). Une fois les erreurs affichées, les causes les plus fréquentes sont : une erreur de syntaxe dans l'override, un oubli de la colonne SQL id_image2, ou un fichier class_index.php obsolète.",{"q":53,"a":54},"Les miniatures de ma seconde image ne se génèrent pas, que faire ?","Assurez-vous que la méthode addImage2() appelle bien ImageManager::resize() pour chaque format défini dans ImageType::getImagesTypes('categories'). Vérifiez les permissions d'écriture du dossier \u002Fimg\u002Fc\u002F. Si les miniatures existaient mais ont disparu, relancez la régénération depuis Préférences > Images dans le back-office, ou en ligne de commande avec php bin\u002Fconsole prestashop:image:regenerate --type=categories sur PS 8.x.","Ajoutez un second champ image aux catégories PrestaShop via un override de la classe Category (PS 1.6\u002F1.7) ou un module Symfony (PS 8.x), en modifiant la base de données, le back-office et les templates front-end.",8,"2026-03-21T13:08:00.000Z",[],"PrestaShop pour les développeurs",{"items":61},[62,73,81,89,97,106,114,122],{"id":63,"type":64,"label":65,"href":67,"icon":68,"description":68,"badge":68,"groupTitle":68,"style":68,"gridColumns":68,"cssClass":68,"psCategoryId":68,"showPsChildren":69,"position":70,"children":71,"psChildren":72},41,"link",{"fr":66},"Expertise","\u002Fexpertise",null,false,0,[],[],{"id":74,"type":64,"label":75,"href":77,"icon":68,"description":68,"badge":68,"groupTitle":68,"style":68,"gridColumns":68,"cssClass":68,"psCategoryId":68,"showPsChildren":69,"position":78,"children":79,"psChildren":80},42,{"fr":76},"Blog","\u002Fblog",1,[],[],{"id":82,"type":64,"label":83,"href":85,"icon":68,"description":68,"badge":68,"groupTitle":68,"style":68,"gridColumns":68,"cssClass":68,"psCategoryId":68,"showPsChildren":69,"position":86,"children":87,"psChildren":88},43,{"fr":84},"Modules PrestaShop","\u002Fmodules",2,[],[],{"id":90,"type":64,"label":91,"href":93,"icon":68,"description":68,"badge":68,"groupTitle":68,"style":68,"gridColumns":68,"cssClass":68,"psCategoryId":68,"showPsChildren":69,"position":94,"children":95,"psChildren":96},44,{"fr":92},"Outils IA","\u002Foutils-ia",3,[],[],{"id":98,"type":64,"label":99,"href":101,"icon":68,"description":68,"badge":68,"groupTitle":68,"style":102,"gridColumns":68,"cssClass":68,"psCategoryId":68,"showPsChildren":69,"position":103,"children":104,"psChildren":105},45,{"fr":100},"Offre Starter ✨","\u002Foffre-starter",{"highlight":20},4,[],[],{"id":107,"type":64,"label":108,"href":110,"icon":68,"description":68,"badge":68,"groupTitle":68,"style":68,"gridColumns":68,"cssClass":68,"psCategoryId":68,"showPsChildren":69,"position":111,"children":112,"psChildren":113},46,{"fr":109},"Academy","\u002Facademy",5,[],[],{"id":115,"type":64,"label":116,"href":118,"icon":68,"description":68,"badge":68,"groupTitle":68,"style":68,"gridColumns":68,"cssClass":68,"psCategoryId":68,"showPsChildren":69,"position":119,"children":120,"psChildren":121},47,{"fr":117},"À propos","\u002Fa-propos",6,[],[],{"id":123,"type":64,"label":124,"href":126,"icon":68,"description":68,"badge":68,"groupTitle":68,"style":68,"gridColumns":68,"cssClass":68,"psCategoryId":68,"showPsChildren":69,"position":127,"children":128,"psChildren":129},48,{"fr":125},"Contact","\u002Fcontact",7,[],[],{"columns":131},[132,144,174,190],{"title":133,"links":134},"Plateforme",[135,137,140,141],{"label":136,"href":101,"external":69},"Offre Starter (2 500 €)",{"label":138,"href":139,"external":69},"Devenir Ambassadeur","\u002Fambassadeur",{"label":84,"href":85,"external":69},{"label":142,"href":143,"external":20},"CodeMyShop.com","https:\u002F\u002Fcodemyshop.com",{"title":145,"links":146},"Le Synedre",[147,150,153,156,159,162,165,168,171],{"label":148,"href":149,"external":69},"L'histoire","\u002Fsynedre",{"label":151,"href":152,"external":69},"Constitution","\u002Fsynedre\u002Fconstitution",{"label":154,"href":155,"external":69},"L'équipe","\u002Fequipe",{"label":157,"href":158,"external":69},"Le réacteur en direct","\u002Freacteur",{"label":160,"href":161,"external":69},"Le Drill (entraînement)","\u002Fdrill",{"label":163,"href":164,"external":69},"Protocole de réunion","\u002Fsynedre\u002Freunion",{"label":166,"href":167,"external":69},"Les agents IA","\u002Fagents-ia",{"label":169,"href":170,"external":69},"La Conduite","\u002Fsynedre\u002Fconduite",{"label":172,"href":173,"external":69},"Charte plateforme","\u002Fsynedre\u002Fcharte",{"title":175,"links":176},"Ressources",[177,178,179,182,184,187],{"label":76,"href":77,"external":69},{"label":109,"href":110,"external":69},{"label":180,"href":181,"external":69},"Dictionnaire","\u002Fdictionnaire",{"label":183,"href":67,"external":69},"Expertise PrestaShop",{"label":185,"href":186,"external":69},"Flywheel","\u002Fflywheel",{"label":188,"href":189,"external":69},"Manifeste","\u002Fmanifeste",{"title":117,"links":191},[192,194,197],{"label":193,"href":118,"external":69},"Alexandre Carette",{"label":195,"href":196,"external":69},"Dossier de presse","\u002Fpresse",{"label":125,"href":126,"external":69},{"header":199},{"logo":200,"topBar":205,"contactEmail":208,"features":209,"navBar":68},{"src":201,"alt":202,"text":193,"href":203,"class":204},"\u002Flogo-ac.svg","Alexandre Carette — Architecte E-commerce Souverain","\u002F","h-10 w-10",{"message":68,"showLanguages":69,"align":206,"languages":207},"left",[],"contact@alexandrecarette.fr",{"showSearch":69,"showWishlist":69,"showLogin":20,"showContact":69,"showCart":69,"stickyHeader":20,"headerLayout":210},"inline",{"academy":212,"blog":213,"expertise":224},[],[214,218,221],{"title":215,"url":216,"score":78,"type":217},"PrestaShop headless avec Nuxt 3 : pourquoi séparer back et front","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-separation-front-back","blog",{"title":219,"url":220,"score":78,"type":217},"PrestaShop headless : Nuxt 3, pas Next.js — le choix souverain","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-nextjs-souverainete",{"title":222,"url":223,"score":78,"type":217},"Sylius rachète PrestaShop : ce que ça change pour vous","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fsylius-rachat-prestashop-headless-souverainete",[],{"footer":226},{"theme":227,"description":68,"hours":68,"logo":228,"contact":229,"social":230,"bottomBar":240},"dark",{"src":201,"href":203,"alt":193},{"email":68,"phone":68,"address":68,"cta":68},[231,234,237],{"platform":232,"href":233,"label":232},"linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Falexandre-carette\u002F",{"platform":235,"href":236,"label":235},"malt","https:\u002F\u002Fwww.malt.fr\u002Fprofile\u002Falexandrecarette",{"platform":238,"href":239,"label":238},"github","https:\u002F\u002Fgithub.com\u002Fprest4cafe",{"copyright":68}]