Skip to content

How to toggle custom tab visibility in product view with event observer based on custom attribute’s value (custom layout handle)?

There is a custom tab “Ask Question” in a product that has a form (it has a logic for saving data to the database).

My task is to create an event observer for the attribute that I have created programmatically via Setup/Patch/Data and remove the tab if the value is set to “No” (“Yes” is the default).

This is my observer:

 <?php

namespace AlexAskQuestionObserver;

use MagentoFrameworkEventObserver;
use MagentoFrameworkEventObserverInterface;
use MagentoCatalogModelProduct;

class AddQuestionTab implements ObserverInterface
{
    /**
     * @param Observer $observer
     * @return void
     */
    public function execute(Observer $observer)
    {
        /** @var Product $product */
        $product = $observer->getEvent()->getData('product');

        // Check if the product has the "allow_to_ask_questions" attribute set to "No"
        if ($product->getData('allow_to_ask_questions') === 0) {
            // Remove the "Ask a Question" tab from the layout
            $layout = $observer->getData('layout');
            $layout->getUpdate()->addHandle('ask_question_form');
        }
    }
}

events.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_product_save_after">
        <observer name="askquestion_tab"
                  instance="AlexAskQuestionObserverAddQuestionTab"
        />
    </event>
    <event name="controller_action_predispatch_catalog_product_view">
        <observer name="alex_ask_question"
                  instance="AlexAskQuestionObserverCatalogControllerProductViewPredispatch"
        />
    </event>
    <event name="catalog_product_load_after">
        <observer name="alex_ask_question"
                  instance="AlexAskQuestionObserverCatalogModelProductLoadAfter"
        />
    </event>
</config>

catalog_product_view.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <update handle="ask_question_form"/>
    <body>
        <referenceBlock name="product.info.details">
            <block class="MagentoCatalogBlockProductView"
                   name="ask.question.tab"
                   as="ask.question"
                   template="Alex_AskQuestion::product/view/ask_question.phtml"
                   group="detailed_info">
                <arguments>
                    <argument translate="true" name="title" xsi:type="string">Ask a question</argument>
                </arguments>
                <block class="AlexAskQuestionBlockQuestions"
                       name="question.list"
                       template="Alex_AskQuestion::product/view/questions_list.phtml">
                    <arguments>
                        <argument name="limit" xsi:type="number">20</argument>
                    </arguments>
                </block>
            </block>
        </referenceBlock>
    </body>
</page>

Installer

<?php

namespace AlexAskQuestionSetupPatchData;

use MagentoCatalogModelProduct;
use MagentoCatalogModelProductAttributeSourceBoolean;
use MagentoEavModelEntityAttributeScopedAttributeInterface;
use MagentoEavSetupEavSetup;
use MagentoEavSetupEavSetupFactory;
use MagentoFrameworkExceptionLocalizedException;
use MagentoFrameworkSetupModuleDataSetupInterface;
use MagentoFrameworkSetupPatchDataPatchInterface;
use MagentoFrameworkValidatorValidateException;

class AddAskQuestionAttribute implements DataPatchInterface
{
    /**
     * @var ModuleDataSetupInterface
     */
    private $moduleDataSetup;

    /**
     * @var EavSetupFactory
     */
    private $eavSetupFactory;

    /**
     * AddAskQuestionAttribute constructor.
     *
     * @param ModuleDataSetupInterface $moduleDataSetup
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(ModuleDataSetupInterface $moduleDataSetup, EavSetupFactory $eavSetupFactory)
    {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * @return void
     * @throws LocalizedException
     * @throws ValidateException
     */
    public function apply()
    {
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);

        $eavSetup->addAttribute(
            Product::ENTITY,
            'allow_to_ask_questions',
            [
                'type' => 'int',
                'backend' => '',
                'frontend' => '',
                'label' => 'Allow to ask question',
                'input' => 'select',
                'class' => '',
                'source' => Boolean::class,
                'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
                'visible' => true,
                'required' => true,
                'sort_order' => 90,
                'user_defined' => false,
                'default' => '1',
                'searchable' => false,
                'filterable' => false,
                'comparable' => false,
                'visible_on_front' => false,
                'used_in_product_listing' => true,
                'unique' => false,
                'apply_to' => ''
            ]
        );
    }

    /**
     * @return array|string[]
     */
    public static function getDependencies(): array
    {
        return [];
    }

    /**
     * @return array|string[]
     */
    public function getAliases(): array
    {
        return [];
    }

    /**
     * @return string
     */
    public static function getVersion(): string
    {
        return '1.0.1';
    }
}