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.

philwinkle
  • 35,751
  • 5
  • 91
  • 145

2 Answers2

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/

philwinkle
  • 35,751
  • 5
  • 91
  • 145
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];
    }
}
Pmclain
  • 2,598
  • 21
  • 22