Change list.phtml to Show Products of Multiple Categories in Same Block

categoryce-1.9.2.0cmsmagento-1.9product-list

Subject is very concise: I need to show all products within given categories in a CMS page.

To accomplish this, I want to change list.phtml, since it's easy implementable and have a cool appearance.

To be more clear, I want my block like this:

{{block type="catalog/product_list" name="product_list" category_id="12,13,26" column_count="5" mode="list" template="catalog/product/multiple_list.phtml"}}

Is it possible? I'm trying in several ways, but just can't figure out the logic to use in list.phtml that fit in my needs.

By the way, I've tried these solutions, but they aren't exactly what I'm in need:

Points of interest:

  • Magento version: 1.9.2
  • Already showing products of single category
  • Listing products of given root category would fit, but doesn't work too (it's showing products of all the other root categories)

Edit 1:
I have found a answer that comes real close to what I need:

<?php
/**
* Displays multiple category view templates along with the product list for it
*/
/* @var $this Mage_Core_Block_Template */

$category_ids     = explode(',', $this->getData('category_ids'));
$current_category = Mage::registry('current_category');

if ($current_category) {
Mage::unregister('current_category');
}

foreach ($category_ids as $id) {

$category = Mage::getModel('catalog/category')->load(trim($id));

if (!$category->getId()) {
    continue;
}

Mage::register('current_category', $category);

$product_list = $this->getLayout()->createBlock('catalog/product_list', 'product_list_'.$id, array('template' => 'catalog/product/list.phtml'));

echo $this
    ->getLayout()
    ->createBlock('catalog/category_view', 'category_'.$id, array('template' => 'catalog/category/view.phtml'))
    ->append($product_list, 'product_list')
    ->toHtml();

Mage::unregister('current_category');
}

if ($current_category) {
Mage::register('current_category', $current_category);
}

The problem now is that this code is showing all products in root category, instead of the products within category given. Yet it's showing all product lists in it's own block. I want to show all three product lists in same block.

Edit 2: Now I've got this:

<?php
/**
 * Displays multiple category view templates along with the product list for it
 */
/* @var $this Mage_Core_Block_Template */

$category_ids     = explode(',', $this->getData('category_ids'));
$current_category = Mage::registry('current_category');

if ($current_category) {
    Mage::unregister('current_category');
}

foreach ($category_ids as $it => $id) {

    $category = Mage::getModel('catalog/category')->load(trim($id));

    if (!$category->getId()) {
        continue;
    }

    Mage::register('current_category', $category);

    global ${"category_"$it} = $this->getLayout()->createBlock('catalog/product_list', 'product_list_'.$id, array('template' => 'catalog/product/list.phtml'));

    Mage::unregister('current_category');

}

foreach ($category_ids as $it => $id) {
        global array product_list ( array $product_list [, array ${"category_"$it}] );
}

Mage::register('current_category', 'category_1');

echo $this
    ->getLayout()
        ->createBlock('catalog/category_view', 'category_1', array('template' => 'catalog/category/view.phtml'))
        ->append($product_list, 'product_list')
        ->toHtml();

}

if ($current_category) {
    Mage::unregister('current_category');
}

This part of code should:

  • Create 3 arrays of products
  • Merge these 3 arrays into 1 "products_list"
  • Create 1 block as "view"
  • Echo all 3 arrays into same block.

But now, it just stops my CMS page, breaking all content page.

Edit 3:

I'm not sure about how to create my own block, or how to call a block defined by me, but following @fschmengler and @Wouter Steenmeijer, here's what I have now:

Layout Update XML:

<reference name="content">
    <block type="core/template" name="multiple_categories" template="catalog/category/list.phtml">
        <action method="setData"><key>category_ids</key><val>12,13,26</val></action>
     </block>
</reference>

file: app/code/local/starscream/default/block/multiple.php

content:

<?php
 protected function _getProductCollection()
    {
    $category_ids = $this->getCategoryIds();
    $productCollection = Mage::getModel('catalog/product')
        ->getCollection()
        ->addStoreFilter()
        ->setVisibility(Mage::getSingleton('catalog/product_visibility')->getVisibleInCatalogIds());
        ->addMinimalPrice()
        ->addFinalPrice()
        ->addTaxPercents()
        ->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes())
        ->addUrlRewrite()
        ->joinField(
            'category_id', 'catalog/category_product', 'category_id',
            'product_id = entity_id', null, 'left'
        )
        ->addAttributeToFilter('category_id', array(
            array('in' => array($category_ids)),
        ));

        return $productCollection;
    }
?>

I didn't find how to call this "multiple.php" block I created in my CMS page… Am I missing something?

Any help is appreciated.

Best Answer

Good question!

The trick here is to extend a block based on catalog/product_list.

I think the best way here is to add some xml to the "Layout Update XML" section.

<reference name="content">
    <block type="catalog/product_list" 
           name="multiple_categories" template="catalog/product/list.phtml">
        <action method="setCategoryIds"><category_ids>4,5,6,7</category_id></action>
    </block>
</reference>

Here you have to replace catalog/product_list with your created custom module block. SetCategoryIds sets the categoryids in this block so you can filter on them.

In product/list.phtml is this called to get the product collection:

    $_productCollection=$this->getLoadedProductCollection();

The trick here is to create a custom module that extends on catalog/product_list and replaces the function _getProductCollection.

If you want to know how to do that, please read this: read this thread

In this new block you add this function:

    protected function _getProductCollection()
    {
    $category_ids = $this->getCategoryIds();
    $productCollection = Mage::getModel('catalog/product')
        ->getCollection()
        ->addStoreFilter()
        ->setVisibility(Mage::getSingleton('catalog/product_visibility')->getVisibleInCatalogIds());
        ->addMinimalPrice()
        ->addFinalPrice()
        ->addTaxPercents()
        ->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes())
        ->addUrlRewrite()
        ->joinField(
            'category_id', 'catalog/category_product', 'category_id',
            'product_id = entity_id', null, 'left'
        )
        ->addAttributeToFilter('category_id', array(
            array('in' => array($category_ids)),
        ));

        return $productCollection;
    }

EDIT:

First, forget about the custom module. This is magento best pratice, since we dont want to edit the core. We will get back to that later.

You're block type now is core/template. The function getProductCollection doesn't exist in the block core/template. Have a look in this folder: app/code/mage/core/block/template.php

So you have to reference to another block. Ideally you want to create a custom module for this that extents the block type catalog/product_list. But as I said earlier, well get back to that later.

In the block catalog/product_list ( app/code/mage/catalog/product/list.php ) is the function _getProductCollection(). This is the function that every catalog pages uses to get the product collection. This is also the function you want to use. So change core/template with catalog/product_list.

Replace the function _getProductCollection() with the function I pasted above. You will see that it works!

Now that you know that the new function that you made works, you want to put this code in a new custom block. You do that to create a module with a block. Read this thread carefully to create a new block: Stackexchange link to create a custom block

Reason for creating a new block is that we dont want to edit the core of magento. When you update magento to the newest version the changes you have done are gone. Also its hard to keep track of the changes being done.

I hope you now better understand the magento block system!

Related Topic