Question

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,
                                        ],
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        ]
    );
  }
}
Was it helpful?

Solution

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

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top