6

I'm trying to show configurable product options for each related product on a product page, so that the user can select options and add a related product to the basket without navigating to that related product's individual page.

I used code from and answer to another question found here, copying it into related.phtml, although it was originally suggested for doing something similar in list.phtml.

I am able to display the drop-down options for each related product

enter image description here

, but adding to basket of the main product, seems to produce this error:

Fatal error: Call to a member function getAttributeCode() on a non-object in C:\wamp\www\magento91\app\code\core\Mage\Catalog\Model\Product\Type\Configurable.php on line 526

Edit: there seems to be some kind of conflict between the main product and the related items on the page, when adding to Cart.

Also, the related products themselves, will not add to the basket correctly either. They tend to just navigate to that product's individual page, when clicking Add to Cart.

Could someone please tell me where I'm going wrong?

     <?php foreach($this->getItems() as $_item): ?>
        <li class="item">
            <?php if(!$_item->isComposite() && $_item->isSaleable()): ?>
                <?php if (!$_item->getRequiredOptions()): ?>
                    <input type="checkbox" class="checkbox related-checkbox" id="related-checkbox<?php echo $_item->getId() ?>" name="related_products[]" value="<?php echo $_item->getId() ?>" />
                <?php endif; ?>
            <?php endif; ?>
            <div class="product">
                <a href="<?php echo $_item->getProductUrl() ?>" title="<?php echo $this->escapeHtml($_item->getName()) ?>" class="product-image"><img src="<?php echo $this->helper('catalog/image')->init($_item, 'thumbnail')->resize(75) ?>" width="75" height="75" alt="<?php echo $this->escapeHtml($_item->getName()) ?>" /></a>
                <div class="product-details">
                    <p class="product-name"><a href="<?php echo $_item->getProductUrl() ?>"><?php echo $this->escapeHtml($_item->getName()) ?></a></p>
                    <?php echo $this->getPriceHtml($_item, true, '-related') ?>
                    <?php if ($this->helper('wishlist')->isAllow()) : ?>
                        <a href="<?php echo $this->getAddToWishlistUrl($_item) ?>" class="link-wishlist"><?php echo $this->__('Add to Wishlist') ?></a>
                    <?php endif; ?>
                </div>

                <!-- Insert FORM here -->
                <form action="<?php echo $this->getAddToCartUrl($_item) ?>" method="post" id="product_addtocart_form_<?php echo $_item->getId()?>"<?php if($_item->getOptions()): ?> enctype="multipart/form-data"<?php endif; ?>> 
                    <?php if(!$_item->isGrouped()): ?> 
                        <input type="text" name="qty" id="qty" maxlength="12" value="<?php echo ($this->getMinimalQty($_item)?$this->getMinimalQty($_item):1) ?>" /> 
                        <label for="qty"><?php echo $this->__('Qty') ?>:</label> 
                    <?php endif; ?> 

                    <!-- Code to get configurable options for related products-->
                    <div class="related-options-custom">
                       <?php $_product = $_item; ?>
                        <?php if($_product->isConfigurable()): ?>
                          <!--//get attributes-->
                          <?php $attributes = $_product->getTypeInstance(true)->getConfigurableAttributes($_product) ?>
                          <?php if(count($attributes)): ?>
                            <ul>
                            <?php foreach($attributes as $att): ?>
                              <?php $pAtt=$att->getProductAttribute();
                                //get the child products
                                $allProducts = $_product->getTypeInstance(true)->getUsedProducts(null, $_product);
                                $frontValues =array() ?>
                                <dt><label class="required"><em>*</em><?php echo $pAtt->getFrontendLabel() ?></label></dt>
                                <dd<?php if ($att->decoratedIsLast){?> class="last"<?php }?>>
                                    <div class="input-box">
                                       <select name="super_attribute[<?php echo $att->getAttributeId() ?>]" id="attribute<?php echo $att->getAttributeId() ?>" class="required-entry super-attribute-select">
                                           <option><?php echo $this->__('Choose an Option...') ?></option>
                                           <?php foreach($allProducts as $p): ?>
                                             <!--//check stock, status, ...-->
                                             <!--//do not show unsaleable options-->
                                             <?php if(!$p->isSaleable()) continue; ?>
                                             <?php $out=$p->getAttributeText($pAtt->getName()); ?>
                                             <?php $frontValues[$out]=$out; ?>
                                           <?php endforeach ?>
                                            <option><?php echo implode('</option><option>', $frontValues) ?></option>
                                       </select>
                                   </div>
                               </dd>
                              </li>
                            <?php endforeach ?>
                            </ul>
                          <?php endif ?>
                        <?php endif ?>
                    </div>
                    <!-- End of Configurable Code -->


                    <button type="button" onclick="this.form.submit()"><span><span><span><?php echo $this->__('Add to Cart') ?></span></span></span></button>
                </form>
                <!-- END OF FORM -->

            </div>
        </li>
    <?php endforeach ?>
  • Hi Weddar, I seem to be going down exactly the same path as you, and running into all the same obstacles. I was wondering if you ever got this implementation all sorted out, and if so, if you would mind sharing your working solution here (or at least your final approach). – baku Aug 17 '15 at 18:37
2

Try changing:

<?php echo $att->getAttributeId() ?>

to:

<?php if (is_object($att)) echo $att->getAttributeId() ?>
  • Sorry, it doesn't work. Nothing changes in the HTML of the page and the same error is produced. Somehow the main product is conflicting with the related items. – Weddar Thork May 17 '15 at 9:21
2

This is doable, but it requires a lot of work. You should ask yourself if is is worth the effort ;) I do, sometimes.

You need to ensure all the selectable options are unique. As was mentioned in the answer by @fschmengler you also need to make the forms unique, but I had later found it is best to not use forms, but some javascript that build the form, using data-values from the elements. You may very well get away with using individual forms.

I'll need to note that I did this over 1.5 years ago (I think), and as far as I am aware, works just fine. My exact memory of what was all done is fuzzy, so I am looking at my own code, to remember. I may miss something, so just ask if it seems that way.

So, first you need to render the options. I am not going to go into any details here, as it sounds like you are already doing this. The only issue is that you need to make the ids unique.

If you look at the way I render the options in the gift extension, you can most likely work out how to adjust your product rendering.

html for products display (sorry has to be an image, as there is too much html to paste here.)

enter image description here

The following javascript deals with the add to cart (removed unrelated code)

<script>
    document.observe('dom:loaded', function () {
        $$('.giftselect-btn-cart').each(function (element) {
            element.observe('click', function () {
                if (this.getAttribute('data-type') == 'gift-bundle') {
                    this.disable(true);
                    document.location = this.getAttribute('data-url');
                } else {
                    var giftAddToCartForm = new giftSelect(this.id,
                        this.getAttribute('data-url'),
                        this.getAttribute('data-itemid'),
                        this.getAttribute('data-giftruleid'),
                        this.getAttribute('data-giftkey'),
                        this.getAttribute('data-parentid'),
                        this.getAttribute('data-qty-override'));
                    giftAddToCartForm.submit();
                }
                return false;
            });
        })

    });

    </script>

You will see that I generate a new form of type giftSelect You can find the javascript that defines this here: https://gist.github.com/ProxiBlue/a23774012fd10c747a78

(there will be unrelated code in this file)

You will also see that I use my own controller action of giftAdd. At present I cannot find the code that alters the given data to the super_attribute that is used to define the options selected. Midnight now, and need to get some sleep. Will update here soon.

I do this in my Gift Promotions extension. You can select multiple configurables, with options, handling validation, and dependencies on their options.

enter image description here

I hope this helps, and do ask for any further information.

1

There is no simple solution, but at least I can tell you why it does not work and where you have to make changes:

In the category it's possible because you create the form such that the same add to cart request is send as it would be on the product page.

Related products however are not added to the cart with a separate request, but together with the main product, and in a limited way.

The request parameter related_products is nothing but an array of product ids, and if you look how it is processed, you will be disappointed:

$related = $this->getRequest()->getParam('related_product');
...
if (!empty($related)) {
    $cart->addProductsByIds(explode(',', $related));
}

Source: Mage_Checkout_CartController::addAction()

The addProductsById() method cannot take any additional parameters, so it only works for simple products without custom options.

Steps to a solution

So what you need to do is overriding addAction and use $cart->addProduct() for each related product, passing all parameters for the related product as well.

Also, make sure to avoid conflicts with the form field names (that's the cause of your current error). For example, convert all field names for the related products to the form related[$id][...]

This again will probably require you to override parts of the JavaScript in configurable.js

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.