Magento Display all products within the category on a product view page

user1455139 picture user1455139 · Aug 16, 2012 · Viewed 7.6k times · Source

I am trying to customize my product landing pages to include all a scrollable view of all other products within the same category. I have it almost there, but it is showing products from all categories, rather than just the category the current product you are viewing is in. Below is the code I have added to my product view.phtml, which gives me the products in my scrollable container. Can any one help me limit it to show only products in the current category? A sample of one of the product pages can be viewed at Product view page

The version is magento 1.6.1

My product view customization here

<div class="coll_container">
<!-- "previous page" action -->
<a class="prev browse left"></a>
<div id="collection" class="scrollable">


<?php                        
$cat_id = Mage::getModel('catalog/layer')->getCurrentCategory()->getId(); // set      current category id
$category = Mage::getModel('catalog/category')->load($cat_id);
$productCollection = Mage::getResourceModel('catalog/product_collection')
                         ->addCategoryFilter($category);

$products = $category->getProductCollection()->addCategoryFilter($category)->addAttributeToSelect('*');
?>

<ul>

<?php foreach ( $products as $_product ): ?>
<li class="item"><?php if($_product->isComposite() || !$_product->isSaleable()):   ?>     
<?php endif; ?>
      <a class="item-link" href="<?php echo $_product->getProductUrl() ?>"><img src="<?php echo $this->helper('catalog/image')->init($_product, 'thumbnail')->keepAspectRatio(true)->keepFrame(false)->resize(150,225) ?>" alt="<?php echo $this->htmlEscape($_product->getName()) ?>" width="150" height="225" /></a>

     <div class="tooltip">
                    <span class="indicator"><!-- --></span>
                    <div class="tooltip-content">
                <a href="<?php echo $_product->getProductUrl() ?>"><?php echo   $this->htmlEscape($_product->getName()) ?></a>
            <!-- Price -->
       <p class="price"> <?php echo $this->getPriceHtml($_product, true) ?>    </p>        
        </div><!-- End Tooltip content -->
        </div><!-- End Tooltip -->
   </li>
<?php endforeach; ?> 
</ul>




</div><!-- End Collection -->
<!-- "next page" action -->
<a class="next browse right"></a>

</div><!-- End coll_container -->

Answer

J&#252;rgen Thelen picture Jürgen Thelen · Aug 17, 2012

Besides the redundancy of getting the collection twice - $productCollection and $products, the latter one being used for the loop - your code would work correctly and the collection would contain only products of the current category, provided your landing pages are rewritten to

catalog/category/view/id/<id> OR
catalog/product/view/id/<id>/category/<id>

but not, if they are rewritten to

catalog/product/view/id/<id>

This is because Mage_Catalog_Model_Layer::getCurrentCategory() depends on whether the registry key current_category is set. If current_category is not set, the method returns the root category id of the current store, which explains why you see products of all categories:

public function getCurrentCategory()
{
    $category = $this->getData('current_category');
    if (is_null($category)) {
        if ($category = Mage::registry('current_category')) {
            $this->setData('current_category', $category);
        }
        else {
            $category = Mage::getModel('catalog/category')->load($this->getCurrentStore()->getRootCategoryId());
            $this->setData('current_category', $category);
        }
    }

    return $category;
}

In Magento OOB, the registry key current_category will be set at different locations, but in your case only these two are of interest:

Mage_Catalog_CategoryController::_initCatagory()*
Mage_Catalog_Helper_Product::initProduct()

The former is normally only called by

Mage_Catalog_CategoryController::viewAction()

The latter is called at several places, amongst others at

Mage_Catalog_ProductController::viewAction()

but in this case only, if a catalog parameter like catalog/<id> was passed.

Rewrites

One possibility to fix your issue would be to add rewrites for your landing pages that use

catalog/product/view/id/1/category/3

style target_paths.

If you only have a handfull of products, you can do this manually using the "URL Rewrite Management" in the admin backend.

If you have many products, you can also do it programmatically.

Using the product's category id directly

Another possibility to fix this issue would be, to get the category id directly from the product being viewed and use it to filter the collection:

$aCategoryId = $this->getProduct()->getCategoryIds();
if (!$aCategoryId) {
    echo "This product is not assigned to any categories.";
}
$iCategoryId = $aCategoryId[0];
$oCategory = Mage::getModel('catalog/category')->load($iCategoryId);
$oProductCollection = $oCategory
    ->getProductCollection()
    ->addCategoryFilter($oCategory)
    ->addAttributeToSelect('*')
    ->addFieldToFilter('entity_id', array('neq' => $this->getProduct()->getId()));
foreach ($oProductCollection as $oProduct) {
    var_dump($oProduct->getName());
}

Note, that I added a filter to exclude the viewed product itself from the collection.


* that's not a typo, it is really written a _initCatagory, not _initCategory in at least CE 1.6.2 (haven't checked others, yet)