Prestashop 1.7技术问询:如何在product.tpl中获取最低价配送商并展示
在PrestaShop 1.7商品详情页获取最低价配送商方案
嘿,针对你在PrestaShop 1.7的product.tpl里获取最低价配送商的需求,我给你梳理两种可行方案,优先推荐控制器预处理的方式(模板尽量少写业务逻辑是最佳实践哦):
方案一:通过ProductController预处理数据(推荐)
直接修改核心控制器不太友好,建议用override机制来扩展,这样升级PrestaShop时不会丢失你的修改:
- 在你的项目根目录下,创建
override/controllers/front/ProductController.php文件,写入以下代码:
<?php class ProductController extends ProductControllerCore { public function initContent() { parent::initContent(); // 获取当前商品对象 $product = $this->product; // 获取计算运费用的地址:已登录用户用默认地址,未登录用系统默认国家临时地址 if ($this->context->customer->isLogged()) { $address = new Address((int)$this->context->customer->id_address_default); } else { $address = new Address(); $address->id_country = (int)Configuration::get('PS_COUNTRY_DEFAULT'); $address->id_state = 0; $address->postcode = ''; } // 创建临时购物车并添加当前商品(用于计算运费) $cart = new Cart(); $cart->id_customer = (int)$this->context->customer->id; $cart->id_address_delivery = (int)$address->id; $cart->id_address_invoice = (int)$address->id; $cart->id_lang = (int)$this->context->language->id; $cart->id_currency = (int)$this->context->currency->id; $cart->id_shop = (int)$this->context->shop->id; $cart->add(); $cart->updateQty(1, $product->id); // 筛选可用配送商并找出最低价 $carriers = Carrier::getCarriers($this->context->language->id, true, false, false, null, Carrier::ALL_CARRIERS); $lowestCarrier = null; $lowestPrice = PHP_INT_MAX; foreach ($carriers as $carrier) { $carrierObj = new Carrier((int)$carrier['id_carrier']); // 检查配送商是否激活且支持当前地址所在区域 if ($carrierObj->active && $carrierObj->checkCarrierZone((int)$address->id_country)) { $shippingCost = $cart->getPackageShippingCost($carrierObj, $address, true); if ($shippingCost < $lowestPrice) { $lowestPrice = $shippingCost; $lowestCarrier = $carrierObj; } } } // 清理临时购物车,避免产生无效记录 $cart->delete(); // 将数据传递给模板 $this->context->smarty->assign([ 'lowest_carrier' => $lowestCarrier, 'lowest_shipping_price' => $lowestPrice ]); } }
登录后台,进入高级参数 > 性能页面,点击"清除缓存",让override生效。
在你的主题
product.tpl中添加展示代码:
{if $lowest_carrier} <div class="product-shipping-info"> <p>💡 最低价配送:<strong>{$lowest_carrier->name}</strong> - 运费:{$lowest_shipping_price|convertPrice}</p> </div> {else} <p>⚠️ 当前商品暂无可用配送方式</p> {/if}
方案二:直接在模板中编写逻辑(应急可用,不推荐)
如果暂时不想修改控制器,也可以直接在product.tpl中写逻辑,但后期维护会比较麻烦:
{* 获取当前商品 *} {assign var="current_product" value=$product} {* 获取地址:已登录用默认地址,未登录用系统默认国家 *} {assign var="shipping_address" value=""} {if $customer->isLogged()} {assign var="shipping_address" value=new Address($customer->id_address_default)} {else} {assign var="shipping_address" value=new Address()} {$shipping_address->id_country = Configuration::get('PS_COUNTRY_DEFAULT')} {$shipping_address->id_state = 0} {$shipping_address->postcode = ''} {/if} {* 创建临时购物车 *} {assign var="temp_cart" value=new Cart()} {$temp_cart->id_customer = $customer->id} {$temp_cart->id_address_delivery = $shipping_address->id} {$temp_cart->id_address_invoice = $shipping_address->id} {$temp_cart->id_lang = $language->id} {$temp_cart->id_currency = $currency->id} {$temp_cart->id_shop = $shop->id} {$temp_cart->add()} {$temp_cart->updateQty(1, $current_product->id)} {* 遍历配送商找最低价 *} {assign var="min_shipping_price" value=99999} {assign var="best_carrier" value=null} {foreach from=Carrier::getCarriers($language->id, true, false, false, null, Carrier::ALL_CARRIERS) item=carrier_item} {assign var="carrier_obj" value=new Carrier($carrier_item.id_carrier)} {if $carrier_obj->active && $carrier_obj->checkCarrierZone($shipping_address->id_country)} {assign var="cost" value=$temp_cart->getPackageShippingCost($carrier_obj, $shipping_address, true)} {if $cost < $min_shipping_price} {assign var="min_shipping_price" value=$cost} {assign var="best_carrier" value=$carrier_obj} {/if} {/if} {/foreach} {* 清理临时购物车 *} {$temp_cart->delete()} {* 展示结果 *} {if $best_carrier} <div class="shipping-notice"> <p>最低价配送选项:<strong>{$best_carrier->name}</strong>,运费:{$min_shipping_price|convertPrice}</p> </div> {else} <p>暂无可用配送方式</p> {/if}
重要注意事项
- 地址适配:未登录用户的临时地址可以根据你的业务调整(比如默认热门国家/地区),不然运费计算可能不符合实际场景。
- 配送商限制:如果你的配送商有重量、体积限制,需要额外添加检查逻辑(比如
$carrierObj->checkWeight($product->weight))。 - 免运费处理:如果有免运费的配送商,代码会自动识别(因为0是最小的价格),符合预期。
- 缓存问题:修改override后一定要清缓存,否则不会生效。
内容的提问来源于stack exchange,提问作者user8772487
相关产品推荐
相关产品推荐

