You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Magento自定义.phtml文件中带自定义与配置选项的产品表单使用方法及显示异常排查

问题描述

我在Magento主题中尝试通过SKU循环展示2个关联产品,集成代码后产品能正常显示,加入购物车功能也没问题,但产品的自定义选项和配置选项完全不显示。想请教各位我遗漏了哪些关键步骤?同时也想了解如何在自定义.phtml文件中正确渲染带有自定义选项和配置选项的产品表单。

我的实现步骤如下:

1. 修改form.phtml文件

在主题目录theme/Magento_Catalog/templates/view/下的form.phtml中添加了以下代码:

<?php 
$_complete_set_attributeValue = $_product->getResource()->getAttribute('complete_set_sku')->getFrontend()->getValue($_product); 
// print_r($_complete_set_attributeValue); 
if ($_complete_set_attributeValue) { 
    echo $this->getLayout()->createBlock("Magento\Framework\View\Element\Template")
              ->setTemplate("Magento_Catalog::product/popup_comeplete_set_product.phtml")
              ->toHtml(); 
} 
?>

2. 创建自定义模板popup_comeplete_set_product.phtml

在主题目录theme/Magento_Catalog/templates/product/下创建了该文件,代码如下:

<?php
$objectManager = \Magento\Framework\App\ObjectManager::getInstance(); 
$helperImport = $objectManager->get('\Magento\Catalog\Helper\Image'); 
$cartHelper = $objectManager->get('\Magento\Catalog\Block\Product\ListProduct'); 
$_helper = $this->helper('Magento\Catalog\Helper\Output'); 
$postDataHelper = $this->helper('Magento\Framework\Data\Helper\PostHelper'); 
$productTypeInstance = $objectManager->get('Magento\ConfigurableProduct\Model\Product\Type\Configurable'); 
$typeInstance = $objectManager->get('Magento\GroupedProduct\Model\Product\Type\Grouped'); 
// $typeInstance = $objectManager->get('Magento\Bundle\Model\Product\Type'); 
$collection = $objectManager->get('Magento\Catalog\Model\Product') 
    ->getCollection() 
    ->addAttributeToSelect('*') 
    ->addAttributeToFilter('sku',array('BAB','PRI')); 
$total_product_count = $collection->count(); 
?>
<div class="popup-complete-set-block product-add-form <?= $block->escapeHtml($product->getSku()) ?>"> 
<form style="width: 100%;display: flex;" data-product-sku="<?= $block->escapeHtml($product->getSku()) ?>" action="<?= $addToCartUrl; ?>" method="post" id="product_addtocart_form"<?php if ($product->getOptions()): ?> enctype="multipart/form-data"<?php endif; ?>> 
<input type="hidden" name="product" value="<?= /* @escapeNotVerified */ $product->getId() ?>" /> 
<input type="hidden" name="selected_configurable_option" value="" /> 
<input type="hidden" name="related_product" id="related-products-field" value="" /> 
<?= $block->getBlockHtml('formkey') ?> 
<?= $block->getChildHtml('form_top') ?> 
<?php if (!$block->hasOptions()):?> 
<?= $block->getChildHtml('product_info_form_content') ?> 
<?php else:?> 
<?php if ($product->isSaleable() && $block->getOptionsContainer() == 'container1'):?> 
<?= $block->getChildChildHtml('options_container') ?> 
<?php endif;?> 
<?php endif; ?> 
<?php if ($product->isSaleable() && $block->hasOptions() && $block->getOptionsContainer() == 'container2'):?> 
<?= $block->getChildChildHtml('options_container') ?> 
<?php endif;?> 
<?= $block->getChildHtml('form_bottom') ?> 
<div class="popup-complete-set-image"> 
<img src="<?php echo $resizedImageUrl; ?>" alt="<?php echo $product->getName() ?>" /> 
</div> 
<div class="popup-complete-set-detail"> 
<p class="slide-number"><?php echo $counter++;?> / <?php echo $total_product_count;?></p> 
<h3 class="slide-title"><a href="<?php echo $product->getProductUrl() ?>"><?php echo $product->getName() ?></a></h3> 
<p class="slide-price"> 
<?php echo $block->getProductPrice($product);?> 
</p> 
<?php if ($product->isSaleable()): ?> 
<div class="box-tocart"> 
<div class="fieldset"> 
<?php //if ($block->shouldRenderQuantity()): ?> 
<div class="field qty"> 
<label class="label" for="qty"><span><?= /* @escapeNotVerified */ __('Qty') ?></span></label> 
<div class="control"> 
<div class="sp-quantity"> 
<div class="sp-minus fff"> 
<a class="ddd" href="#">-</a></div> 
<div class="sp-input"> 
<input type="number" name="qty" id="qty" value="<?= /* @escapeNotVerified */ $block->getProductDefaultQty() * 1 ?>" title="<?= /* @escapeNotVerified */ __('Qty') ?>" class="input-text qty quntity-input" style="border: 0px solid #dfdfdf !important;border-radius: 0 !important;height: 43px;" data-validate="<?= $block->escapeHtml(json_encode($block->getQuantityValidators())) ?>" /> 
</div> 
<div class="sp-plus fff"> 
<a class="ddd" href="#">+</a></div> 
</div> 
</div> 
</div> 
<?php //endif; ?> 
<div class="actions"> 
<button type="submit" title="<?= /* @escapeNotVerified */ $buttonTitle ?>" class="action primary tocart product-form-cart" id="product-addtocart-button"> 
<span><?= /* @escapeNotVerified */ $buttonTitle ?></span> 
<svg fill="#fff" height="20" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1171 960q0 13-10 23l-466 466q-10 10-23 10t-23-10l-50-50q-10-10-10-23t10-23l393-393-393-393q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l466 466q10 10 10 23z"></path></svg> 
</button> 
<?= $block->getChildHtml('', true) ?> 
</div> 
</div> 
</div> 
<?php else : ?> 
<?php if ($product->getIsSalable()) : ?> 
<div class="stock available"><span><?php /* @escapeNotVerified */ echo __('In stock') ?></span></div> 
<?php else : ?> 
<div class="stock unavailable"><span><?php /* @escapeNotVerified */ echo __('Out of stock') ?></span></div> 
<?php endif; ?> 
<?php endif; ?> 
</div> 
</form> 
</div>

问题原因分析

你的代码里有几个核心问题导致选项不显示:

  1. 未正确传递产品对象到自定义块:你在form.phtml里创建的是通用Template块,没有把查询到的关联产品传递给这个块,导致模板里的$product变量上下文不对,无法正确加载产品选项。
  2. 缺少选项渲染的子块:Magento的产品自定义选项、配置选项是通过专门的子块(比如Magento_Catalog::product/view/options.phtml、Magento_ConfigurableProduct::product/view/type/options/configurable.phtml)来渲染的,你的自定义块没有加载这些子块,所以getChildChildHtml('options_container')根本找不到内容。
  3. 直接使用ObjectManager不规范:虽然能拿到产品集合,但没有按照Magento的标准流程初始化产品块的依赖,导致产品的选项数据没有被正确加载和准备。
  4. 变量未定义:模板里的$addToCartUrl、$resizedImageUrl、$buttonTitle、$counter这些变量都没有定义,不仅会导致功能异常,也会影响选项渲染的逻辑。

解决方案

下面给你两种可行的修改方案,推荐第一种更符合Magento规范的方法:

方案一:使用Magento自带的产品表单块渲染

Magento自带的Magento\Catalog\Block\Product\View\Form块已经封装了所有选项渲染的逻辑,我们可以直接复用它:

1. 修改form.phtml中的代码

<?php 
$_complete_set_attributeValue = $_product->getResource()->getAttribute('complete_set_sku')->getFrontend()->getValue($_product); 
if ($_complete_set_attributeValue) { 
    // 先获取关联产品SKU列表,这里假设你的属性值是逗号分隔的SKU
    $relatedSkus = explode(',', $_complete_set_attributeValue);
    // 获取产品集合
    $productCollection = $this->getLayout()->createBlock('Magento\Catalog\Block\Product\ListProduct')
                              ->getProductCollection()
                              ->addAttributeToSelect('*')
                              ->addAttributeToFilter('sku', ['in' => $relatedSkus]);
    // 循环每个产品,创建表单块
    $counter = 1;
    $total_product_count = $productCollection->count();
    foreach ($productCollection as $relatedProduct) {
        echo $this->getLayout()->createBlock('Magento\Catalog\Block\Product\View\Form')
                  ->setProduct($relatedProduct)
                  ->setData('counter', $counter++)
                  ->setData('total_count', $total_product_count)
                  ->setTemplate('Magento_Catalog::product/popup_complete_set_product.phtml')
                  ->toHtml();
    }
} 
?>

2. 修改popup_complete_set_product.phtml模板

现在模板可以直接使用$block(即Product\View\Form块)的所有方法,包括选项渲染:

<?php
$_product = $block->getProduct();
$buttonTitle = __('Add to Cart');
// 处理图片
$resizedImageUrl = $block->getImage($_product, 'product_page_image_small')->getUrl();
$counter = $block->getData('counter');
$total_product_count = $block->getData('total_count');
?>
<div class="popup-complete-set-block product-add-form <?= $block->escapeHtml($_product->getSku()) ?>"> 
    <form data-product-sku="<?= $block->escapeHtml($_product->getSku()) ?>" 
          action="<?= $block->getSubmitUrl($_product) ?>" 
          method="post" 
          id="product_addtocart_form_<?= $_product->getId() ?>"
          <?php if ($_product->getOptions()): ?> enctype="multipart/form-data"<?php endif; ?>> 
        <input type="hidden" name="product" value="<?= /* @escapeNotVerified */ $_product->getId() ?>" /> 
        <input type="hidden" name="selected_configurable_option" value="" /> 
        <input type="hidden" name="related_product" id="related-products-field-<?= $_product->getId() ?>" value="" /> 
        <?= $block->getBlockHtml('formkey') ?> 
        <?= $block->getChildHtml('form_top') ?> 

        <?php if (!$block->hasOptions()):?> 
            <?= $block->getChildHtml('product_info_form_content') ?> 
        <?php else:?> 
            <?php if ($_product->isSaleable() && $block->getOptionsContainer() == 'container1'):?> 
                <?= $block->getChildChildHtml('options_container') ?> 
            <?php endif;?> 
        <?php endif; ?> 

        <?php if ($_product->isSaleable() && $block->hasOptions() && $block->getOptionsContainer() == 'container2'):?> 
            <?= $block->getChildChildHtml('options_container') ?> 
        <?php endif;?> 

        <?= $block->getChildHtml('form_bottom') ?> 

        <div class="popup-complete-set-image"> 
            <img src="<?= $resizedImageUrl; ?>" alt="<?= $block->escapeHtml($_product->getName()) ?>" /> 
        </div> 

        <div class="popup-complete-set-detail"> 
            <p class="slide-number"><?= $counter;?> / <?= $total_product_count;?></p> 
            <h3 class="slide-title"><a href="<?= $_product->getProductUrl() ?>"><?= $block->escapeHtml($_product->getName()) ?></a></h3> 
            <p class="slide-price"> 
                <?= $block->getProductPrice($_product);?> 
            </p> 

            <?php if ($_product->isSaleable()): ?> 
                <div class="box-tocart"> 
                    <div class="fieldset"> 
                        <div class="field qty"> 
                            <label class="label" for="qty_<?= $_product->getId() ?>"><span><?= /* @escapeNotVerified */ __('Qty') ?></span></label> 
                            <div class="control"> 
                                <div class="sp-quantity"> 
                                    <div class="sp-minus fff"> 
                                        <a class="ddd" href="#">-</a></div> 
                                    <div class="sp-input"> 
                                        <input type="number" name="qty" id="qty_<?= $_product->getId() ?>" 
                                               value="<?= /* @escapeNotVerified */ $block->getProductDefaultQty() * 1 ?>" 
                                               title="<?= /* @escapeNotVerified */ __('Qty') ?>" 
                                               class="input-text qty quntity-input" 
                                               style="border: 0px solid #dfdfdf !important;border-radius: 0 !important;height: 43px;" 
                                               data-validate="<?= $block->escapeHtml(json_encode($block->getQuantityValidators())) ?>" /> 
                                    </div> 
                                    <div class="sp-plus fff"> 
                                        <a class="ddd" href="#">+</a></div> 
                                </div> 
                            </div> 
                        </div> 

                        <div class="actions"> 
                            <button type="submit" title="<?= /* @escapeNotVerified */ $buttonTitle ?>" class="action primary tocart product-form-cart" id="product-addtocart-button-<?= $_product->getId() ?>"> 
                                <span><?= /* @escapeNotVerified */ $buttonTitle ?></span> 
                                <svg fill="#fff" height="20" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1171 960q0 13-10 23l-466 466q-10 10-23 10t-23-10l-50-50q-10-10-10-23t10-23l393-393-393-393q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l466 466q10 10 10 23z"></path></svg> 
                            </button> 
                            <?= $block->getChildHtml('', true) ?> 
                        </div> 
                    </div> 
                </div> 
            <?php else : ?> 
                <?php if ($_product->getIsSalable()) : ?> 
                    <div class="stock available"><span><?php /* @escapeNotVerified */ echo __('In stock') ?></span></div> 
                <?php else : ?> 
                    <div class="stock unavailable"><span><?php /* @escapeNotVerified */ echo __('Out of stock') ?></span></div> 
                <?php endif; ?> 
            <?php endif; ?> 
        </div> 
    </form> 
</div>

方案二:手动加载选项子块(适合自定义程度高的场景)

如果你需要完全自定义表单结构,可以手动在自定义块中添加选项子块:

1. 在form.phtml中传递产品并添加子块

<?php 
$_complete_set_attributeValue = $_product->getResource()->getAttribute('complete_set_sku')->getFrontend()->getValue($_product); 
if ($_complete_set_attributeValue) { 
    $relatedSkus = explode(',', $_complete_set_attributeValue);
    $productCollection = $this->getLayout()->createBlock('Magento\Catalog\Block\Product\ListProduct')
                              ->getProductCollection()
                              ->addAttributeToSelect('*')
                              ->addAttributeToFilter('sku', ['in' => $relatedSkus]);
    $counter = 1;
    $total_product_count = $productCollection->count();
    foreach ($productCollection as $relatedProduct) {
        // 创建自定义块
        $customBlock = $this->getLayout()->createBlock("Magento\Framework\View\Element\Template")
                            ->setTemplate("Magento_Catalog::product/popup_complete_set_product.phtml")
                            ->setProduct($relatedProduct)
                            ->setData('counter', $counter++)
                            ->setData('total_count', $total_product_count);
        // 添加自定义选项子块
        $customBlock->setChild('options', 
            $this->getLayout()->createBlock('Magento\Catalog\Block\Product\View\Options')
                 ->setProduct($relatedProduct)
                 ->set
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 23:47:30