Solving Magento

Solutions for Magento E-Commerce Platform

by Oleg Ishenko

Magento Grouped Product Type

The Grouped product type is one of the three composite product type available in the standard Magento installation. Being composite means that products of this type are comprised of one or more child items. Grouped products make it possible to bring together several single products under one roof without them having to share any specific feature, like associated products of a configurable being essentially the same product with one or several variable attributes, or to be inseparable parts of one greater offer, like elements of a bundle product.

Thus the defining feature of a grouped product is a loose relationship between its elements. It is customer who decides what grouped items and in what quantity to buy. To illustrate this let’s consider a grouped product that is available in Magento sample shop data, which you can download from the Magento website (here).

The example product is called “Magento Red Furniture Set” and has the SKU 1114. Its detail page looks like this:

furniture_set

Figure 1. Details page of a grouped product

Note the list of sub product and fields where customers can enter desired quantities for each set item. These fields mean that customer can buy any number of items in any combination. This freedom is restricted only by the items’ availability and configuration settings for the maximal number of products in cart. Naturally, customer is expected to choose minimum one item with quantity of at least 1, otherwise nothing can be added to cart and an error message is displayed.

Now let’s take a look at the same product in the back-end. You’ll notice that this product has no price- or tax-related attributes. Unlike the configurable product type that has a base price, grouped product type has none. Price information is comprised from individual prices of the grouped sub-products (similar to dynamic pricing of a bundle). Whatever price-related logic applies to your grouped products, such as special offers, tier prices, or catalog rules – all of these must be done on the sub-product level.

To find out what sub-items are available in this grouped product switch to tab “Associated products”. You will see the following grid:

associated_products

Figure 2. Furniture set items

This grid can be used to add more products to the set. To do that in the first column change the option from Yes to Any. This will change the list from showing only products already in the set to any possible product. Allowed product types are defined in configuration node global/catalog/product/type/grouped/allow_product_types. The config.xml file of the Mage_Catalog module defines two such types, simple and virtual:


<config>
        ...
        <global>
                ...
                <catalog>
                        <product>
                                <type>
                                        ...
                                        <grouped>
                                                <label>Grouped Product</label>
                                                <model>catalog/product_type_grouped</model>
                                                <price_model>catalog/product_type_grouped_price</price_model>
                                                <composite>1</composite>
                                                <allow_product_types>
                                                        <simple/>
                                                        <virtual/>
                                                </allow_product_types>
                                                <index_priority>50</index_priority>
                                                <price_indexer>catalog/product_indexer_price_grouped</price_indexer>
                                        </grouped>
                                        ...
                                </type>
                        </product>
                        ...
                </catalog>
        ...
        </global>
</config>


Listing 1. Grouped product type configuration. /app/code/core/Mage/Catalog/etc/config.xml, line 480.

Module Mage_Downloadable extends this configuration and adds another product type, Downloadable, to the allowed product types list (see /app/code/core/Mage/Downloadable/etc/config.xml, line 173.

A product to be added to a grouped product must not only be of an allowed type but also have its attribute required_options not to be equal 1. If a product has required_options set to 1 it means that there are options that must be selected before the product can be added to cart. This definitely applies to configurable and bundle products. In some situations other product types can also be affected. First, a downloadable product can have this attribute set to 1 if its links can be purchased separately. Second, any product which has a custom option flagged as “required” also will get required_options set to 1.

Associated products have two options you can control: default quantity and position. If you provide a value for default quantity it will be displayed pre-entered into the quantity input field in the front-end add-to-cart form. The position property allows you to define where in the list the associated product will be displayed. The list is sorted by “position” in an ascending order, negative values are allowed.

Class Mage_Catalog_Model_Product_Type_Grouped

Like other product type classes this one extends class Mage_Catalog_Model_Product_Abstract and defines functionality specific to the Grouped type:

  • Accessing associated products of a grouped one.
  • Writing information about linked products to database after a grouped product is saved.
  • Converting grouped products to quote items or adding a grouped product to a wishlist.

Besides these three main functionality points (which we will look at in greater detail in a minute) the type class also does the following:

  • Tells the system that this product type is composite and can be configured (protected properties $_isComposite and $_canConfigure are set to true).
  • Determines if a product of this type can be sold. This is achieved by method isSalable(), which checks if a grouped product has a non-null value for its is_salable property and returns it. If the grouped product’s is_salable is null (product is not disabled and this property was not set explicitly elsewhere), then the system looks if at least one of its linked products can be sold and returns true if yes.

Grouped product type and its associated products

The relationships between grouped products and their linked sub-products are controlled by instances of class Mage_Catalog_Model_Product_Link and its resource model class Mage_Catalog_Model_Resource_Product_Link. This tandem is a standard Magento model construct that links to database table catalog_product_link. If you look into the link class constants you’ll notice that they also define relationships other than the one between grouped products:

class Mage_Catalog_Model_Product_Link extends Mage_Core_Model_Abstract
{
        const LINK_TYPE_RELATED     = 1;
        const LINK_TYPE_GROUPED     = 3;
        const LINK_TYPE_UPSELL      = 4;
        const LINK_TYPE_CROSSSELL   = 5;

Listing 2. Link type constants, /app/code/core/Mage/Catalog/Model/Product/Link.php, line 46.

As you can see, this class also governs related, upsell, and crossell relationships.

But let’s come back to the Grouped product type class. A list of associated products is generated in method getAssociatedProducts:

public function getAssociatedProducts($product = null)
{
    if (!$this->getProduct($product)->hasData($this->_keyAssociatedProducts)) {
        $associatedProducts = array();

        if (!Mage::app()->getStore()->isAdmin()) {
            $this->setSaleableStatus($product);
        }

        $collection = $this->getAssociatedProductCollection($product)
            ->addAttributeToSelect('*')
            ->addFilterByRequiredOptions()
            ->setPositionOrder()
            ->addStoreFilter($this->getStoreFilter($product))
            ->addAttributeToFilter('status', array('in' => $this->getStatusFilters($product)));

        foreach ($collection as $item) {
            $associatedProducts[] = $item;
        }
        $a = $collection->getSelect()->__toString();
        $this->getProduct($product)->setData($this->_keyAssociatedProducts, $associatedProducts);
    }
    return $this->getProduct($product)->getData($this->_keyAssociatedProducts);
}

Listing 3. Retrieving a list of associated products for a grouped one, /app/code/core/Mage/Catalog/Model/Product/Type/Grouped.php, line 124.

In the first lines, as it is common in such cases, Magento checks if the product object already has a list of linked products which a previous call might have saved in property _cache_instance_associated_products. If no such data is present, a collection of linked products is initialized and data are fetched from the database. Initialization of the associated products collection takes place in the Grouped type class’ method getAssociatedProductCollection:

public function getAssociatedProductCollection($product = null)
{
    $collection = $this->getProduct($product)->getLinkInstance()->useGroupedLinks()
        ->getProductCollection()
        ->setFlag('require_stock_items', true)
        ->setFlag('product_children', true)
        ->setIsStrongMode();
    $collection->setProduct($this->getProduct($product));
    return $collection;
}

Listing 4. Building an associated product collection, /app/code/core/Mage/Catalog/Model/Product/Type/Grouped.php, line 223.

Here you can see that a link class instance is fetched and used to get a collection of links from table catalog_product_link filtered by link type “grouped”. This link collection is extended to include product data and product stock information. Setting a “strong mode” means that the returned linked products will be filtered by its parent product ID, i.e. the grouped product’s ID.

Other methods of the Grouped product type class that deal with associated products (getChildrenIds and getParentIdsByChild) access the link resource model directly to retrieve data from table catalog_product_link.

Whenever a grouped product is saved the information about its associated products must be saved as well. This is done in the second line of the product model’s _afterSave method:

protected function _afterSave()
{
    $this->getLinkInstance()->saveProductRelations($this);
    $this->getTypeInstance(true)->save($this);

Listing 5. Using an instance of a grouped product type class to save associated products, /app/code/core/Mage/Catalog/Model/Product.php, line 537.

Note that in the first line an instance of the link class Mage_Catalog_Model_Product_Link is used to save the product’s relations, such as cross- and upsell products, and related products. In the second line method save of the product type instance is called. It also uses a link class instance to save the relations of the grouped product to its sub-products:

public function save($product = null)
{
    parent::save($product);
    $this->getProduct($product)->getLinkInstance()->saveGroupedLinks($this->getProduct($product));
    return $this;
}

Listing 6. Saving grouped links, /app/code/core/Mage/Catalog/Model/Product/Type/Grouped.php, line 260.

Adding grouped products to cart or wishlist

The _prepareProduct method of the Grouped product class, just like in any other product type class, serves to ensure that the product being added to the shopping cart or to a wishlist has all required properties set. Note two processing modes in this method: “lite” and “strict”, The “lite”, or Mage_Catalog_Model_Product_Type_Abstract::PROCESS_MODE_LITE, is engaged when a product is being added to a wishlist. This mode skips validation of required options. In contrast, the “strict” mode, or Mage_Catalog_Model_Product_Type_Abstract::PROCESS_MODE_FULL, is active during the add-to-cart process and mandates that all the required configuration are to be complete and valid. This what it means for a grouped product:

  • at least one of the sub-products must have quantity > 0
  • all the sub-products with quantity > 0 must have all their required options set.

Actually, the second case is superfluous, because such products would have their attribute required_options set to 1, which would have prevented them to be linked to a grouped product in the first place. However, this check is still done.

If customer attempts to add a grouped product to cart without entering quantity for any sub-product, the system will display an error message: “Please specify the quantity of product(s)”. Unlike Configurable, the standard implementation of the Grouped type offers no client-side validation for the add-to-cart form.

Add a grouped product to cart and you’ll see that it is not the grouped product itself but its sub-products that are added:

grouped_shopping_cart

Figure 3. Grouped sub-products in a shopping cart.

You can change their quantity or remove some of them separately without any obvious relation between them. This is quite different from the other composite types, e.g. Configurable. Also unlike Configurable, there is no parent item in quote or order. The quote and order items refer to the sub-products directly and their past relationship to a grouped product is preserved in form of a serialized property products_options.

Conclusion

In this post we’ve discussed the Grouped product type, which is a composite product type implemented in Magento core. We’ve looked into this type’s product management and have seen how sub-products can be added to a grouped product in the back-end. We’ve learned where does the system store grouped product relationships, and what product types a grouped product can have as associated products. Finally, we’ve made an overview of functions that the Grouped product type extends from the abstract product type and have seen what purpose do they serve to. In the next post I will present a simple tutorial that tackles some of the Grouped type functionality.

33 thoughts on “Magento Grouped Product Type

  1. Pingback: Magento Grouped Product Type Tutorial | Solving Magento

  2. Pingback: Magento Bundle Product Type (Part 1) | Solving Magento

  3. Pingback: Magento Downloadable Product Type (Part 2) | Solving Magento

  4. Great blog i just found it tonight and have bookmarked it!

    Just wanting to know if its possible to add downloadable products into a grouped product?

    Any help would be greatly appreciated 🙂

    • Hello Nicole,

      Yes, it should be possible. Module Mage_Downloadable extends the Grouped type configuration and adds the Downloadable type to the list of types that can be used by Grouped products (link).

  5. Pingback: Creating a Custom Product Type in Magento | Solving Magento

  6. Hi Oleg,
    Really interesting & useful blog – thanks.
    What I was wondering is how to modify the customer UI ‘add to cart ‘experience with grouped products to make bulk buying better.
    For example, a t-shirt in 10 colours & 5 sizes = a lot of rows for users to enter quantity in.
    Is there a way of showing the product in a table with size as the header (Small, Medium, Large, etc) and colour as the rows – so the UI would look something like:

    S M L XL
    Blue qty qty qty qty

    etc?
    Thanks,
    Eddie

    • Hi Eddie,

      I think that is possible. What you need is to tell the template what sizes and colors the associated product collection has. You get this collection for a grouped product by calling

      $coll = $product->getTypeInstance(true)->getAssociatedProducts($product);

      Iterate through the collection to get the distinct values for the size and color attributes. Once that is done, you can create a table in the template with respective columns and rows. Create a loop in the template that puts quantity inputs for the associated products into the right cells – and that is it.

      Hope that helps 🙂

  7. Hi Oleg.

    I am having difficulty with my grouped products.
    I have purchased this extension: http://ecommerce.brimllc.com/grouped-options.html

    I have implemented this extension, which allows configurable products to be grouped, but I need to now try and change the default table setup, that the products are being listed as, to a dropdown list.

    My client wants to sell her bikinis in a set or let the customer choose either the top or the bottom half.. All three have their respective costs. This is one of the products that I have set up with this extension: http://beachandbeyond.co.za/shop/swimwear/shop-by-brand/seafolly/mod-club-balconette-hipster.html
    And this is what my client wants it to look like: http://www.odabash.com/shop/swimwear/bikini/portugal-35019.html?___SID=U

    Please help me out! I have been struggling for three weeks with this issue.

    • Hi Kristen,

      I don’t quite understand: your client wants the product page to look like the one in the obadash.com shop – and I think it is quite possible given the layout I’ve seen in the extension’s demo shop. This would require some template manipulation and styling of course. But you say, you need to transform the options into a drop-down list – that is to choose between top, bottom, or both – which is like the current layout in the client’s shop. Is that right? Because that would require some serious work – and I can’t advise since I don’t have the extension’s source. Plus, I find the obadash layout more user friendly – you clearly see the options to choose; and the drop-down somewhat hides them.

  8. Hi Oleg,
    The products within the group are simple products associated to the grouped product. The simple product can also be found and viewed in the catalog or if they register in a google search. If you happen to click a link to a simple product is there a way to direct to the grouped product and not the simple so that you see all of the intended options.

    Thanks, Dan

    • Hi Daniel,

      I think, you will have to write an extension for that. My idea is to create an observer listening to the catalog_controller_product_init_after event. The observer receives a product instance which it can use to locate a parent product. If a parent product exists, and it is a grouped product, then initiate a redirect to the parent product’s URL. A sample code for the observer is this (caution: I did not test it):

              $product = $observer->getEvent()->getProduct();
              $groupedTypeInstance = Mage::getModel('catalog/product_type_grouped');
              $parentIds = $groupedTypeInstance->getParentIdsByChild($product->getId());
      
              foreach ($parentIds as $parentId) {
                  $parent = Mage::getModel('catalog/product')->load($parentId);
                  if ($parent
                      && $parent instanceof Mage_Catalog_Model_Product
                      && $parent->getTypeId() == 'grouped'
                  ) {
                      $redirect = Mage::getStoreConfig(
                          'catalog/grouped_options/redirect_enabled',
                          Mage::app()->getStore()->getId()
                      );
                      if ($redirect) {
                          Mage::app()->getResponse()->setRedirect($parent->getProductUrl());
                      }
                      break;
                  }
              }
      
      • Hi Oleg, Thanks for giving me hope that this solution is possible although I had a feeling that the answer would be way above my level of understanding!
        Where should I insert the code extension sample to test? Is it a core >model> product>action.

        • Hi Oleg,
          I inserted the code into app>code>local>model>observer.php
          When selecting a simple product the page returned a blank screen with solid black background. Could it be I inserted the code incorrectly or the extension failed.
          Thanks for any more help with this!

          • Hi Oleg,
            I followed your thread on how to create event and observer and introduced this. After I flushed cache and the outcome is that nothing happend, or the simple product did not re-direct to the grouped as required.
            Do you think the code is correct, maybe it is my setup of observer?
            Thanks, Dan

  9. Pingback: Magento Grouped Product Redirect Tutorial | Solving Magento

  10. I have been looking for a solution to our Group Products Display problem and cam across your post. You seem very knowledgeable and I hope you might have a bit of insight to share. I have several products that I want to group together. I have built the groups but the options do not appear on the product page. I am using the default theme, running 1.4.2 and my developer says all the files are available and he cannot figure out why it is not working…argh! It is critical that this feature works for our store…any suggestions?

    • By saying “option”, do you mean, your simple products have custom options which do not show in the grouped product details page?

      I’m not familiar with version 1.4.2, so I have to refer to 1.7 assuming it doesn’t differ from your version in functionality regarding the Grouped type and product options display.

      For a product custom option to be shown in the details page the option must be assigned to the product itself. The snippet below displays the output of a block (container2) that contains the custom option forms:

              <?php if ($_product->isSaleable() && $this->hasOptions()):?>
                  <?php echo $this->getChildChildHtml('container2', '', true, true) ?>
              <?php endif;?>
      

      This code can be found in the catalog/product/view.phtml file, line 100.

      Here, Magento checks if the current product has custom options ($this->hasOptions()) and, if yes, renders the options block.

      Grouped products can’t have custom options. Even if their child products do have them, custom options will not be displayed in the grouped product details page – standard Magento doesn’t offer this functionality.

      You will have to write an extension for that. In this extension, I think, user interface in the product detail page will be the biggest challenge – combining the grouped product configuration form with child products’ custom option fields.

    • I am sorry, in my previous post use of the term “options” was misleading and incorrect. My products do not have “options” I simply meant that the associated products do not appear on the product page. I would like (and it’s required) that the associated products show so the customer may select how many of the associated items they want to add to their cart. I have enabled the product so you can see the page at: http://www.inrangesupplies.com/index.php/dura-steel-ipsc-plate-and-stand.html

      Also, when I try to add the product to my cart I get a message saying “Please specify the quantity of product(s)” so I know Magento is looking for the associated products.

      I can see a portion of the group product function is working because I can see that the price is showing “starting at” on the Category page.

      I hope this clarifies my problem better. I can’t tell you how much I appreciate your taking time to review this problem. Thank you so much!

      Kara

      • You are right, Magento shows the add-to-cart error message because the request has no grouped child product selection. You should check the following:

        • The option products must not be of type Configurable or Bundle
        • The option products must not have “required” custom options
        • The option product must be in stock
        • The option product must be enabled

        The code responsible for fetching a list of grouped children is here /app/code/core/Mage/Catalog/Model/Product/Type/Grouped.php, line 124. This function is called from the grouped product details page template at /app/design/frontend/base/default/template/catalog/product/view/type/grouped.phtml, line 36. Your developer should try setting debug breakpoints there to check why no option products are returned.

        This template file belongs to the “base” design package’s “default” theme. In your shop you are probably using a different package and theme. Please check if the grouped product details page template has code to output grouped children similar to one in the template above.

        Again, this is the 1.7.0 version code, and I can’t guarantee it is identical to the 1.4.2 version in your shop.

        • Thank you for your response. Our developer and myself have checked all the suggestions but still cannot get child products to appear on the product page. I am at a loss for the next step. Argh! Thank you for your suggestions!

  11. Hello,

    First, I really do appreciate your blog. I have a grouped product that is displaying and working as it should. However, I would like to have the same functionality that both simple or configurable products have when a user clicks on the “add to cart” button from the main products or category page. That being that the user is directed to the individual product page where they then choose their options. Instead they receive the “Please specify the quantity of product(s).” error. They then have to figure out that they must click the image or product name to get to the product page. Seems like this should be built-in like the other options. That being to redirect to the specified product page. Am i missing something?

    • Do you mean, the user clicks the “Add to cart” button of a configurable product in a product list page (category) and gets the error message without being redirected to the product details page? The redirect to the grouped product page in such a case is a standard Magento feature. In my demo-shop, http://osc.solvingmagento.net/furniture/living-room.html, a user clicking the “Add to cart” button of the “Magento Red Furniture Set” product will be redirected to the product’s details page where he can configure the grouped options.

      This redirect is defined in method addProduct of the core Mage_Checkout_Model_Cart class. If this code doesn’t work, then it must be a third party extension that prevents it.

  12. My Website was having approx 16000 Simple Products and around 500 Group Products.

    Last Week I uploaded another 16000 Simple Products.

    Now When i try to import the CSV file for Group Products for around 40 SKU’s, All SKU’s are been created but the Associated sku, Asso Position, and Default Qnty are not being imported.

    I am using the same CSV Format as i had used earlier.

    I am using the Default Import / Export Module of Magento.

    Kindly advice.

  13. i have grouped product in which there is two simple product with one product has custom option when i set is required yes this simple product is hidden from grouped product page, also at grouped product page the simple product name are not clickable to redirect us to simple product from group product if any one has module please share with me

    thanks

  14. Hi , I am new developer and developing a magento store for my self.
    As per your post I have set default quntity for associated item to 1. and it shows on front end as 1 in qty box. but when I clicked on add to cart button it shows me error that “Please specify the quantity of product(s).” !!
    can any one help me how can I solve this issue????

    Thanks all

  15. Hi,
    when i add grouped product to wishlist, i want it to add the associated products to the wishlist instead of only one grouped product. How to do it it.Please help

  16. great post! but do you think it’s possible to place grouped product within a grouped product it self?
    Any help will be appreciated!

    Thanks in advance

  17. Thanks for the great article!
    In a category list page, which includes simple and grouped products, is it possible to sort the products by price?
    We consider that grouped product total price, is the sum of it’s associated products.

Leave a Reply

Your email address will not be published. Required fields are marked *

Theme: Esquire by Matthew Buchanan.