PrestaShop模块displayProductPriceBlock钩子重复触发问题
PrestaShop模块钩子重复触发导致价格多次折扣问题修复
问题描述
开发了名为HalvePriceOutOfStock的PrestaShop模块,通过displayProductPriceBlock钩子为缺货商品价格减2。测试发现钩子被触发两次,原本22元的商品价格变成16元(被连续减了两次2)。尝试用全局标记变量控制执行次数,却导致其他商品无法正常触发钩子。
问题根源
displayProductPriceBlock钩子在PrestaShop中可能被多次调用(例如商品列表、商品详情页的不同价格区块,或原价/折扣价的渲染场景)- 直接修改
$params['product']['price']会导致后续钩子调用基于已修改的价格重复计算 - 通过解析格式化后的价格字符串来计算折扣,容易出现格式兼容问题,且依赖不稳定的字符串处理
修复方案
核心思路
- 限制钩子仅在主价格区块触发,跳过无关价格场景
- 按商品ID标记处理状态,确保每个商品只被修改一次
- 直接调用PrestaShop原生API获取原始价格,替代字符串解析逻辑
修改后的完整代码
<?php if (!defined('_PS_VERSION_')) { exit; } class HalvePriceOutOfStock extends Module { public function __construct() { $this->name = 'halvepriceoutofstock'; $this->tab = 'pricing_promotion'; $this->version = '0.1.0'; $this->author = 'Ali Fertah'; $this->need_instance = 0; parent::__construct(); $this->displayName = $this->l('Halve Price for Out-of-Stock Products'); $this->description = $this->l('Displays out-of-stock products with half the original price.'); $this->ps_versions_compliancy = array('min' => '1.7', 'max' => _PS_VERSION_); } public function install() { return parent::install() && $this->registerHook('displayProductPriceBlock'); } public function uninstall() { return parent::uninstall(); } public function hookDisplayProductPriceBlock($params) { // 仅处理主价格区块,跳过原价、促销价等其他价格渲染场景 if ($params['type'] !== 'price') { return; } $productId = $params['product']['id_product']; // 按商品ID标记已处理状态,避免同个商品被重复折扣 if (!isset($this->context->processed_products[$productId])) { $params['product']['price'] = $this->updateProductPrice($productId); $this->context->processed_products[$productId] = true; } $this->context->smarty->assign(array( 'product_price' => $params['product']['price'] )); } public function updateProductPrice($productId) { $product = new Product($productId); if ($product->quantity <= 0) { // 获取商品原始含税价格(改为getPrice(false, ...)可获取不含税价格) $originalPrice = (float)$product->getPrice(true, null, 6); $discountedPrice = $originalPrice - 2; // 用PrestaShop原生工具格式化价格,适配当前货币和本地化设置 return $this->context->currency->format($discountedPrice, $this->context->currency->id, false); } else { // 返回商品原价格 return $this->context->currency->format($product->getPrice(true, null, 6), $this->context->currency->id, false); } } }
关键修改说明
- 增加
type参数判断,过滤掉非主价格的钩子调用 - 基于商品ID的状态标记,确保每个商品仅被折扣一次
- 直接通过Product对象获取原始价格,避免字符串解析的兼容性问题
- 使用PrestaShop原生价格格式化方法,适配不同货币和地区的格式要求
内容的提问来源于stack exchange,提问作者scofio
相关产品推荐
相关产品推荐

