Corriger l'erreur « id_shop n'est pas valide » en multi-boutique PrestaShop
Guide complet pour résoudre l'erreur id_shop invalide en multi-boutique PrestaShop. Diagnostic, création des tables _shop manquantes et correction du modèle ObjectModel.
En bref : L'erreur « id_shop n'est pas valide » survient quand un module PrestaShop ne possède pas de table _shop associative ni la déclaration multishop dans son ObjectModel. La correction implique de créer la table manquante, d'ajouter id_shop dans les tables existantes, et de mettre à jour la définition du modèle PHP.
Le problème : un module incompatible multi-boutique
Vous activez le mode multi-boutique de PrestaShop, vous basculez sur un contexte boutique spécifique, et là : « id_shop n'est pas valide ». L'erreur survient systématiquement lorsqu'un module tiers tente d'enregistrer ou de lire des données sans gérer correctement l'association aux boutiques.
Le coupable est presque toujours le même : le développeur du module n'a pas prévu la compatibilité multi-boutique dans sa structure de base de données ni dans son modèle ObjectModel.
Comprendre l'architecture multi-boutique de PrestaShop
PrestaShop repose sur un mécanisme de tables associatives pour isoler les données par boutique. Pour chaque entité compatible multi-boutique, on retrouve généralement trois tables :
Quand la table _shop est absente, PrestaShop ne peut pas associer l'enregistrement à une boutique. L'ObjectModel lève alors l'erreur id_shop n'est pas valide lors de l'appel à add() ou save().
Diagnostic étape par étape
1. Identifier les tables du module
Ouvrez phpMyAdmin et listez les tables du module concerné :
SHOW TABLES LIKE '%navcmsblock%';
Vous devriez obtenir quelque chose comme :
ps_tmnavcmsblockinfo
ps_tmnavcmsblockinfo_lang
Si vous ne voyez pas de table ps_tmnavcmsblockinfo_shop, c'est la cause du problème.
2. Vérifier la colonne id_shop dans la table principale
Inspectez la structure de la table principale :
DESCRIBE ps_tmnavcmsblockinfo;
Si la colonne id_shop est absente ou mal typée, l'ObjectModel ne peut pas filtrer par boutique.
3. Vérifier le modèle ObjectModel du module
Ouvrez le fichier PHP de la classe du modèle (souvent classes/NavCmsBlock.php ou équivalent) et cherchez la propriété $definition. Un modèle correctement configuré pour le multi-boutique doit contenir :
public static $definition = array(
'table' => 'tmnavcmsblockinfo',
'primary' => 'id_tmnavcmsblockinfo',
'multilang' => true,
'multishop' => true, // <-- Souvent absent dans les modules mal codés
'fields' => array(
'id_shop' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
// ... autres champs
),
);
L'absence de 'multishop' => true ou de la déclaration du champ id_shop est un indicateur fiable du problème.
Correction complète
Étape 1 : Créer la table `_shop` manquante
Exécutez cette requête SQL via phpMyAdmin (onglet SQL) :
CREATE TABLE IF NOT EXISTS `ps_tmnavcmsblockinfo_shop` (
`id_tmnavcmsblockinfo` INT UNSIGNED NOT NULL,
`id_shop` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id_tmnavcmsblockinfo`, `id_shop`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Note PrestaShop 8.x : Utilisez
utf8mb4au lieu deutf8etInnoDBau lieu de la variable_MYSQL_ENGINE_si vous exécutez la requête manuellement. En PHP, conservez_MYSQL_ENGINE_pour la portabilité.
Étape 2 : Ajouter id_shop dans la table _lang si nécessaire
Certains modules nécessitent aussi l'association boutique dans la table des traductions :
ALTER TABLE `ps_tmnavcmsblockinfo_lang`
ADD COLUMN `id_shop` INT(10) UNSIGNED NOT NULL DEFAULT 1
AFTER `id_tmnavcmsblockinfo`;
Étape 3 : Peupler les associations existantes
Si des données existent déjà en base, associez-les à votre boutique par défaut :
INSERT INTO `ps_tmnavcmsblockinfo_shop` (`id_tmnavcmsblockinfo`, `id_shop`)
SELECT `id_tmnavcmsblockinfo`, 1
FROM `ps_tmnavcmsblockinfo`
WHERE `id_tmnavcmsblockinfo` NOT IN (
SELECT `id_tmnavcmsblockinfo` FROM `ps_tmnavcmsblockinfo_shop`
);
Étape 4 : Corriger le modèle ObjectModel
Modifiez la classe PHP du modèle pour déclarer la compatibilité multi-boutique :
class NavCmsBlock extends ObjectModel
{
public $id_tmnavcmsblockinfo;
public $id_shop;
// ... autres propriétés
public static $definition = array(
'table' => 'tmnavcmsblockinfo',
'primary' => 'id_tmnavcmsblockinfo',
'multilang' => true,
'multishop' => true,
'fields' => array(
'id_shop' => array(
'type' => self::TYPE_INT,
'validate' => 'isUnsignedId',
'shop' => true,
),
// ... autres champs existants
),
);
}
Étape 5 : Corriger la méthode installDB() du module
Pour que le module crée correctement ses tables lors d'une future installation, modifiez la méthode installDB() :
public function installDB()
{
$return = true;
// Table principale
$return &= Db::getInstance()->execute('
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'tmnavcmsblockinfo` (
`id_tmnavcmsblockinfo` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`id_shop` INT(10) UNSIGNED DEFAULT NULL,
PRIMARY KEY (`id_tmnavcmsblockinfo`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8mb4;
');
// Table multi-boutique
$return &= Db::getInstance()->execute('
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'tmnavcmsblockinfo_shop` (
`id_tmnavcmsblockinfo` INT UNSIGNED NOT NULL,
`id_shop` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id_tmnavcmsblockinfo`, `id_shop`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8mb4;
');
// Table traductions
$return &= Db::getInstance()->execute('
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'tmnavcmsblockinfo_lang` (
`id_tmnavcmsblockinfo` INT UNSIGNED NOT NULL,
`id_shop` INT(10) UNSIGNED NOT NULL DEFAULT 1,
`id_lang` INT(10) UNSIGNED NOT NULL,
`title` VARCHAR(255) DEFAULT NULL,
`content` TEXT DEFAULT NULL,
PRIMARY KEY (`id_tmnavcmsblockinfo`, `id_shop`, `id_lang`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8mb4;
');
return $return;
}
Le piège du typage : id_shop en string
Un problème subtil mais fréquent : PrestaShop peut retourner id_shop sous forme de string au lieu d'un entier. Si le module effectue une comparaison stricte (===), la validation échoue silencieusement.
Le diagnostic :
$id_shop = (int) Shop::getContextShopID();
// ou
$id_shop = (int) Context::getContext()->shop->id;
Castez toujours id_shop en int avant de l'utiliser dans vos requêtes ou comparaisons.
Vérification rapide avec Shop::getShops()
Pour confirmer que PrestaShop détecte bien vos boutiques, utilisez ce snippet de debug temporaire :
$shops = Shop::getShops();
error_log(print_r($shops, true));
Vous devriez obtenir un tableau associatif contenant au minimum une entrée avec id_shop, name, et active. Si ce tableau est vide, le problème est plus profond : vérifiez la table ps_shop et la configuration multi-boutique dans les paramètres généraux.
Bonnes pratiques pour les développeurs de modules
Checklist multi-boutique
- **Table `_shop` obligatoire** pour toute entité ObjectModel
- **Propriété `multishop => true`** dans `$definition`
- **Colonne `id_shop`** dans la table principale ET la table `_lang` si applicable
- **Clé primaire composite** `(id_entite, id_shop)` dans la table `_shop`
- **Cast en int** systématique de `id_shop` dans les requêtes
- **Hook `actionShopDataDuplication`** pour dupliquer les données lors de la création d'une nouvelle boutique
PrestaShop 8.x : ce qui change
Depuis PrestaShop 8, le ObjectModel valide plus strictement les associations multi-boutique. Un module qui fonctionnait "par chance" en 1.6 ou 1.7 sans table _shop échouera quasi-systématiquement en 8.x. Si vous migrez, auditez toutes les classes ObjectModel de vos modules tiers avec :
grep -rn "multishop" modules/tm_*/classes/
Tout module sans multishop => true dans ses définitions est un candidat au bug.
Questions fréquentes
Tout ce que vous devez savoir sur ce sujet.
Un projet PrestaShop ?
Discutons-en directement.
193 projets livrés
Lire sur le blog

Alexandre Carette
Expert PrestaShop & Architecture E-commerce
Développeur PrestaShop depuis 2014, 193 projets livrés. Je conçois des architectures headless Nuxt + PrestaShop et des outils d'automatisation IA pour les e-commerçants.