0

I am trying to create custom tab and have a button which on click its trigger modal window, I tried to create by following this method:https://www.mageworx.com/blog/2016/08/how-to-create-a-modal-window-in-a-custom-field-with-a-code-in-magento-2/

It is not showing any error, I also check logs but it shows nothing and even my custom tab is not displaying on the product edit page.

My di.xml

 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
     <type name="SimpleMagento\ProductCustomerPrice\Ui\DataProvider\Product\Form\Modifier\ProductPrice">
        <arguments>
           <argument name="scopeName" xsi:type="string">product_form.product_form</argument>
        </arguments>
     </type>
     <virtualType name="SimpleMagento\ProductCustomerPrice\Ui\DataProvider\Product\Form\Modifier\Pool" type="Magento\Ui\DataProvider\Modifier\Pool">
        <arguments>
            <argument name="modifiers" xsi:type="array">
                <item name="related" xsi:type="array">
                   <item name="class" xsi:type="string">SimpleMagento\ProductCustomerPrice\Ui\DataProvider\Product\Form\Modifier\ProductPrice</item>
                   <item name="sortOrder" xsi:type="number">110</item>
                </item>
            </argument>
       </arguments>
    </virtualType>
</config>

File: ProductPrice.php

File Path:

SimpleMagento\ProductCustomerPrice\Ui\DataProvider\Product\Form\Modifier\ProductPrice

class ProductPrice extends \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier
{
const CUSTOM_MODAL_LINK = 'custom_modal_link';
const CUSTOM_MODAL_INDEX = 'custom_modal';
const CUSTOM_MODAL_CONTENT = 'content';
const CUSTOM_MODAL_FIELDSET = 'fieldset';
const CONTAINER_HEADER_NAME = 'header';
/**
 * @var LocatorInterface
 */
protected $locator;
/**
 * @var UrlInterface
 */
protected $urlBuilder;
/**
 * @var string
 */
protected $scopeName;
/**
 * @var string
 */
protected $scopePrefix;
/**
 * @var string
 */
private static $previousGroup = 'search-engine-optimization';

/**
 * @var int
 */
private static $sortOrder = 90;

public function __construct(LocatorInterface $locator,
                            UrlInterface $urlBuilder,
                            $scopeName = '',
                            $scopePrefix = '')
{
    $this->locator = $locator;
    $this->urlBuilder = $urlBuilder;
    $this->scopeName = $scopeName;
    $this->scopePrefix = $scopePrefix;
}

/**
 * @param array $data
 * @return array
 * @since 100.1.0
 */
public function modifyData(array $meta)
{
  return $meta;
}

/**
 * @param array $meta
 * @return array
 * @since 100.1.0
 */
public function modifyMeta(array $meta)
{
    $this->meta = $meta;
    $this->addCustomModal();
    $this->addCustomModalLink(10);

    return $this->meta;
}

protected function addCustomModal()
{
    $this->meta = array_merge_recursive(
        $this->meta,
        [
            static::CUSTOM_MODAL_INDEX => $this->getModalConfig(),
        ]
    );
}

protected function getModalConfig()
{
    return [
        'arguments' => [
            'data' => [
                'config' => [
                    'componentType' => Modal::NAME,
                    'dataScope' => '',
                    'provider' => static::FORM_NAME . '.product_form_data_source',
                    'ns' => static::FORM_NAME,
                    'options' => [
                        'title' => __('Modal Title'),
                        'buttons' => [
                            [
                                'text' => __('Save'),
                                'class' => 'action-primary', // additional class
                                'actions' => [
                                    [
                                        'targetName' => 'index = product_form', // Element selector
                                        'actionName' => 'save', // Save parent form (product)
                                    ],
                                    'closeModal', // method name
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        ],
        'children' => [
            static::CUSTOM_MODAL_CONTENT => [
                'arguments' => [
                    'data' => [
                        'config' => [
                            'autoRender' => false,
                            'componentType' => 'container',
                            'dataScope' => 'data.product', // save data in the product data
                            'externalProvider' => 'data.product_data_source',
                            'ns' => static::FORM_NAME,
                            'render_url' => $this->urlBuilder->getUrl('mui/index/render'),
                            'realTimeLink' => true,
                            'behaviourType' => 'edit',
                            'externalFilterMode' => true,
                            'currentProductId' => $this->locator->getProduct()->getId(),
                        ],
                    ],
                ],
                'children' => [
                    static::CUSTOM_MODAL_FIELDSET => [
                        'arguments' => [
                            'data' => [
                                'config' => [
                                    'label' => __('Fieldset'),
                                    'componentType' => Fieldset::NAME,
                                    'dataScope' => 'custom_data',
                                    'collapsible' => true,
                                    'sortOrder' => 10,
                                    'opened' => true,
                                ],
                            ],
                        ],
                        'children' => [
                            static::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
                        ],
                    ],
                ],
            ],
        ],
    ];
}

protected function getHeaderContainerConfig($sortOrder)
{
    return [
        'arguments' => [
            'data' => [
                'config' => [
                    'label' => null,
                    'formElement' => Container::NAME,
                    'componentType' => Container::NAME,
                    'template' => 'ui/form/components/complex',
                    'sortOrder' => $sortOrder,
                    'content' => __('You can write any text here'),
                ],
            ],
        ],
        'children' => [],
    ];
}
protected function addCustomModalLink($sortOrder)
{
    $this->meta = array_replace_recursive(
        $this->meta,
        [
            CustomOptions::GROUP_CUSTOM_OPTIONS_NAME => [
                'children' => [
                    CustomOptions::CONTAINER_HEADER_NAME => [
                        'children' => [
                            static::CUSTOM_MODAL_LINK => [
                                'arguments' => [
                                    'data' => [
                                        'config' => [
                                            'title' => __('Open Custom Modal'),
                                            'formElement' => Container::NAME,
                                            'componentType' => Container::NAME,
                                            'component' => 'Magento_Ui/js/form/components/button',
                                            'actions' => [
                                                [
                                                    'targetName' => 'ns=' . static::FORM_NAME . ', index='
                                                        . static::CUSTOM_MODAL_INDEX, // selector
                                                    'actionName' => 'openModal', // method name
                                                ],
                                            ],
                                            'displayAsLink' => false,
                                            'sortOrder' => $sortOrder,
                                        ],
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        ]
    );
  }
}
  • As I know there is a default modifier called related. Try to change the name in modifier argument from<item name="related" xsi:type="array"> to the <item name="myCustomModal" xsi:type="array">. And please be sure this di.xml is placed inside etc/adminhtml directory – durex Jan 22 '20 at 12:31
  • And the name of the VirtualType you would like to apply the modifier should be name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool". And do not pass type argument for VirtualType because it is passed inside Magento_Catalog's di.xml – durex Jan 22 '20 at 12:36
  • @durex, its in etc/adminhtml, btw nothings change after I make changes as per your suggestion – Sagar Parikh SGR Jan 22 '20 at 12:45
  • So I sure you have some mistakes here, I've tested the code and everything you've made works. Take a look at the screenshots I've attached in the answer below. – durex Jan 22 '20 at 13:44
1

I highly recommend reading the Magento's docs about the Ui Components here at the Magento Docs.

You were trying to put the modal button tab inside Customizable Options section so please check the addCustomModalLink function to understand how to add a custom section.

Also this works only with the Magento 2.2 as I know, when the modifiers support for the Product Form was added.

Be sure your module is enabled inside the global etc/config.php.

There is a default modifier called related. Try to change the name in modifier argument from <item name="related" xsi:type="array"> to the <item name="myCustomModal" xsi:type="array">.

And please be sure this di.xml is placed inside etc/adminhtml directory.

And the name of the VirtualType you would like to apply the modifier should be name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool". And do not pass type argument for VirtualType because it is passed inside Magento_Catalog's di.xml. Also I don't think you need to pass scopeName argument inside your modifier because you don't use it.

The full code is:

app/code/Vendor/Module/etc/adminhtml/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">
    <virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool">
        <arguments>
            <argument name="modifiers" xsi:type="array">
                <item name="myCustomModifier" xsi:type="array">
                    <item name="class" xsi:type="string">Vendor\Module\Ui\DataProvider\Product\Form\Product\Modifier\Modifier</item>
                    <item name="sortOrder" xsi:type="number">110</item>
                </item>
            </argument>
        </arguments>
    </virtualType>
</config>

app/code/Vendor/Module/Ui/DataProvider/Product/Form/Product/Modifier/Modifier.php

<?php

namespace Vendor\Module\Ui\DataProvider\Product\Form\Product\Modifier;

use Magento\Backend\Model\UrlInterface;
use Magento\Catalog\Model\Locator\LocatorInterface;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\CustomOptions;
use Magento\Ui\Component\Container;
use Magento\Ui\Component\Form\Fieldset;
use Magento\Ui\Component\Modal;

class Modifier extends AbstractModifier
{
    const CUSTOM_MODAL_LINK = 'custom_modal_link';
    const CUSTOM_MODAL_INDEX = 'custom_modal';
    const CUSTOM_MODAL_CONTENT = 'content';
    const CUSTOM_MODAL_FIELDSET = 'fieldset';
    const CONTAINER_HEADER_NAME = 'header';
    const CUSTOM_GROUP_NAME = 'my_custom_group';
    const CUSTOM_GROUP_BTN_CONTAINER_NAME = 'my_buttons';
    /**
     * @var LocatorInterface
     */
    protected $locator;
    /**
     * @var UrlInterface
     */
    protected $urlBuilder;
    /**
     * @var string
     */
    protected $scopeName;
    /**
     * @var string
     */
    protected $scopePrefix;
    /**
     * @var string
     */
    private static $previousGroup = 'search-engine-optimization';

    /**
     * @var int
     */
    private static $sortOrder = 90;

    /**
     * @var array
     */
    protected $meta = [];

    /**
     * Modifier constructor.
     * @param LocatorInterface $locator
     * @param UrlInterface $urlBuilder
     */
    public function __construct(
        LocatorInterface $locator,
        UrlInterface $urlBuilder
    ) {
        $this->locator = $locator;
        $this->urlBuilder = $urlBuilder;
    }

    /**
     * @param array $data
     * @return array
     * @since 100.1.0
     */
    public function modifyData(array $data)
    {
        return $data;
    }

    /**
     * @param array $meta
     * @return array
     * @since 100.1.0
     */
    public function modifyMeta(array $meta)
    {
        $this->meta = $meta;
        $this->addCustomModal();
        $this->addCustomModalLink(1000);

        return $this->meta;
    }

    /**
     * @return void
     */
    protected function addCustomModal()
    {
        $this->meta = array_merge_recursive(
            $this->meta,
            [
                static::CUSTOM_MODAL_INDEX => $this->getModalConfig(),
            ]
        );
    }

    /**
     * @return array
     */
    protected function getModalConfig()
    {
        return [
            'arguments' => [
                'data' => [
                    'config' => [
                        'componentType' => Modal::NAME,
                        'dataScope' => '',
                        'provider' => static::FORM_NAME . '.product_form_data_source',
                        'ns' => static::FORM_NAME,
                        'options' => [
                            'title' => __('Modal Title'),
                            'buttons' => [
                                [
                                    'text' => __('Save'),
                                    'class' => 'action-primary', // additional class
                                    'actions' => [
                                        [
                                            'targetName' => 'index = product_form', // Element selector
                                            'actionName' => 'save', // Save parent form (product)
                                        ],
                                        'closeModal', // method name
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
            'children' => [
                static::CUSTOM_MODAL_CONTENT => [
                    'arguments' => [
                        'data' => [
                            'config' => [
                                'autoRender' => false,
                                'componentType' => 'container',
                                'dataScope' => 'data.product', // save data in the product data
                                'externalProvider' => 'data.product_data_source',
                                'ns' => static::FORM_NAME,
                                'render_url' => $this->urlBuilder->getUrl('mui/index/render'),
                                'realTimeLink' => true,
                                'behaviourType' => 'edit',
                                'externalFilterMode' => true,
                                'currentProductId' => $this->locator->getProduct()->getId(),
                            ],
                        ],
                    ],
                    'children' => [
                        static::CUSTOM_MODAL_FIELDSET => [
                            'arguments' => [
                                'data' => [
                                    'config' => [
                                        'label' => __('Fieldset'),
                                        'componentType' => Fieldset::NAME,
                                        'dataScope' => 'custom_data',
                                        'collapsible' => true,
                                        'sortOrder' => 10,
                                        'opened' => true,
                                    ],
                                ],
                            ],
                            'children' => [
                                static::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
                            ],
                        ],
                    ],
                ],
            ],
        ];
    }

    /**
     * @param $sortOrder
     * @return array
     */
    protected function getHeaderContainerConfig($sortOrder)
    {
        return [
            'arguments' => [
                'data' => [
                    'config' => [
                        'label' => null,
                        'formElement' => Container::NAME,
                        'componentType' => Container::NAME,
                        'template' => 'ui/form/components/complex',
                        'sortOrder' => $sortOrder,
                        'content' => __('You can write any text here'),
                    ],
                ],
            ],
            'children' => [],
        ];
    }

    /**
     * @param $sortOrder
     * @return void
     */
    protected function addCustomModalLink($sortOrder)
    {
        $this->meta = array_replace_recursive(
            $this->meta,
            [
                static::CUSTOM_GROUP_NAME => [
                    'arguments' => [
                        'data' => [
                            'config' => [
                                'label' => __('My Group Fieldset'),
                                'componentType' => Fieldset::NAME,
                                'collapsible' => true,
                                'sortOrder' => $sortOrder,
                                'opened' => true,
                            ],
                        ],
                    ],
                    'children' => [
                        self::CUSTOM_GROUP_BTN_CONTAINER_NAME => [
                            'arguments' => [
                                'data' => [
                                    'config' => [
                                        'label' => null,
                                        'formElement' => Container::NAME,
                                        'componentType' => Container::NAME,
                                        'template' => 'ui/form/components/complex',
                                        'sortOrder' => 10,
                                        'content' => __('There are your buttons inside children section.'),
                                    ],
                                ],
                            ],
                            'children' => [
                                static::CUSTOM_MODAL_LINK => [
                                    'arguments' => [
                                        'data' => [
                                            'config' => [
                                                'title' => __('Open Custom Modal'),
                                                'formElement' => Container::NAME,
                                                'componentType' => Container::NAME,
                                                'component' => 'Magento_Ui/js/form/components/button',
                                                'actions' => [
                                                    [
                                                        'targetName' => 'ns=' . static::FORM_NAME . ', index='
                                                            . static::CUSTOM_MODAL_INDEX, // selector
                                                        'actionName' => 'openModal', // method name
                                                    ],
                                                ],
                                                'displayAsLink' => false,
                                                'sortOrder' => 10,
                                            ],
                                        ],
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ]
        );
    }
}

app/code/Vendor/Module/registration.php

<?php

use \Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Vendor_Module', __DIR__);

app/code/Vendor/Module/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Vendor_Module"/>
</config>

There are screenshots.

The button

The modal

  • app/code/Vendor/Module/DataProvider/Ui/Product/Form/Product/Modifier/Modifier.php, are you sure regarding this path? I think Ui/DataProvider will be right – Sagar Parikh SGR Jan 22 '20 at 13:53
  • @SagarParikhSGR Oh sorry I accidentally mixed up it with DataProvider and Ui. The correct path is app/code/Vendor/Module/Ui/DataProvider/Product/Form/Product/Modifier/Modifier.php – durex Jan 22 '20 at 13:55
  • You can place it whatever you want though. Just don't forget to change the namespace and the declaration of it inside di.xml – durex Jan 22 '20 at 13:56
  • but why the button show in customizable options? I am try to create custom tab and if someone open the tab, its shows the button for the popup window, a similar feature like Related Products, Up-Sells, and Cross-Sells tab – Sagar Parikh SGR Jan 22 '20 at 14:07
  • I understand I follow the wrong tutorial for it, can you please help for how I can achieve this functionality ? – Sagar Parikh SGR Jan 22 '20 at 14:10

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.