(Magento 1.4)
A conceptually obvious task of associating simple products with required options to a grouped product proved to be more of a challenge than expected. By default, Magento doesn’t allow this relationship; however, with some simple core overrides, it is possible with the following steps:
1. Create two basic local modules with the following structures:
app/code/local/{module}/Catalog
- Block/Adminhtml/Product/Edit/Tab/Super/Group.php
- Model/Product/Type/Grouped.php
- etc/config.xml
app/code/local/{module}/CatalogInventory
- Model/Mysql4/Indexer/Stock/Grouped.php
- etc/config.xml
2. Edit Group.php by extending Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Group and only overriding the method _prepareCollection(). In the core file, Magento specifies a required option filter; simply remove this and you’re left with:
protected function _prepareCollection()
{
$allowProductTypes = array();
foreach (Mage::getConfig()->getNode('global/catalog/product/type/grouped/allow_product_types')->children() as $type) {
$allowProductTypes[] = $type->getName();
}
$collection = Mage::getModel('catalog/product_link')->useGroupedLinks()
->getProductCollection()
->setProduct($this->_getProduct())
->addAttributeToSelect('*')
->addAttributeToFilter('type_id', $allowProductTypes);
$this->setCollection($collection);
return Mage_Adminhtml_Block_Widget_Grid::_prepareCollection();
}
3. Edit Grouped.php by extending Mage_Catalog_Model_Product_Type_Grouped and overriding its getAssociatedProducts() method. Remove the required option filter, and you’re left with:
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('*')
->setPositionOrder()
->addStoreFilter($this->getStoreFilter($product))
->addAttributeToFilter('status', array('in' => $this->getStatusFilters($product)));
foreach ($collection as $product) {
$associatedProducts[] = $product;
}
$this->getProduct($product)->setData($this->_keyAssociatedProducts, $associatedProducts);
}
return $this->getProduct($product)->getData($this->_keyAssociatedProducts);
}
4. The last update for the /Catalog sub-module is to create the config.xml file. This file should look like this:
<?xml version="1.0"?>
<config>
<modules>
<{Module}_Catalog>
<version>0.1.0</version>
</{Module}_Catalog>
</modules>
<global>
<blocks>
<adminhtml>
<rewrite> <catalog_product_edit_tab_super_group>{Module}_Catalog_Block_Adminhtml_Product_Edit_Tab_Super_Group</catalog_product_edit_tab_super_group>
</rewrite>
</adminhtml>
</blocks>
<models>
<catalog>
<rewrite> <product_type_grouped>{Module}_Catalog_Model_Product_Type_Grouped</product_type_grouped>
</rewrite>
</catalog>
</models>
</global>
</config>
5. Now edit Grouped.php under the CatalogInventory sub-module. Extend Mage_CatalogInventory_Model_Mysql4_Indexer_Stock_Grouped and override its _getStockStatusSelect(…) method. Remove the required option clause from the sql query, and you’re code should look as such:
protected function _getStockStatusSelect($entityIds = null, $usePrimaryTable = false)
{
$adapter = $this->_getWriteAdapter();
$idxTable = $usePrimaryTable ? $this->getMainTable() : $this->getIdxTable();
$select = $adapter->select()
->from(array('e' => $this->getTable('catalog/product')), array('entity_id'));
$this->_addWebsiteJoinToSelect($select, true);
$this->_addProductWebsiteJoinToSelect($select, 'cw.website_id', 'e.entity_id');
$select->columns('cw.website_id')
->join(
array('cis' => $this->getTable('cataloginventory/stock')),
'',
array('stock_id'))
->joinLeft(
array('cisi' => $this->getTable('cataloginventory/stock_item')),
'cisi.stock_id = cis.stock_id AND cisi.product_id = e.entity_id',
array())
->joinLeft(
array('l' => $this->getTable('catalog/product_link')),
'e.entity_id = l.product_id AND l.link_type_id=' . Mage_Catalog_Model_Product_Link::LINK_TYPE_GROUPED,
array())
->joinLeft(
array('le' => $this->getTable('catalog/product')),
'le.entity_id = l.linked_product_id',
array())
->joinLeft(
array('i' => $idxTable),
'i.product_id = l.linked_product_id AND cw.website_id = i.website_id AND cis.stock_id = i.stock_id',
array())
->columns(array('qty' => new Zend_Db_Expr('0')))
->where('cw.website_id != 0')
->where('e.type_id = ?', $this->getTypeId())
->group(array('e.entity_id', 'cw.website_id', 'cis.stock_id'));
// add limitation of status
$psExpr = $this->_addAttributeToSelect($select, 'status', 'e.entity_id', 'cs.store_id');
$psCond = $adapter->quoteInto($psExpr . '=?', Mage_Catalog_Model_Product_Status::STATUS_ENABLED);
if ($this->_isManageStock()) {
$statusExpr = new Zend_Db_Expr('IF(cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 0,'
. ' 1, cisi.is_in_stock)');
} else {
$statusExpr = new Zend_Db_Expr('IF(cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 1,'
. 'cisi.is_in_stock, 1)');
}
$stockStatusExpr = new Zend_Db_Expr("LEAST(MAX(IF({$psCond}, i.stock_status, 0))"
. ", {$statusExpr})");
$select->columns(array(
'status' => $stockStatusExpr
));
if (!is_null($entityIds)) {
$select->where('e.entity_id IN(?)', $entityIds);
}
return $select;
}
6. Edit config.xml under CatalogInventory, which should look as such:
<?xml version="1.0"?>
<config>
<modules>
<{Module}_CatalogInventory>
<version>0.1.0</version>
</{Module}_CatalogInventory>
</modules>
<global>
<models>
<cataloginventory_mysql4>
<rewrite>
<indexer_stock_grouped>{Module}_CatalogInventory_Model_Mysql4_Indexer_Stock_Grouped</indexer_stock_grouped>
</rewrite>
</cataloginventory_mysql4>
</models>
</global>
</config>
7. As with any module, you’ll want to define it within your app/etc/modules/{Module}_App.xml file. Simple add:
<{Module}_Catalog>
<active>true</active>
<codePool>local</codePool>
</{Module}_Catalog>
<{Module}_CatalogInventory>
<active>true</active>
<codePool>local</codePool>
</{Module}_CatalogInventory>
That’s all there is to it. Now, from the admin section, you can associate simple products that have required options to a grouped product. Also, with the CatalogInventory modifications, the stock_status will be set appropriately, and the product will be visible from the catalog search and catalog landings pages.
I didn’t dive into the meanings of my changes, but if you’ve done any Magento core overrides in the past, it should be self explanatory.
To see an example, check out http://www.motionsavers.com/catalogsearch/result/?q=Cotterman . As of this posting, each Cotterman ladder is a grouped product with numerous simple product associations, each of which contains required options. Hope this saves someone time…
{ 18 comments… read them below or add one }
it was very interesting to read.
I want to quote your post in my blog. It can?
And you et an account on Twitter?
Sure, you can quote this information. I’m happy you found it useful. My Twitter is tmillhouse.
Thanks for reading!
Hi bud,
I am going to this is a go right now. I have been having huge trouble with this very problem.
You should post a few front end screenshots of what it looks like after as well
Hi there,
Are you considering releasing further more extensive documentation on this?
Kind Regards
Ryan
Ask and you shall receive
Here is the full source of the custom modules : http://www.brimllc.com/wp-content/uploads/2010/07/app.zip
Be sure to change “Brim” module name to whatever yours is, and then you’ll need to reference this from your main app/etc/{module xml file} .
If you have questions with this, you can always email me at tim@brimllc.com.
Thank you for the guidance, much appreciated.
FYI – Thought you might like to know that your MotionSavers.com website does not work as expected for IE7. When you click on a simple product IE generates an ‘operation aborted’ error (can’t find website). No way for IE7 users to purchase (or configure) a ladder. Works well in Firefox.
Many thanks.
Hmm … that’s odd that you’re seeing issues with IE7. I’m running IE7 in parallels and don’t see the issue. Thanks for the heads up, and I’ll test from a Windows box later tonight.
I would like to exchange links with your site http://www.brimllc.com
Is this possible?
Thank you for your interest in our site; however, at this time, we are currently undergoing some restructuring, so we wont be able to handle any link sharing at this time.
I’m actually trying to do this same thing, so stumbling across this website was a godsend. Unfortunately, however, I can’t find a product on your example site that seems to work as advertised. For instance, this product:
http://www.motionsavers.com/series-2600-ladders.html
The first ladder in the 32″ grouping (2609R3232) definitely has at least one required custom option (Thread Type) but nothing like that shows up on the grouped product page. If I try to add to my cart a quantity of 1 of that product from the grouped product page, it brings me back to that page with an error that says “Please specify the required product(s) options”.
Is your mod not working currently?
Hey Craig, for my requirements on motionsavers, my client only needed simple products with required options to be displayed visually with other simple products without required options; however, if a customer wishes to purchase a simple product with a required option, he needs to go to the simple product page to make the modifications.
Good catch on the ladder page. The intended page flow here should actually redirect to the simple page with that message rather than the grouped page.
Although this is how my requirements were specified, you can still configure options on the grouped page with some additional code. Basically, in the grouped template file, get the options for each simple product and use some code like this:
This code allows you to print out the options inputs and allow the customer to select on the grouped page.
EDIT: the previous link Craig has mentioned has been fixed
By the way, here is an example of how the required simple products are suppose to work on the site: http://www.motionsavers.com/ladders/tilt-and-roll-ladders-9.html . They simply display “Choose Options” if there are required options.
I’ll have to fix the link you found. Thanks
.
Thank you for the guidance, much appreciated
Do you have a back end example or images.
Many thanks.
The source can be downloaded here: http://www.brimllc.com/wp-content/uploads/2010/07/app.zip .
I’d be happy to provide more information on the subject; is there a specific piece that you’d like more clarification on?
Also, as this seems to be a fairly common request, Brim LLC would be more than happy to offer quotes on the work to implement this module.
I’ve been looking for a Magneto solution to support what I’ll call Grouped – Configured products or Grouped Simple Products with Options that appear on one product page. I realize this could be done as one big Configured product but my client would like to merchandise their bedding similar to another site.
http://www.garnethill.com/garnet-hill-signature-flannel-bedding/bedding-home/sheets/flannel-sheets/131926
Ideally every individual sku would be controlled under inventory, but i realize that may not be possible so I’m looking for a solution that has groups of “configurable products”. This approach looked promising but I don’t think my client will want to have 2 pages.
Do you know of any solutions to this. Appears to be a somewhat common Magento request.
Thanks, Jeff
Check out my response to Craig Anderson above. He requested the same example of how to display the options on a single page. Really, this isn’t too difficult since you have access to all of the simple/configurable products from the grouped phtml template. All you need to do is create the necessary html inputs. The example I listed above is using a select input.
Thanks. I’m new to Magento. I understand the concepts but I’m having a difficult time with the syntax. I’m using the grouped.phtml file to loop through the $_associatedProducts as $_item. So in theory I should be able to access each item and get the options assigned to each item then display in a drop down like you have suggested above.
I must be missing something b/c it keeps coming back blank.
Thanks for your help
I sent you an email. If you send me your grouped file, I’ll take a look and make the necessary modifications that will display the options with the necessary html inputs.