Jump to content

Display subcategory products in parent category


Recommended Posts

Hi, I have categories that contain subcategory but don't contain products. When a visitor clicks on a such category it's showen the message saying that there are no products in that category.

 

How can I display the products of the subcategory, or is there a way to associate the products of the subcategory to the parent category?

 

Thank you.

Edited by NelutuO (see edit history)
Link to comment
Share on other sites

  • 1 month later...

It may come to associating all products with their parent category as well, but I'd really like to avoid it (as I have a large number of products). Manually would take days, and trying to do it with straight sql is giving me a headache.

 

Logically, a product that is in a subcategory would also be in the parent category. It boggles my mind why Prestashop wouldn't have a flag for this somewhere. (I'm hoping there is one that I have simply missed!) :)

 

It appears I can also do some controller editing, but that seems sloppy. http://www.prestashop.com/forums/topic/61907-displaying-all-products-from-subcategories-on-the-category-page/page-3?do=findComment&comment=1278016

Link to comment
Share on other sites

hello

if you want to display products of subcategories while you're browsing parent category - just turn on block layered navigation module.

you don't have to configure it and create filters etc. just install it, turn it on and enable this option (on module configuration page)
Qfd8Tjl.png

  • Like 7
Link to comment
Share on other sites

Thanks Vekia. Perhaps I'm missing something. Doesn't that just affect what's displayed under that block? I have a site structure that's like:

* Products
      * Parent Category
            * Child Category

And I'd like my child category products to show up when I'm in my Parent Category and Products. Not just the categories in the block, but the actual products on the page when I'm viewing the category pages.

 

Right now when I'm in Products, I see my categories and subcategories displaying in the block, but as for the actual product view I get "There are no products in this category" followed by a list of subcategories. I'd like to see all the products.

 

I guess I may have to manually just add all my products to their parent categories...

Edited by tsprings (see edit history)
Link to comment
Share on other sites

noooo, you don't have to add products to their parent categories.

if you will turn it on (option that i mentioned) products from subcategories will be automatically visible if you will browse parent categories

Link to comment
Share on other sites

  • 1 month later...

Based on this post: http://www.prestashop.com/forums/topic/61907-displaying-all-products-from-subcategories-on-the-category-page/page-3?do=findComment&comment=1278016

 

(Use at your own risk, this is working on my 1.6 store, but I am by no means a Prestashop expert.)

 

Create the following file: override/controllers/front/CategoryController.php

 

With this code:

<?php
class CategoryController extends CategoryControllerCore
{
	public $php_self = 'category';
	protected $category;
	public $customer_access = true;
	public $subCatProdCount = 0;

	/**
	 * Assign sub categories templates vars
	 */
	protected function assignSubcategories()
	{
		if ($subCategories = $this->category->getSubCategories($this->context->language->id))
		{
			$subcategory_objects=array();
		   foreach ($subCategories as $subcategory)
				  {
				   $sub=new Category(intval($subcategory['id_category']));//,intval($cookie->id_lang));
				   $subcategory_objects[$subcategory['id_category']]=$sub;
				   $this->subCatProdCount += $sub->getProducts(null, null, null, $this->orderBy, $this->orderWay, true);
			   }
			   $this->context->smarty->assign("subcategories_objects",$subcategory_objects);
			   
			$this->context->smarty->assign(array(
				'subcategories' => $subCategories,
				'subcategories_nb_total' => count($subCategories),
				'subcategories_nb_half' => ceil(count($subCategories) / 2)
			));
		}
	}
	
	public function assignProductList()
	{
		$hookExecuted = false;
		Hook::exec('actionProductListOverride', array(
			'nbProducts' => &$this->nbProducts,
			'catProducts' => &$this->cat_products,
			'hookExecuted' => &$hookExecuted,
		));

		// The hook was not executed, standard working
		if (!$hookExecuted)
		{
			$this->context->smarty->assign('categoryNameComplement', '');
			$this->nbProducts = $this->category->getProducts(null, null, null, $this->orderBy, $this->orderWay, true);
			$this->pagination((int)$this->nbProducts); // Pagination must be call after "getProducts"
			$this->cat_products = $this->category->getProducts($this->context->language->id, (int)$this->p, (int)$this->n, $this->orderBy, $this->orderWay);
		}
		// Hook executed, use the override
		else
			// Pagination must be call after "getProducts"
			$this->pagination($this->nbProducts);

		Hook::exec('actionProductListModifier', array(
			'nb_products' => &$this->nbProducts,
			'cat_products' => &$this->cat_products,
		));

		foreach ($this->cat_products as &$product)
			if ($product['id_product_attribute'] && isset($product['product_attribute_minimal_quantity']))
				$product['minimal_quantity'] = $product['product_attribute_minimal_quantity'];

		$this->addColorsToProductList($this->cat_products);

		$this->nbProducts += $this->subCatProdCount;
		$this->context->smarty->assign('nb_products', $this->nbProducts);
	}
	
}

In the bootstrap theme, category.tpl find the following code:

{if $products}
    <div class="content_sortPagiBar clearfix">
        <div class="sortPagiBar clearfix">
            {include file="./product-sort.tpl"}
            {include file="./nbr-product-page.tpl"}
        </div>
        
        <div class="top-pagination-content clearfix">
            {include file="./product-compare.tpl"}
            {include file="$tpl_dir./pagination.tpl"}
        </div>
    </div>
    {include file="./product-list.tpl" products=$products}
    <div class="content_sortPagiBar">
        <div class="bottom-pagination-content clearfix">
            {include file="./product-compare.tpl" paginationId='bottom'}
            {include file="./pagination.tpl" paginationId='bottom'}
        </div>
    </div>
{/if}

And replace the {/if} with:

{elseif isset($subcategories_objects)}
        {foreach from=$subcategories item=subcategory}

          {assign var="subcategory_id" value=$subcategory.id_category}
          {assign var="subcategory_object" value=$subcategories_objects.$subcategory_id}
      
            {include file="./product-list.tpl" products=$subcategory_object->getProducts('1','1','100','price','desc')}
      
        {/foreach}
{/if}

It's not perfect (as in you can't sort, compare, etc.) but at least you can view products in subcategories.

  • Like 3
Link to comment
Share on other sites

  • 4 months later...

Hi everyone i found a fix for this!! :) i've been trying stuff all day.

 

Firstly as Vekia said, turn on your block layered navigation module and turn on display sub categories. (go to module > layered navigation block > click configure)

 

When i did this, it still didn't work.

 

You then also need to go back to the layered navigation module and in the section ''FILTERS TEMPLATES'' you need to create a new template.

 

In the template select all of your main categories, then scroll down and make sure ''sub-categories filter'' is selected as green  (yes)

 

Now it should work :)

  • Like 5
Link to comment
Share on other sites

Hi everyone i found a fix for this!! :) i've been trying stuff all day.

 

Firstly as Vekia said, turn on your block layered navigation module and turn on display sub categories. (go to module > layered navigation block > click configure)

 

When i did this, it still didn't work.

 

You then also need to go back to the layered navigation module and in the section ''FILTERS TEMPLATES'' you need to create a new template.

 

In the template select all of your main categories, then scroll down and make sure ''sub-categories filter'' is selected as green  (yes)

 

Now it should work :)

 

so we have working solution now.

anyway, that's a little strange that sometimes it works witohut filter templates, and in some other shops works only when filter is defined.

Link to comment
Share on other sites

  • 1 month later...

Dear all

I have a similar question.

I need to display same subcategory in 3 different parent categories.

We are selling memory cards. We added it under "Memory Cards" sub category under "Storage Devices" parent category.

I need to add same "Memory Cards" sub category under "Mobile Phone Accessories" category and "Camera Accessories" category.

Is it possible? If yes, please guide me.

  • Like 1
Link to comment
Share on other sites

  • 1 year later...

Hello, if you need show all products from subcategories in parent category, here's what you need to do:
 
This is my own solution to this problem.
This solution works great on versions 1.6.1 and higher.
 
Open file classes/Category.php and find function getProducts()
 
Inside at the top of the function code, write this:
 
 

		$id_parent = (int)$this->id;
		$parent = new Category((int)$id_parent);

Below in function find this code:

		/** Return only the number of products */
		if ($get_total) {
			$sql = 'SELECT COUNT(cp.`id_product`) AS total
					FROM `'._DB_PREFIX_.'product` p
					'.Shop::addSqlAssociation('product', 'p').'
					LEFT JOIN `'._DB_PREFIX_.'category_product` cp ON p.`id_product` = cp.`id_product`
					WHERE cp.`id_category` = '.(int)$this->id.
				($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '').
				($active ? ' AND product_shop.`active` = 1' : '').
				($id_supplier ? 'AND p.id_supplier = '.(int)$id_supplier : '');

			return (int)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql);
		}

And replace this code, on this one:

		/** Return only the number of products */
		if ($get_total) {
			$sql = 'SELECT COUNT(cp.`id_product`) AS total
					FROM `'._DB_PREFIX_.'product` p
					'.Shop::addSqlAssociation('product', 'p').'
					LEFT JOIN `'._DB_PREFIX_.'category_product` cp ON p.`id_product` = cp.`id_product`
					LEFT JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category)
					WHERE c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright.' AND c.active = 1
				'.($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '').
				($active ? ' AND product_shop.`active` = 1' : '').
				($id_supplier ? 'AND p.id_supplier = '.(int)$id_supplier : '');

			return (int)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql);
		}

You simple need add one LEFT JOIN:

LEFT JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category)

And replace WHERE in sql request on this:

WHERE c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright.' AND c.active = 1

Below in function find this code:

		$sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) AS quantity'.(Combination::isFeatureActive() ? ', IFNULL(product_attribute_shop.id_product_attribute, 0) AS id_product_attribute,
					product_attribute_shop.minimal_quantity AS product_attribute_minimal_quantity' : '').', pl.`description`, pl.`description_short`, pl.`available_now`,
					pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image` id_image,
					il.`legend` as legend, m.`name` AS manufacturer_name, cl.`name` AS category_default,
					DATEDIFF(product_shop.`date_add`, DATE_SUB("'.date('Y-m-d').' 00:00:00",
					INTERVAL '.(int)$nb_days_new_product.' DAY)) > 0 AS new, product_shop.price AS orderprice
				FROM `'._DB_PREFIX_.'category_product` cp
				LEFT JOIN `'._DB_PREFIX_.'product` p
					ON p.`id_product` = cp.`id_product`
				'.Shop::addSqlAssociation('product', 'p').
				(Combination::isFeatureActive() ? ' LEFT JOIN `'._DB_PREFIX_.'product_attribute_shop` product_attribute_shop
				ON (p.`id_product` = product_attribute_shop.`id_product` AND product_attribute_shop.`default_on` = 1 AND product_attribute_shop.id_shop='.(int)$context->shop->id.')':'').'
				'.Product::sqlStock('p', 0).'
				INNER JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category AND c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright : 'c.id_category = '.(int)$id_parent).' AND c.active = 1)
				LEFT JOIN `'._DB_PREFIX_.'category_lang` cl
					ON (product_shop.`id_category_default` = cl.`id_category`
					AND cl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('cl').')
				LEFT JOIN `'._DB_PREFIX_.'product_lang` pl
					ON (p.`id_product` = pl.`id_product`
					AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').')
				LEFT JOIN `'._DB_PREFIX_.'image_shop` image_shop
					ON (image_shop.`id_product` = p.`id_product` AND image_shop.cover=1 AND image_shop.id_shop='.(int)$context->shop->id.')
				LEFT JOIN `'._DB_PREFIX_.'image_lang` il
					ON (image_shop.`id_image` = il.`id_image`
					AND il.`id_lang` = '.(int)$id_lang.')
				LEFT JOIN `'._DB_PREFIX_.'manufacturer` m
					ON m.`id_manufacturer` = p.`id_manufacturer`
				WHERE product_shop.`id_shop` = '.(int)$context->shop->id.'
					AND cp.`id_category` = '.(int)$this->id
					.($active ? ' AND product_shop.`active` = 1' : '')
					.($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '')
					.($id_supplier ? ' AND p.id_supplier = '.(int)$id_supplier : '');

And replace on this one:

		$sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) AS quantity'.(Combination::isFeatureActive() ? ', IFNULL(product_attribute_shop.id_product_attribute, 0) AS id_product_attribute,
					product_attribute_shop.minimal_quantity AS product_attribute_minimal_quantity' : '').', pl.`description`, pl.`description_short`, pl.`available_now`,
					pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image` id_image,
					il.`legend` as legend, m.`name` AS manufacturer_name, cl.`name` AS category_default,
					DATEDIFF(product_shop.`date_add`, DATE_SUB("'.date('Y-m-d').' 00:00:00",
					INTERVAL '.(int)$nb_days_new_product.' DAY)) > 0 AS new, product_shop.price AS orderprice
				FROM `'._DB_PREFIX_.'category_product` cp
				LEFT JOIN `'._DB_PREFIX_.'product` p
					ON p.`id_product` = cp.`id_product`
				'.Shop::addSqlAssociation('product', 'p').
				(Combination::isFeatureActive() ? ' LEFT JOIN `'._DB_PREFIX_.'product_attribute_shop` product_attribute_shop
				ON (p.`id_product` = product_attribute_shop.`id_product` AND product_attribute_shop.`default_on` = 1 AND product_attribute_shop.id_shop='.(int)$context->shop->id.')':'').'
				'.Product::sqlStock('p', 0).'
				LEFT JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category)
				LEFT JOIN `'._DB_PREFIX_.'category_lang` cl
					ON (product_shop.`id_category_default` = cl.`id_category`
					AND cl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('cl').')
				LEFT JOIN `'._DB_PREFIX_.'product_lang` pl
					ON (p.`id_product` = pl.`id_product`
					AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').')
				LEFT JOIN `'._DB_PREFIX_.'image_shop` image_shop
					ON (image_shop.`id_product` = p.`id_product` AND image_shop.cover=1 AND image_shop.id_shop='.(int)$context->shop->id.')
				LEFT JOIN `'._DB_PREFIX_.'image_lang` il
					ON (image_shop.`id_image` = il.`id_image`
					AND il.`id_lang` = '.(int)$id_lang.')
				LEFT JOIN `'._DB_PREFIX_.'manufacturer` m
					ON m.`id_manufacturer` = p.`id_manufacturer`
				WHERE product_shop.`id_shop` = '.(int)$context->shop->id.'
					AND c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright.' AND c.active = 1
					'.($active ? ' AND product_shop.`active` = 1' : '')
					.($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '')
					.($id_supplier ? ' AND p.id_supplier = '.(int)$id_supplier : '');

Here you need do all the same, add LEFT JOIN and change WHERE section in sql request.
 
Thats all!!!
 
PLEASE NOT: If you use blocklayered module, you dont need this fix, just turn on show product from subcategories in module settings.

 

Also i attach file, you can download this file and upload inside this folder: /override/classes/

 

Category.php

 

Dont forget delete after this file: /cache/class_index.php

If you already have this file inside override folder, you need copy getProducts function from this file and write this function inside your old file.

Also i attach file, you can download this file and upload inside this folder: /override/classes/

 

Category.php

 

Dont forget delete after this file: /cache/class_index.php

If you already have this file inside override folder, you need copy getProducts function from this file and write this function inside your old file.

  • Like 1
Link to comment
Share on other sites

Small fix. i found bug, you need change:

 

		if ($get_total) {
			$sql = 'SELECT COUNT(cp.`id_product`) AS total
 

 

on

 

		if ($get_total) {
			$sql = 'SELECT COUNT(DISTINCT cp.`id_product`) AS total
  • Like 1
Link to comment
Share on other sites

×
×
  • Create New...