12

我正在为页脚构建一个“本月产品”块。它应该加载一个类别的产品并显示第一个。

这是我的模板文件custom/featured-product.phtml

<?php $_productCollection = $this->getLoadedProductCollection() ?>

<div class="featured-product">
    <h2><?php echo $this->__('Product of the Month') ?></h2>

    <?php foreach ($_productCollection as $_product): ?>
        <div class="item">
            <a class="product-image" href="<?php echo $_product->getProductUrl() ?>">
                <img src="<?php echo $this->helper('catalog/image')->init($_product, 'small_image')->resize(200); ?>" alt="<?php echo $this->htmlEscape($this->getImageLabel($_product, 'small_image')) ?>" />
            </a>

            <a class="product-name" href="<?php echo $_product->getProductUrl() ?>"><?php echo $this->htmlEscape($_product->getName()) ?></a>

            <?php echo $this->getPriceHtml($_product, true) ?>
        </div>

        <?php
        // Note: Exit after first product.
        break;
        ?>
    <?php endforeach ?>
</div>

它只是 Magento 产品列表模板的简化版本:catalog/product/list.phtml


在职的

在 CMS 页面中嵌入块时,它可以正常工作。例子:

{{block type="catalog/product_list" category_id="13" template="custom/featured-product.phtml" }}


不工作

通过 嵌入块时local.xml,它会失败。返回正确的标记,但未加载指定的类别。而是加载了一组随机(我不知道它们是如何选择的)产品。

我的代码local.xml

<default>
    <reference name="footer">
        <block type="catalog/product_list" name="custom.featuredProduct" as="product_of_the_month" category_id="13" template="custom/featured-product.phtml" />
    </reference>
</default>

为了完整起见,我page/html/footer.phtml像这样显式地渲染块:

<?php echo $this->getChildHtml('product_of_the_month') ?>


有任何想法吗?

我最好的猜测是我local.xml的不正确。我需要加载父块吗?


[更新]

我的原始代码使产品页面崩溃。解决方法不是将代码如此依赖于 Magento 核心文件:catalog/product/list.phtml. 特别避免这一行:

<?php $_productCollection = $this->getLoadedProductCollection() ?>


[解决方案]

此处包含带有用于 CMS 页面和 LayoutXML 示例的工作版本: https ://stackoverflow.com/a/12288000/1497746

4

3 回答 3

12

使用 Alan Storm 的建议找到了一个可行的解决方案。

/template/custom/featured-product.phtml

<?php
$_categoryId = $this->getCategoryId();

$_productCollection = Mage::getModel('catalog/category')->load($_categoryId)
    ->getProductCollection()
    ->addAttributeToSelect('*')
    ->addAttributeToFilter('status', 1)
    ->addAttributeToFilter('visibility', 4)
    ->setOrder('price', 'ASC');
?>

<div class="featured-product">
    <h2><?php echo $this->__( $this->getLabel() ); ?></h2>

    <?php foreach ($_productCollection as $_product): ?>
        <div class="item">
            <a class="product-image" href="<?php echo $_product->getProductUrl() ?>">
                <img src="<?php echo $this->helper('catalog/image')->init($_product, 'small_image')->resize(200); ?>" alt="<?php echo $this->htmlEscape($this->getImageLabel($_product, 'small_image')) ?>" />
            </a>

            <a class="product-name" href="<?php echo $_product->getProductUrl() ?>"><?php echo $this->htmlEscape($_product->getName()) ?></a>

            <?php echo $this->getPriceHtml($_product, true) ?>
        </div>

        <?php
        // Note: Exit after first product.
        break;
        ?>
    <?php endforeach ?>
</div>

简而言之,集合是手动生成的,而不是接收集合(就像我最初的尝试那样):

<?php $_productCollection = $this->getLoadedProductCollection() ?>
<?php $_collectionSize = $_productCollection->count(); ?>


在 CMS 页面中使用:

{{block type="core/template" category_id="13" label="Product of the Month" template="custom/featured-product.phtml" }}


在模板中使用:

/layout/local.xml

<default>
    <reference name="footer">
        <block type="core/template" name="custom.featuredProduct" as="featured_product" template="custom/featured-product.phtml">
            <action method="setData"><key>category_id</key><value>13</value></action>
            <action method="setData"><key>label</key><value>Product of the Month</value></action>
        </block>
    </reference>
</default>

/template/page/html/footer.phtml

<?php echo $this->getChildHtml('featured_product') ?>


有用的资源:

如何获得产品集合:

使用魔法 getter/setter:

于 2012-09-05T18:58:06.627 回答
5

首先,多年来我遇到了随机问题,使用布局更新 xml 属性节点来设置块上的值(除了template, as, name, type, or之外class,所以尝试这样的事情

<default>
    <reference name="footer">
        <block type="catalog/product_list" name="custom.featuredProduct" as="product_of_the_month" template="custom/featured-product.phtml">
            <action method="setCategoryId"><id>13</id></action>
        </block>
    </reference>
</default>

或这个

<default>
    <reference name="footer">
        <block type="catalog/product_list" name="custom.featuredProduct" as="product_of_the_month" template="custom/featured-product.phtml">
            <action method="setData"><key>category_id</key><value>13</value></action>
        </block>
    </reference>
</default>

可能会有所帮助,这将是我的第一步。

之后,我会查看加载集合的代码块

#File: app/code/core/Mage/Catalog/Block/Product/List.php
class Mage_Catalog_Block_Product_List extends Mage_Catalog_Block_Product_Abstract
{
    ...
    public function getLoadedProductCollection()
    {
        return $this->_getProductCollection();
    }        
    ...
    protected function _getProductCollection()
    {
        if (is_null($this->_productCollection)) {
            $layer = $this->getLayer();
            /* @var $layer Mage_Catalog_Model_Layer */
            if ($this->getShowRootCategory()) {
                $this->setCategoryId(Mage::app()->getStore()->getRootCategoryId());
            }

            // if this is a product view page
            if (Mage::registry('product')) {
                // get collection of categories this product is associated with
                $categories = Mage::registry('product')->getCategoryCollection()
                    ->setPage(1, 1)
                    ->load();
                // if the product is associated with any category
                if ($categories->count()) {
                    // show products from this category
                    $this->setCategoryId(current($categories->getIterator()));
                }
            }

            $origCategory = null;
            if ($this->getCategoryId()) {
                $category = Mage::getModel('catalog/category')->load($this->getCategoryId());
                if ($category->getId()) {
                    $origCategory = $layer->getCurrentCategory();
                    $layer->setCurrentCategory($category);
                }
            }
            $this->_productCollection = $layer->getProductCollection();

            $this->prepareSortableFieldsByCategory($layer->getCurrentCategory());

            if ($origCategory) {
                $layer->setCurrentCategory($origCategory);
            }
        }

        return $this->_productCollection;
    }                
}

getLoadedProductCollection方法包装了对 的调用_getProductCollection,并且_getProductCollection是实际加载集合的位置。

所以,一些临时的调试代码在

protected function _getProductCollection()
{
    var_dump(__METHOD__);
    var_dump($this->getCategoryId());
    Mage::Log(__METHOD__);
    Mage::Log($this->getCategoryId());
}

可以帮助确保您的类别 ID 从布局更新 XML 到块。

但是,如果您更深入地查看_getProductCollection,您会注意到在某些情况下它会重置类别 ID。

if ($this->getShowRootCategory()) {
    $this->setCategoryId(Mage::app()->getStore()->getRootCategoryId());
}
...
if (Mage::registry('product')) {
    // get collection of categories this product is associated with
    $categories = Mage::registry('product')->getCategoryCollection()
        ->setPage(1, 1)
        ->load();
    // if the product is associated with any category
    if ($categories->count()) {
        // show products from this category
        $this->setCategoryId(current($categories->getIterator()));
    }
}
...

如果其他一些 Magento 代码设置了该show_root_category属性,或者您在注册表中有产品对象的页面上,Magento 将覆盖您的类别 ID。

使事情变得更加复杂,一旦加载集合,它就会被设置在受保护的属性上

$this->_productCollection = $layer->getProductCollection();

没有公共 getter 方法。

在这里进行的方法是无数的。如果是我,我会考虑以下其中一项

  1. 使用自定义块类扩展Mage_Catalog_Block_Product_List并具有重置集合上的类别或加载新集合的方法

  2. 自己加载集合,而不依赖于中的代码product/list

于 2012-09-05T16:35:23.523 回答
1

我在 Magento CE 1.7.0.2 下成功地重现了这个问题。

首先,我创建了一个包含以下内容的 local.xml:

<default>
    <reference name="footer">
        <block type="catalog/product_list" name="custom.featuredProduct" as="product_of_the_month" category_id="13" template="custom/featured-product.phtml" />
    </reference>
</default>

我发现,缺少一些包装 XML 元素并添加了一些额外的行:

<?xml version="1.0"?>
<layout>
    <default>
        <reference name="footer">
            <block type="catalog/product_list" name="custom.featuredProduct" as="product_of_the_month" category_id="13" template="custom/featured-product.phtml" />
        </reference>
    </default>
</layout>

添加所需的 XML 元素后,它就可以工作了。

于 2012-09-05T16:45:50.470 回答