8

I have setup a custom option for my product in Magento as dropdown i.e.

Size : Small, Medium, Large

On product page I show additional information for each option using javascript.

Small - Waist 30, Chest 36, Length 42...
Medium - Waist 32, Chest 38, Length 44...
Large - Waist 34, Chest 40, Length 48...

When I add product to cart i get the Size title (Small, Medium or Large) in cart but I also want to show this additional information (Waist 30, Chest 36, Length 42...) and get it saved with order.

What is best way to do it? Thanks in advance.

Farrukh
  • 131
  • 1
  • 1
  • 8
  • Are you saving this additional data somehow? When you check the Admin for the order, does the waist, chest, length, etc. show up? – seanbreeden Feb 17 '12 at 20:34
  • Sorry, if I had not been clear enough. I just show this information if javascript which is hard coded in phtml file. for example if(val==small) then show Waist 30, Chest 36, Length 42... Now I want to add this extra information to the order so that it get stored for each item. – Farrukh Feb 17 '12 at 21:02

3 Answers3

30

The custom options are only stored on the quote as option ID's and values. Every time the options are rendered, they are basically reloaded from the database.
If you modify the values, you would need to save them, and that would set them for everybody.

That said, I work around the issue by adding an additional custom option with the modified value on the fly, using an event observer. For this I use additional options.
Then I remove the original custom option from the quote item.

Up to 1.4 Magento took care of the rest, but since then you need to copy the additional options to the order item manually, and also need to take care it's set again if an item is reordered.

So here is an example observer configuration.

<frontend>
    <events>
        <checkout_cart_product_add_after>
            <observers>
                <customoptions>
                    <type>singleton</type>
                    <class>customoptions/observer</class>
                    <method>checkoutCartProductAddAfter</method>
                </customoptions>
            </observers>
        </checkout_cart_product_add_after>
        <sales_convert_quote_item_to_order_item>
            <observers>
                <customoptions>
                    <type>singleton</type>
                    <class>customoptions/observer</class>
                    <method>salesConvertQuoteItemToOrderItem</method>
                </customoptions>
            </observers>
        </sales_convert_quote_item_to_order_item>
    </events>
</frontend>

The rest is handled in the observer class.

/**
 * Add additional options to order item product options (this is missing in the core)
 *
 * @param Varien_Event_Observer $observer
 */
public function salesConvertQuoteItemToOrderItem(Varien_Event_Observer $observer)
{
    $quoteItem = $observer->getItem();
    if ($additionalOptions = $quoteItem->getOptionByCode('additional_options')) {
        $orderItem = $observer->getOrderItem();
        $options = $orderItem->getProductOptions();
        $options['additional_options'] = unserialize($additionalOptions->getValue());
        $orderItem->setProductOptions($options);
    }
}

/**
 * Manipulate the custom product options
 *
 * @param Varien_Event_Observer $observer
 * @return void
 */
public function checkoutCartProductAddAfter(Varien_Event_Observer $observer)
{
    $item = $observer->getQuoteItem();
    $infoArr = array();

    if ($info = $item->getProduct()->getCustomOption('info_buyRequest')) {
        $infoArr = unserialize($info->getValue());
    }

    // Set additional options in case of a reorder
    if ($infoArr && isset($infoArr['additional_options'])) {
        // An additional options array is set on the buy request - this is a reorder
        $item->addOption(array(
            'code' => 'additional_options',
            'value' => serialize($infoArr['additional_options'])
        ));
        return;
    }

    $options = Mage::helper('catalog/product_configuration')->getCustomOptions($item);

    foreach ($options as $option)
    {
        // The only way to identify a custom option without
        // hardcoding ID's is the label :-(
        // But manipulating options this way is hackish anyway
        if ('Size' === $option['label'])
        {
            $optId = $option['option_id'];

            // Add replacement custom option with modified value
            $additionalOptions = array(array(
                'code' => 'my_code',
                'label' => $option['label'],
                'value' => $option['value'] . ' YOUR EXTRA TEXT',
                'print_value' => $option['print_value'] . ' YOUR EXTRA TEXT',
            ));
            $item->addOption(array(
                'code' => 'additional_options',
                'value' => serialize($additionalOptions),
            ));

            // Update info_buyRequest to reflect changes
            if ($infoArr &&
                isset($infoArr['options']) &&
                isset($infoArr['options'][$optId]))
               {
                // Remove real custom option
                unset($infoArr['options'][$optId]);

                // Add replacement additional option for reorder (see above)
                $infoArr['additional_options'] = $additionalOptions;

                $info->setValue(serialize($infoArr));
                $item->addOption($info);
            }

            // Remove real custom option id from option_ids list
            if ($optionIdsOption = $item->getProduct()->getCustomOption('option_ids')) {
                $optionIds = explode(',', $optionIdsOption->getValue());
                if (false !== ($idx = array_search($optId, $optionIds))) {
                    unset($optionIds[$idx]);
                    $optionIdsOption->setValue(implode(',', $optionIds));
                    $item->addOption($optionIdsOption);
                }
            }

            // Remove real custom option
            $item->removeOption('option_' . $optId);
        }
    }

This is it in a nutshell. Add error checking and taking care of special cases like adding the same product to the cart again as needed.
Hope this gets you started working with custom product options. Not half bad once you get familiar with them.

Vinai
  • 14,162
  • 2
  • 49
  • 69
  • Thank you Vinai for the help. I will try this. – Farrukh Feb 20 '12 at 14:26
  • Here is another answer based on this approach with a little different twist and more detail: http://stackoverflow.com/a/9496266/485589 – Vinai Mar 02 '12 at 07:04
  • will it help if i am setting addition option in sales_quote_collect_totals_before. Because my sales_convert_quote_item_to_order_item it not calling. all – Milople Inc Mar 08 '14 at 05:50
  • @vinay : how it is possible for wishlist?. When user click on add to wishlist button then how we show these additional options on wishlist – Trliok Jul 01 '16 at 09:12
  • I am implemented this on Magento 2 so that I can able to change the custom option values and that changes are reflected on cart page, but when I was followed the sales_convert_quote_item_to_order_item observer on Magento2 the changes are not reflected on the order page. – senthil May 10 '18 at 14:33
0

Go to Admin -> Catalog -> Attributes -> Manage Attributes. Locate your Attribute from the list. In your case, it's probably size. Click it and go to Manage Labels / Options. From there you can add the additional information to each value. You can change the Label to "Small - Waist 30, Chest 36, Length 42" and repeat for each attribute value that you want to change.

seanbreeden
  • 6,104
  • 5
  • 36
  • 45
  • 1
    Sean, thanks for the answer but its not the attribute, it is the custom option. Unfortunately, I can not follow this method because there are log of other issues involved too. If you can guide me to problematically change the value of custom option, it will make my life much easier. – Farrukh Feb 17 '12 at 21:20
-1

Just to add a small fix to Vinai's great solution. The solution breaks the logic of getting a quote item by product.

The function getItemByProduct in Mage_Sales_Model_Quote_Item calls the function representProduct which compares between the quote and product options. If both objects have identical list of options it returns the quote object otherwise false.

Because both objects have different options now that we added our custom option the function will return false.

One way to solve this issue is to rewrite Mage_Sales_Model_Quote_Item class and add your custom option code to the local variable $_notRepresentOptions in the constructor.

class Custom_Options_Model_Sales_Quote_Item extends Mage_Sales_Model_Quote_Item {

        /**
         * Initialize resource model
         *
         */
        protected function _construct()
        {        
            $this->_notRepresentOptions = array_merge($this->_notRepresentOptions, array('additional_options'));

           parent::_construct();
        }
}
Rizwan Khan
  • 211
  • 3
  • 19
Itay Raz
  • 1
  • 1