3

I have 2 or 3 different bundle-type products. Generally they all appear the same in the catalog, with differing attribute sets showing/hiding available options.

It seems there will eventually be a bundle-type product with a vastly different template using a 1-column design as opposed to a 2-columns-right template. My first thought was to use custom layout xml, but all products added to this attribute set in the future will need the template.

2 Answers 2

7

By defining an observer to listen for controller_action_layout_load_before we are able to dynamically add layout handles on product pages based on the loaded product's attribute set:

<?php
class YourCompany_YourModule_Model_Observer
{
    public function addAttributeSetHandle(Varien_Event_Observer $observer)
    {
        $product = Mage::registry('current_product');
 
        /**
         * Return if it is not product page
         */
        if (!($product instanceof Mage_Catalog_Model_Product)) {
            return;
        }
 
        $attributeSet = Mage::getModel('eav/entity_attribute_set')->load($product->getAttributeSetId());
        /**
         * Convert attribute set name to alphanumeric + underscore string
         */
        $niceName = str_replace('-', '_', $product->formatUrlKey($attributeSet->getAttributeSetName()));
 
        /* @var $update Mage_Core_Model_Layout_Update */
        $update = $observer->getEvent()->getLayout()->getUpdate();
        $update->addHandle('PRODUCT_ATTRIBUTE_SET_' . $niceName);
    }
}

And now the following will work in a layout:

<PRODUCT_ATTRIBUTE_SET_shirts>
    <reference name="root">
      <action method="setTemplate"><template>page/view.phtml</template></action>
    </reference>
</PRODUCT_ATTRIBUTE_SET_shirts>

Code and examples sourced: http://magebase.com/magento-tutorials/creating-custom-layout-handles/

0

Magento 2

Layout handles can be added by using a plugin on \Magento\Catalog\Helper\Product\View::initProductLayout

The $params argument can control the order handles are added and subsequently merged when the layout is generated. $params is an optional argument, but should be an instance of Magento\Framework\DataObject when passed.

Handles are added in the following order:

  1. $params->getBeforeHandles()
  2. catalog_product_view_type_{{type}}
  3. catalog_product_view_sku_{{sku}}
  4. $params->getAfterHandles()

Example plugin where a custom layout handle is added based on a product attribute. The new layout handle will apply changes to Magento's core bundle product layout and must be added after catalog_product_view_type_bundle.

etc/frontend/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Catalog\Helper\Product\View">
        <plugin name="custom_module_helper_product_view" type="Vendor\Namespace\Plugin\Helper\Product\View" />
    </type>
</config>

Plugin/Helper/Product/View.php

<?php
declare(strict_types=1);

namespace Vendor\Namespace\Plugin\Helper\Product;

use Magento\Bundle\Model\Product\Type;
use Magento\Framework\DataObject;
use Magento\Framework\DataObjectFactory;

class View
{
    const HANDLE = 'my_custom_handle_for_getting_things_done';

    /**
     * @var DataObjectFactory
     */
    private $dataObjectFactory;

    /**
     * @param DataObjectFactory $dataObjectFactory
     */
    public function __construct(
        DataObjectFactory $dataObjectFactory
    ) {
        $this->dataObjectFactory = $dataObjectFactory;
    }

    /**
     * @param \Magento\Catalog\Helper\Product\View $subject
     * @param \Magento\Framework\View\Result\Page $resultPage
     * @param \Magento\Catalog\Api\Data\ProductInterface $product
     * @param null|DataObject $params
     * @return array
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function beforeInitProductLayout(
        \Magento\Catalog\Helper\Product\View $subject,
        \Magento\Framework\View\Result\Page $resultPage,
        \Magento\Catalog\Api\Data\ProductInterface $product,
        ?DataObject $params = null
    ): array {
        if ($product->getTypeId() !== Type::TYPE_CODE) {
            return [$resultPage, $product, $params];
        }

        if ($params === null) {
            $params = $this->dataObjectFactory->create();
        }

        /*
         * This is an example setting the layout based on a custom
         * attribute. Anything, such as attribute set, could be used 
         * for driving the logic below.
         */
        $simpleKit = $product->getCustomAttribute('some_attribute');
        if ($simpleKit !== null && (bool)$simpleKit->getValue() === true) {
            $afterHandles = $params->getAfterHandles() ?? [];
            $afterHandles[] = self::HANDLE;
            $params->setAfterHandles($afterHandles);
        }

        return [$resultPage, $product, $params];
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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