Search code examples
phpmagentotransactionsbundleproduct

Magento bundle products: child option sort order issue


I'm having an issue wherein a Bundled Product's child option/products are not sorting correctly in transactional emails.

The sort order is important, in this case, because the product model is one of the options, and needs to be displayed first.

In template/bundle/email/order/items/order/default.phtml, we have the view logic to spit out product details:

<?php $_item = $this->getItem() ?>
<?php $_order=$this->getOrder() ?>

<?php $parentItem = $this->getItem() ?>
<?php $items = array_merge(array($parentItem), $parentItem->getChildrenItems()); ?>

<?php foreach ($items as $_item): ?>

// etc...

the sort order for the child products are defined, as per usual, in the admin and display normally in the product view, cart, checkout etc... but the order is getting munged during display in emails.

Whats odd is the order is not alphabetical, either. In fact, it seems a bit arbitrary - strange...

At any rate, how should I go about sorting the $items array to match the intended sort order ?

Note = this is the value set in admin->catalog->product->bundle items->position.


Update

Here is my finalized helper method:

/**
 * @codepool   Local
 * @package    Namespace
 * @module     Module
 */

class Namespace_Module_Helper_Product_Sort extends Mage_Core_Helper_Abstract
{

    /*
    * @param $item : bundle product 
    * @return array
    */
    public function sortBundleChildrenByPosition( $item )
    {
        $sorted = array();
        $sorted[] = $item;

        //Mage::log('Namespace_Module_Helper_Product_Bundle::sortChildrenByPosition /n'.print_r($item->debug(), true));

        // grab the product (bundle parent)
        $_product = $item->getProduct();

        // grab child order items
        $_children = $item->getChildrenItems();

        // grab sort order for options
        $optionCollection = $_product->getTypeInstance(true)->getOptionsCollection($_product);

        // iterate over options, comparing title / label, if they match, toss into return array
        foreach ($optionCollection as $option){

            //Mage::log('$option:'.print_r($option->debug(), true));
            $title = $option['default_title'];

            foreach ($_children as $child){
                $prodOption = $child->getProductOptions();
                $bundleSelectionAttributes = unserialize($prodOption['bundle_selection_attributes']);
                //Mage::log('$_children=>$child:product_options[bundle_selection_attributes]'.print_r($bundleSelectionAttributes, true));

                if ($bundleSelectionAttributes['option_label'] == $title){
                    //Mage::log('$bundleSelectionAttributes[option_label] == '.$title.'. $sorted[] ='. print_r($child->debug(), true) );
                    $sorted[] = $child;
                    continue; 
                }
            }

        }

        return $sorted;
    }

}

And I call it in template/bundle/email/order/items/order/default.phtml (or wherever sorted bundles are required) :

<?php 
    $_item = $this->getItem(); 
    $_order=$this->getOrder(); 

    $parentItem = $this->getItem(); 

    //$items = array_merge( array($parentItem), $parentItem->getChildrenItems()); 

    $items = $this->helper('Namespace_Module/Product_Sort')->sortBundleChildrenByPosition( $_item );
?>

... I'm 1000% certain there's some built in method to do this, and probably something cleaner. But I could not find it after a few hours of scrounging.

This works. That is all.


Solution

  • One way to go about it:

    • Loop through all the $items and create an array with id's (as keys) and names (as the values) let's assume it's called $sortedPrd.
    • Sort the new array's ($sortedPrd) values (alphabetically)
    • Loop through $sortedPrd and use the it's key to pull the given product from $items

    Update

    Here is some code to get the positions for bundle options (sub products):

    $optionCollection = $_product->getTypeInstance(true)->getOptionsCollection($_product);
    foreach ($optionCollection as $prdOptions){
    
      $position = $prdOptions->getPosition();
    }
    

    See this question for more info: Magento: how to load product along its all data as it is used in admin