{"id":298356,"date":"2021-07-29T09:45:05","date_gmt":"2021-07-29T09:45:05","guid":{"rendered":"https:\/\/webkul.com\/blog\/?p=298356"},"modified":"2021-08-26T08:02:03","modified_gmt":"2021-08-26T08:02:03","slug":"create-custom-link-product-type-magento2","status":"publish","type":"post","link":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/","title":{"rendered":"Custom Linked Product Types Magento2"},"content":{"rendered":"\n<p>Let&#8217;s suppose we need to add a product collection on the product view page and we want the admin to add those products on the basis of some specifications, so for that, we can use custom linked product types like Related products. <\/p>\n\n\n\n<p>Today we are going to see how can we create a custom product link in Magento 2. So, first of all, create basic module files like module.xml and resgistration.php to register the module (in this tutorial our module&#8217;s name will be Webkul_CustomLink). <\/p>\n\n\n\n<p>Now, to create a custom product link type, we need to add its entry in catalog_product_link_type and catalog_product_link_attribute tables, then create modifier (to add it on product edit page), model (to get linked product collection from catalog product model), and ui_component.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Develop Data Patch for Custom Linked Product Types<\/h2>\n\n\n\n<p>So let&#8217;s begin with schema patch, create a file &#8211;<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Webkul\/CustomLink\/Setup\/Patch\/Data\/CreateLink.php<\/h4>\n\n\n\n<p>The schema patch file will make an entry for our custom linked product type in the database.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\nnamespace Webkul\\CustomLink\\Setup\\Patch\\Data;\n\nuse Magento\\Framework\\Setup\\InstallDataInterface;\nuse Magento\\Framework\\Setup\\ModuleContextInterface;\nuse Magento\\Framework\\Setup\\ModuleDataSetupInterface;\nuse Magento\\Framework\\Setup\\Patch\\DataPatchInterface;\n\nclass CreateLink implements DataPatchInterface\n{\n    \/**\n     * @param ModuleDataSetupInterface $moduleDataSetup\n     *\/\n    public function __construct(\n        ModuleDataSetupInterface $moduleDataSetup\n    ) {\n        $this-&gt;moduleDataSetup = $moduleDataSetup;\n    }\n\n    public function apply()\n    {\n        $setup = $this-&gt;moduleDataSetup;\n\n        $data = &#091;\n            &#091;\n                &#039;link_type_id&#039; =&gt; \\Webkul\\CustomLink\\Model\\Product\\Link::LINK_TYPE_CUSTOMLINK,\n                &#039;code&#039; =&gt; &#039;customlink&#039;\n            ],\n        ];\n\n        foreach ($data as $bind) {\n            $setup-&gt;getConnection()\n                -&gt;insertForce($setup-&gt;getTable(&#039;catalog_product_link_type&#039;), $bind);\n        }\n        $data = &#091;\n            &#091;\n                &#039;link_type_id&#039; =&gt; \\Webkul\\CustomLink\\Model\\Product\\Link::LINK_TYPE_CUSTOMLINK,\n                &#039;product_link_attribute_code&#039; =&gt; &#039;position&#039;,\n                &#039;data_type&#039; =&gt; &#039;int&#039;,\n            ]\n        ];\n        $setup-&gt;getConnection()\n            -&gt;insertMultiple($setup-&gt;getTable(&#039;catalog_product_link_attribute&#039;), $data);\n    }\n\n    \/**\n     * {@inheritdoc}\n     *\/\n    public static function getDependencies()\n    {\n        return &#091;];\n    }\n\n    \/**\n     * {@inheritdoc}\n     *\/\n    public function getAliases()\n    {\n        return &#091;];\n    }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Create Custom Linked Product Types Model<\/h2>\n\n\n\n<p>Now create custom link products model file &#8211;<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Webkul\/CustomLink\/Model\/Product.php<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\nnamespace Webkul\\CustomLink\\Model;\n\nclass Product extends \\Magento\\Catalog\\Model\\Product\n{\n    const LINK_TYPE = &#039;customlink&#039;;\n    const LINK_TYPE_CUSTOMLINK = 7;\n\n    \/**\n     * Retrieve array of customlink products\n     *\n     * @return array\n     *\/\n    public function getCustomLinkProducts()\n    {\n        if (!$this-&gt;hasCustomLinkProducts()) {\n            $products = &#091;];\n            $collection = $this-&gt;getCustomLinkProductCollection();\n            foreach ($collection as $product) {\n                $products&#091;] = $product;\n            }\n            $this-&gt;setCustomLinkProducts($products);\n        }\n        return $this-&gt;getData(&#039;custom_link_products&#039;);\n    }\n\n    \/**\n     * Retrieve customlink products identifiers\n     *\n     * @return array\n     *\/\n    public function getCustomLinkProductIds()\n    {\n        if (!$this-&gt;hasCustomLinkProductIds()) {\n            $ids = &#091;];\n            foreach ($this-&gt;getCustomLinkProducts() as $product) {\n                $ids&#091;] = $product-&gt;getId();\n            }\n            $this-&gt;setCustomLinkProductIds($ids);\n        }\n        return &#091;$this-&gt;getData(&#039;custom_link_product_ids&#039;)];\n    }\n\n    \/**\n     * Retrieve collection customlink product\n     *\n     * @return \\Magento\\Catalog\\Model\\ResourceModel\\Product\\Link\\Product\\Collection\n     *\/\n    public function getCustomLinkProductCollection()\n    {\n        $collection = $this-&gt;getLinkInstance()-&gt;setLinkTypeId(\n            static::LINK_TYPE_CUSTOMLINK\n        )-&gt;getProductCollection()-&gt;setIsStrongMode();\n        $collection-&gt;setProduct($this);\n\n        return $collection;\n    }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Inject LinkProvider Dependencies<\/h2>\n\n\n\n<p>To create a custom product link, we need to inject some dependencies to core link provider classes, so create the following di.xml for that.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Webkul\/CustomLink\/etc\/di.xml<\/h4>\n\n\n\n<p>Inject required dependencies in the di.xml file.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?xml version=&quot;1.0&quot;?&gt;\n&lt;config xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot; xsi:noNamespaceSchemaLocation=&quot;urn:magento:framework:ObjectManager\/etc\/config.xsd&quot;&gt;\n     &lt;type name=&quot;Magento\\Catalog\\Model\\Product\\LinkTypeProvider&quot;&gt;\n        &lt;arguments&gt;\n            &lt;argument name=&quot;linkTypes&quot; xsi:type=&quot;array&quot;&gt;\n                &lt;item name=&quot;customlink&quot; xsi:type=&quot;const&quot;&gt;Webkul\\CustomLink\\Model\\Product\\Link::LINK_TYPE_CUSTOMLINK&lt;\/item&gt;\n            &lt;\/argument&gt;\n        &lt;\/arguments&gt;\n    &lt;\/type&gt;\n    &lt;type name=&quot;Magento\\Catalog\\Model\\ProductLink\\CollectionProvider&quot;&gt;\n        &lt;arguments&gt;\n            &lt;argument name=&quot;providers&quot; xsi:type=&quot;array&quot;&gt;\n                &lt;item name=&quot;customlink&quot; xsi:type=&quot;object&quot;&gt;Webkul\\CustomLink\\Model\\ProductLink\\CollectionProvider\\CustomLinkProducts&lt;\/item&gt;\n            &lt;\/argument&gt;\n        &lt;\/arguments&gt;\n    &lt;\/type&gt;\n    &lt;!-- Plugin to add update argument in collectionProvider --&gt;\n    &lt;type name=&quot;Webkul\\CustomLink\\Model\\ProductLink\\CollectionProvider\\CustomLinkProducts&quot;&gt;\n        &lt;plugin name=&quot;change_custom_link_before&quot; type=&quot;Webkul\\CustomLink\\Plugin\\UpdateToCustomLinkModel&quot;\/&gt;\n    &lt;\/type&gt;\n&lt;\/config&gt;<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Create Injected Model files<\/h2>\n\n\n\n<p>Create the following model files &#8211;<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Webkul\/CustomLink\/Model\/Product\/Link.php<\/h4>\n\n\n\n<p>Link provider class.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\n\/**\n\n * Webkul Software.\n *\n * @category  Webkul\n * @package   Webkul_CustomLink\n * @author    Webkul\n * @copyright Copyright (c) Webkul Software Private Limited (https:\/\/webkul.com)\n * @license   https:\/\/store.webkul.com\/license.html\n *\/\n\nnamespace Webkul\\CustomLink\\Model\\Product;\n\nclass Link extends \\Magento\\Catalog\\Model\\Product\\Link\n{\n    const LINK_TYPE_CUSTOMLINK = 7;\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Webkul\/CustomLink\/Model\/ProductLink\/CollectionProvider\/CustomLinkProducts.php<\/h4>\n\n\n\n<p>The custom link collection provider class.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\nnamespace Webkul\\CustomLink\\Model\\ProductLink\\CollectionProvider;\n\nclass CustomLinkProducts\n{\n    public function getLinkedProducts($product)\n    {\n        return $product-&gt;getCustomLinkProducts();\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Webkul\/CustomLink\/Plugin\/UpdateToCustomLinkModel.php<\/h4>\n\n\n\n<p>In the above CollectionProvider, the $product param in the getLinkedProducts function is an instance of Magento\\Catalog\\Model\\Product, we need to update it to our custom product link model, i.e., Webkul\\CustomLink\\Model\\Product.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\nnamespace Webkul\\CustomLink\\Plugin;\n\nclass UpdateToCustomLinkModel\n{\n    \/**\n     * @param \\Webkul\\CustomLink\\Model\\ProductFactory $catalogModel\n     *\/\n    public function __construct(\n        \\Webkul\\CustomLink\\Model\\ProductFactory $catalogModel\n    ) {\n        $this-&gt;catalogModel = $catalogModel;\n    }\n    \n    \/**\n     * Before plugin to update model class\n     *\n     * @param \\Webkul\\CustomLink\\Model\\ProductLink\\CollectionProvider\\CustomLinkProducts $subject\n     * @param Object $product\n     * @return array\n     *\/\n    public function beforeGetLinkedProducts(\n        \\Webkul\\CustomLink\\Model\\ProductLink\\CollectionProvider\\CustomLinkProducts $subject,\n        $product\n    ) {\n        $currentProduct = $this-&gt;catalogModel-&gt;create()-&gt;load($product-&gt;getId());\n        return &#091;$currentProduct];\n    }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Create UI grid for Custom Linked Product Type<\/h2>\n\n\n\n<p>Now we are left with two parts, first one is ui_component to show columns, filters, etc. and the second one is modifiers to add dynamic data &amp; validations to ui_component values. So for that, we need to create the following  di.xml, modifier file, and component file.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Webkul\/CustomLink\/etc\/adminhtml\/di.xml<\/h4>\n\n\n\n<p>Inject our modifier class to the modifiers pool.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?xml version=&quot;1.0&quot;?&gt;\n\n&lt;config xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot; xsi:noNamespaceSchemaLocation=&quot;urn:magento:framework:ObjectManager\/etc\/config.xsd&quot;&gt;\n    &lt;virtualType name=&quot;Magento\\Catalog\\Ui\\DataProvider\\Product\\Form\\Modifier\\Pool&quot;&gt;\n        &lt;arguments&gt;\n            &lt;argument name=&quot;modifiers&quot; xsi:type=&quot;array&quot;&gt;\n                &lt;item name=&quot;customlink&quot; xsi:type=&quot;array&quot;&gt;\n                    &lt;item name=&quot;class&quot; xsi:type=&quot;string&quot;&gt;Webkul\\CustomLink\\Ui\\DataProvider\\Product\\Form\\Modifier\\CustomLinkTab&lt;\/item&gt;\n                    &lt;item name=&quot;sortOrder&quot; xsi:type=&quot;number&quot;&gt;7&lt;\/item&gt;\n                &lt;\/item&gt;\n            &lt;\/argument&gt;\n        &lt;\/arguments&gt;\n    &lt;\/virtualType&gt;\n&lt;\/config&gt;<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Webkul\/CustomLink\/Ui\/DataProvider\/Product\/Form\/Modifier\/CustomLinkTab.php<\/h4>\n\n\n\n<p>Here I am creating a whole modifier class just to elaborate how inner grids are working, you can simply add a plugin class also of Related product&#8217;s modifier and create afterModifyMeta &amp; afterModifyData methods to customize UI.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\nnamespace Webkul\\CustomLink\\Ui\\DataProvider\\Product\\Form\\Modifier;\n\nuse Magento\\Catalog\\Model\\Locator\\LocatorInterface;\nuse Magento\\Catalog\\Ui\\DataProvider\\Product\\Form\\Modifier\\AbstractModifier;\nuse Magento\\Framework\\Stdlib\\ArrayManager;\nuse Magento\\Framework\\UrlInterface;\nuse Magento\\Ui\\Component\\Container;\nuse Magento\\Ui\\Component\\Form\\Fieldset;\nuse Magento\\Ui\\Component\\Modal;\nuse Magento\\Framework\\Phrase;\nuse Magento\\Ui\\Component\\DynamicRows;\nuse Magento\\Ui\\Component\\Form\\Element\\DataType\\Number;\nuse Magento\\Ui\\Component\\Form\\Element\\DataType\\Text;\nuse Magento\\Ui\\Component\\Form\\Field;\nuse Magento\\Ui\\Component\\Form\\Element\\Input;\nuse Magento\\Framework\\App\\ObjectManager;\nuse Magento\\Catalog\\Api\\Data\\ProductInterface;\nuse Magento\\Catalog\\Api\\Data\\ProductLinkInterface;\nuse Magento\\Catalog\\Api\\ProductLinkRepositoryInterface;\nuse Magento\\Catalog\\Api\\ProductRepositoryInterface;\nuse Magento\\Catalog\\Helper\\Image as ImageHelper;\nuse Magento\\Catalog\\Model\\Product\\Attribute\\Source\\Status;\nuse Magento\\Eav\\Api\\AttributeSetRepositoryInterface;\n\nclass CustomLinkTab extends AbstractModifier\n{\n    const DATA_SCOPE_CUSTOM = &#039;customlink&#039;;\n    const GROUP_CUSTOM = &#039;customlink&#039;;\n    \n    protected $meta = &#091;];\n    protected $scopeName = &#039;product_form.product_form&#039;;\n    protected $scopePrefix = &#039;&#039;;\n    private $priceModifier;\n\n    \/**\n     * @param LocatorInterface $locator\n     * @param ArrayManager $arrayManager\n     * @param UrlInterface $urlBuilder\n     * @param \\Magento\\Catalog\\Model\\ProductFactory $_productloader\n     * @param \\Magento\\Backend\\Model\\UrlInterface $backendUrl\n     *\/\n    public function __construct(\n        LocatorInterface $locator,\n        ArrayManager $arrayManager,\n        UrlInterface $urlBuilder,\n        ProductLinkRepositoryInterface $productLinkRepository,\n        ProductRepositoryInterface $productRepository,\n        ImageHelper $imageHelper,\n        Status $status,\n        AttributeSetRepositoryInterface $attributeSetRepository,\n        \\Magento\\Catalog\\Model\\ProductFactory $_productloader,\n        \\Magento\\Backend\\Model\\UrlInterface $backendUrl\n    ) {\n        $this-&gt;locator = $locator;\n        $this-&gt;arrayManager = $arrayManager;\n        $this-&gt;productLinkRepository = $productLinkRepository;\n        $this-&gt;productRepository = $productRepository;\n        $this-&gt;imageHelper = $imageHelper;\n        $this-&gt;status = $status;\n        $this-&gt;attributeSetRepository = $attributeSetRepository;\n        $this-&gt;urlBuilder = $urlBuilder;\n        $this-&gt;_productloader = $_productloader;\n        $this-&gt;_backendUrl = $backendUrl;\n    }\n\n    public function modifyData(array $data)\n    {\n        \/** @var \\Magento\\Catalog\\Model\\Product $product *\/\n        $product = $this-&gt;locator-&gt;getProduct();\n        $productId = $product-&gt;getId();\n\n        if (!$productId) {\n            return $data;\n        }\n\n        $priceModifier = $this-&gt;getPriceModifier();\n        \/**\n         * Set field name for modifier\n         *\/\n        $priceModifier-&gt;setData(&#039;name&#039;, &#039;price&#039;);\n        $dataScope = static::DATA_SCOPE_CUSTOM;\n\n        $data&#091;$productId]&#091;&#039;links&#039;]&#091;$dataScope] = &#091;];\n        foreach ($this-&gt;productLinkRepository-&gt;getList($product) as $linkItem) {\n            if ($linkItem-&gt;getLinkType() !== $dataScope) {\n                continue;\n            }\n\n            \/** @var \\Magento\\Catalog\\Model\\Product $linkedProduct *\/\n            $linkedProduct = $this-&gt;productRepository-&gt;get(\n                $linkItem-&gt;getLinkedProductSku(),\n                false,\n                $this-&gt;locator-&gt;getStore()-&gt;getId()\n            );\n            $data&#091;$productId]&#091;&#039;links&#039;]&#091;$dataScope]&#091;] = $this-&gt;fillData($linkedProduct, $linkItem);\n        }\n        if (!empty($data&#091;$productId]&#091;&#039;links&#039;]&#091;$dataScope])) {\n            $dataMap = $priceModifier-&gt;prepareDataSource(&#091;\n                &#039;data&#039; =&gt; &#091;\n                    &#039;items&#039; =&gt; $data&#091;$productId]&#091;&#039;links&#039;]&#091;$dataScope]\n                ]\n            ]);\n            $data&#091;$productId]&#091;&#039;links&#039;]&#091;$dataScope] = $dataMap&#091;&#039;data&#039;]&#091;&#039;items&#039;];\n        }\n\n        $data&#091;$productId]&#091;self::DATA_SOURCE_DEFAULT]&#091;&#039;current_product_id&#039;] = $productId;\n        $data&#091;$productId]&#091;self::DATA_SOURCE_DEFAULT]&#091;&#039;current_store_id&#039;] = $this-&gt;locator-&gt;getStore()-&gt;getId();\n\n        return $data;\n    }\n\n    private function getPriceModifier()\n    {\n        if (!$this-&gt;priceModifier) {\n            $this-&gt;priceModifier = ObjectManager::getInstance()-&gt;get(\n                \\Magento\\Catalog\\Ui\\Component\\Listing\\Columns\\Price::class\n            );\n        }\n        return $this-&gt;priceModifier;\n    }\n  \n    public function modifyMeta(array $meta)\n    {\n        $this-&gt;meta = $meta;\n        $this-&gt;addCustomTab();\n  \n        return $this-&gt;meta;\n    }\n  \n    protected function addCustomTab()\n    {\n        $this-&gt;meta = array_merge_recursive(\n            $this-&gt;meta,\n            &#091;\n                static::GROUP_CUSTOM =&gt; $this-&gt;getTabConfig(),\n            ]\n        );\n    }\n  \n    protected function getTabConfig()\n    {\n        return &#091;\n            &#039;arguments&#039; =&gt; &#091;\n                &#039;data&#039; =&gt; &#091;\n                    &#039;config&#039; =&gt; &#091;\n                        &#039;label&#039; =&gt; __(&#039;Custom Link Products&#039;),\n                        &#039;componentType&#039; =&gt; Fieldset::NAME,\n                        &#039;sortOrder&#039; =&gt; 40,\n                        &#039;dataScope&#039; =&gt; &#039;&#039;,\n                        &#039;provider&#039; =&gt; static::FORM_NAME . &#039;.product_form_data_source&#039;,\n                        &#039;ns&#039; =&gt; static::FORM_NAME,\n                        &#039;collapsible&#039; =&gt; true,\n                    ],\n                ],\n            ],\n            &#039;children&#039; =&gt; &#091;\n                $this-&gt;scopePrefix . static::DATA_SCOPE_CUSTOM =&gt; $this-&gt;getCustomFieldset(),\n            ],\n        ];\n    }\n\n    \/**\n     * Prepare data column\n     *\n     * @param ProductInterface $linkedProduct\n     * @param ProductLinkInterface $linkItem\n     * @return array\n     * @since 101.0.0\n     *\/\n    protected function fillData(ProductInterface $linkedProduct, ProductLinkInterface $linkItem)\n    {\n        return &#091;\n            &#039;id&#039; =&gt; $linkedProduct-&gt;getId(),\n            &#039;thumbnail&#039; =&gt; $this-&gt;imageHelper-&gt;init($linkedProduct, &#039;product_listing_thumbnail&#039;)-&gt;getUrl(),\n            &#039;name&#039; =&gt; $linkedProduct-&gt;getName(),\n            &#039;status&#039; =&gt; $this-&gt;status-&gt;getOptionText($linkedProduct-&gt;getStatus()),\n            &#039;attribute_set&#039; =&gt; $this-&gt;attributeSetRepository\n                -&gt;get($linkedProduct-&gt;getAttributeSetId())\n                -&gt;getAttributeSetName(),\n            &#039;sku&#039; =&gt; $linkItem-&gt;getLinkedProductSku(),\n            &#039;price&#039; =&gt; $linkedProduct-&gt;getPrice(),\n            &#039;position&#039; =&gt; $linkItem-&gt;getPosition(),\n        ];\n    }\n\n    protected function getCustomFieldset()\n    {\n        $content = __(\n            &#039;Custom Link products are shown to customers as addons to the item the customer is looking at.&#039;\n        );\n\n        return &#091;\n            &#039;children&#039; =&gt; &#091;\n                &#039;button_set&#039; =&gt; $this-&gt;getButtonSet(\n                    $content,\n                    __(&#039;Add Custom Link Products&#039;),\n                    $this-&gt;scopePrefix . static::DATA_SCOPE_CUSTOM\n                ),\n                &#039;modal&#039; =&gt; $this-&gt;getGenericModal(\n                    __(&#039;Add Custom Link Products&#039;),\n                    $this-&gt;scopePrefix . static::DATA_SCOPE_CUSTOM\n                ),\n                static::DATA_SCOPE_CUSTOM =&gt; $this-&gt;getGrid($this-&gt;scopePrefix . static::DATA_SCOPE_CUSTOM),\n            ],\n            &#039;arguments&#039; =&gt; &#091;\n                &#039;data&#039; =&gt; &#091;\n                    &#039;config&#039; =&gt; &#091;\n                        &#039;additionalClasses&#039; =&gt; &#039;admin__fieldset-section&#039;,\n                        &#039;label&#039; =&gt; __(&#039;Add Custom Link Products&#039;),\n                        &#039;collapsible&#039; =&gt; false,\n                        &#039;componentType&#039; =&gt; Fieldset::NAME,\n                        &#039;dataScope&#039; =&gt; &#039;&#039;,\n                        &#039;sortOrder&#039; =&gt; 10,\n                    ],\n                ],\n            ]\n        ];\n    }\n\n    \/**\n     * Retrieve button set\n     *\n     * @param Phrase $content\n     * @param Phrase $buttonTitle\n     * @param string $scope\n     * @return array\n     * @since 101.0.0\n     *\/\n    protected function getButtonSet(Phrase $content, Phrase $buttonTitle, $scope)\n    {\n        $modalTarget = $this-&gt;scopeName . &#039;.&#039; . static::GROUP_CUSTOM . &#039;.&#039; . $scope . &#039;.modal&#039;;\n\n        return &#091;\n            &#039;arguments&#039; =&gt; &#091;\n                &#039;data&#039; =&gt; &#091;\n                    &#039;config&#039; =&gt; &#091;\n                        &#039;formElement&#039; =&gt; &#039;container&#039;,\n                        &#039;componentType&#039; =&gt; &#039;container&#039;,\n                        &#039;label&#039; =&gt; false,\n                        &#039;content&#039; =&gt; $content,\n                        &#039;template&#039; =&gt; &#039;ui\/form\/components\/complex&#039;,\n                    ],\n                ],\n            ],\n            &#039;children&#039; =&gt; &#091;\n                &#039;button_&#039; . $scope =&gt; &#091;\n                    &#039;arguments&#039; =&gt; &#091;\n                        &#039;data&#039; =&gt; &#091;\n                            &#039;config&#039; =&gt; &#091;\n                                &#039;formElement&#039; =&gt; &#039;container&#039;,\n                                &#039;componentType&#039; =&gt; &#039;container&#039;,\n                                &#039;component&#039; =&gt; &#039;Magento_Ui\/js\/form\/components\/button&#039;,\n                                &#039;actions&#039; =&gt; &#091;\n                                    &#091;\n                                        &#039;targetName&#039; =&gt; $modalTarget,\n                                        &#039;actionName&#039; =&gt; &#039;toggleModal&#039;,\n                                    ],\n                                    &#091;\n                                        &#039;targetName&#039; =&gt; $modalTarget . &#039;.&#039; . $scope . &#039;_product_listing&#039;,\n                                        &#039;actionName&#039; =&gt; &#039;render&#039;,\n                                    ]\n                                ],\n                                &#039;title&#039; =&gt; $buttonTitle,\n                                &#039;provider&#039; =&gt; null,\n                            ],\n                        ],\n                    ],\n\n                ],\n            ],\n        ];\n    }\n\n    \/**\n     * Prepares config for modal slide-out panel\n     *\n     * @param Phrase $title\n     * @param string $scope\n     * @return array\n     * @since 101.0.0\n     *\/\n    protected function getGenericModal(Phrase $title, $scope)\n    {\n        $listingTarget = $scope . &#039;_product_listing&#039;;\n\n        $modal = &#091;\n            &#039;arguments&#039; =&gt; &#091;\n                &#039;data&#039; =&gt; &#091;\n                    &#039;config&#039; =&gt; &#091;\n                        &#039;componentType&#039; =&gt; Modal::NAME,\n                        &#039;dataScope&#039; =&gt; &#039;&#039;,\n                        &#039;options&#039; =&gt; &#091;\n                            &#039;title&#039; =&gt; $title,\n                            &#039;buttons&#039; =&gt; &#091;\n                                &#091;\n                                    &#039;text&#039; =&gt; __(&#039;Cancel&#039;),\n                                    &#039;actions&#039; =&gt; &#091;\n                                        &#039;closeModal&#039;\n                                    ]\n                                ],\n                                &#091;\n                                    &#039;text&#039; =&gt; __(&#039;Add Selected Products&#039;),\n                                    &#039;class&#039; =&gt; &#039;action-primary&#039;,\n                                    &#039;actions&#039; =&gt; &#091;\n                                        &#091;\n                                            &#039;targetName&#039; =&gt; &#039;index = &#039; . $listingTarget,\n                                            &#039;actionName&#039; =&gt; &#039;save&#039;\n                                        ],\n                                        &#039;closeModal&#039;\n                                    ]\n                                ],\n                            ],\n                        ],\n                    ],\n                ],\n            ],\n            &#039;children&#039; =&gt; &#091;\n                $listingTarget =&gt; &#091;\n                    &#039;arguments&#039; =&gt; &#091;\n                        &#039;data&#039; =&gt; &#091;\n                            &#039;config&#039; =&gt; &#091;\n                                &#039;autoRender&#039; =&gt; false,\n                                &#039;componentType&#039; =&gt; &#039;insertListing&#039;,\n                                &#039;dataScope&#039; =&gt; $listingTarget,\n                                &#039;externalProvider&#039; =&gt; $listingTarget . &#039;.&#039; . $listingTarget . &#039;_data_source&#039;,\n                                &#039;selectionsProvider&#039; =&gt; $listingTarget . &#039;.&#039; . $listingTarget . &#039;.product_columns.ids&#039;,\n                                &#039;ns&#039; =&gt; $listingTarget,\n                                &#039;render_url&#039; =&gt; $this-&gt;urlBuilder-&gt;getUrl(&#039;mui\/index\/render&#039;),\n                                &#039;realTimeLink&#039; =&gt; true,\n                                &#039;dataLinks&#039; =&gt; &#091;\n                                    &#039;imports&#039; =&gt; false,\n                                    &#039;exports&#039; =&gt; true\n                                ],\n                                &#039;behaviourType&#039; =&gt; &#039;simple&#039;,\n                                &#039;externalFilterMode&#039; =&gt; true,\n                                &#039;imports&#039; =&gt; &#091;\n                                    &#039;productId&#039; =&gt; &#039;${ $.provider }:data.product.current_product_id&#039;,\n                                    &#039;storeId&#039; =&gt; &#039;${ $.provider }:data.product.current_store_id&#039;,\n                                    &#039;__disableTmpl&#039; =&gt; &#091;&#039;productId&#039; =&gt; false, &#039;storeId&#039; =&gt; false],\n                                ],\n                                &#039;exports&#039; =&gt; &#091;\n                                    &#039;productId&#039; =&gt; &#039;${ $.externalProvider }:params.current_product_id&#039;,\n                                    &#039;storeId&#039; =&gt; &#039;${ $.externalProvider }:params.current_store_id&#039;,\n                                    &#039;__disableTmpl&#039; =&gt; &#091;&#039;productId&#039; =&gt; false, &#039;storeId&#039; =&gt; false],\n                                ]\n                            ],\n                        ],\n                    ],\n                ],\n            ],\n        ];\n\n        return $modal;\n    }\n\n    \/**\n     * Retrieve grid\n     *\n     * @param string $scope\n     * @return array\n     *\/\n    protected function getGrid($scope)\n    {\n        $dataProvider = $scope . &#039;_product_listing&#039;;\n\n        return &#091;\n            &#039;arguments&#039; =&gt; &#091;\n                &#039;data&#039; =&gt; &#091;\n                    &#039;config&#039; =&gt; &#091;\n                        &#039;additionalClasses&#039; =&gt; &#039;admin__field-wide&#039;,\n                        &#039;componentType&#039; =&gt; DynamicRows::NAME,\n                        &#039;label&#039; =&gt; null,\n                        &#039;columnsHeader&#039; =&gt; false,\n                        &#039;columnsHeaderAfterRender&#039; =&gt; true,\n                        &#039;renderDefaultRecord&#039; =&gt; false,\n                        &#039;template&#039; =&gt; &#039;ui\/dynamic-rows\/templates\/grid&#039;,\n                        &#039;component&#039; =&gt; &#039;Magento_Ui\/js\/dynamic-rows\/dynamic-rows-grid&#039;,\n                        &#039;addButton&#039; =&gt; false,\n                        &#039;recordTemplate&#039; =&gt; &#039;record&#039;,\n                        &#039;dataScope&#039; =&gt; &#039;data.links&#039;,\n                        &#039;deleteButtonLabel&#039; =&gt; __(&#039;Remove&#039;),\n                        &#039;dataProvider&#039; =&gt; $dataProvider,\n                        &#039;map&#039; =&gt; &#091;\n                            &#039;id&#039; =&gt; &#039;entity_id&#039;,\n                            &#039;name&#039; =&gt; &#039;name&#039;,\n                            &#039;status&#039; =&gt; &#039;status_text&#039;,\n                            &#039;attribute_set&#039; =&gt; &#039;attribute_set_text&#039;,\n                            &#039;sku&#039; =&gt; &#039;sku&#039;,\n                            &#039;price&#039; =&gt; &#039;price&#039;,\n                            &#039;thumbnail&#039; =&gt; &#039;thumbnail_src&#039;,\n                        ],\n                        &#039;links&#039; =&gt; &#091;\n                            &#039;insertData&#039; =&gt; &#039;${ $.provider }:${ $.dataProvider }&#039;,\n                            &#039;__disableTmpl&#039; =&gt; &#091;&#039;insertData&#039; =&gt; false],\n                        ],\n                        &#039;sortOrder&#039; =&gt; 2,\n                    ],\n                ],\n            ],\n            &#039;children&#039; =&gt; &#091;\n                &#039;record&#039; =&gt; &#091;\n                    &#039;arguments&#039; =&gt; &#091;\n                        &#039;data&#039; =&gt; &#091;\n                            &#039;config&#039; =&gt; &#091;\n                                &#039;componentType&#039; =&gt; &#039;container&#039;,\n                                &#039;isTemplate&#039; =&gt; true,\n                                &#039;is_collection&#039; =&gt; true,\n                                &#039;component&#039; =&gt; &#039;Magento_Ui\/js\/dynamic-rows\/record&#039;,\n                                &#039;dataScope&#039; =&gt; &#039;&#039;,\n                            ],\n                        ],\n                    ],\n                    &#039;children&#039; =&gt; $this-&gt;fillMeta(),\n                ],\n            ],\n        ];\n    }\n\n    \/**\n     * Retrieve meta column\n     *\n     * @return array\n     * @since 101.0.0\n     *\/\n    protected function fillMeta()\n    {\n        return &#091;\n            &#039;id&#039; =&gt; $this-&gt;getTextColumn(&#039;id&#039;, false, __(&#039;ID&#039;), 0),\n            &#039;thumbnail&#039; =&gt; &#091;\n                &#039;arguments&#039; =&gt; &#091;\n                    &#039;data&#039; =&gt; &#091;\n                        &#039;config&#039; =&gt; &#091;\n                            &#039;componentType&#039; =&gt; Field::NAME,\n                            &#039;formElement&#039; =&gt; Input::NAME,\n                            &#039;elementTmpl&#039; =&gt; &#039;ui\/dynamic-rows\/cells\/thumbnail&#039;,\n                            &#039;dataType&#039; =&gt; Text::NAME,\n                            &#039;dataScope&#039; =&gt; &#039;thumbnail&#039;,\n                            &#039;fit&#039; =&gt; true,\n                            &#039;label&#039; =&gt; __(&#039;Thumbnail&#039;),\n                            &#039;sortOrder&#039; =&gt; 10,\n                        ],\n                    ],\n                ],\n            ],\n            &#039;name&#039; =&gt; $this-&gt;getTextColumn(&#039;name&#039;, false, __(&#039;Name&#039;), 20),\n            &#039;status&#039; =&gt; $this-&gt;getTextColumn(&#039;status&#039;, true, __(&#039;Status&#039;), 30),\n            &#039;attribute_set&#039; =&gt; $this-&gt;getTextColumn(&#039;attribute_set&#039;, false, __(&#039;Attribute Set&#039;), 40),\n            &#039;sku&#039; =&gt; $this-&gt;getTextColumn(&#039;sku&#039;, true, __(&#039;SKU&#039;), 50),\n            &#039;price&#039; =&gt; $this-&gt;getTextColumn(&#039;price&#039;, true, __(&#039;Price&#039;), 60),\n            &#039;actionDelete&#039; =&gt; &#091;\n                &#039;arguments&#039; =&gt; &#091;\n                    &#039;data&#039; =&gt; &#091;\n                        &#039;config&#039; =&gt; &#091;\n                            &#039;additionalClasses&#039; =&gt; &#039;data-grid-actions-cell&#039;,\n                            &#039;componentType&#039; =&gt; &#039;actionDelete&#039;,\n                            &#039;dataType&#039; =&gt; Text::NAME,\n                            &#039;label&#039; =&gt; __(&#039;Actions&#039;),\n                            &#039;sortOrder&#039; =&gt; 70,\n                            &#039;fit&#039; =&gt; true,\n                        ],\n                    ],\n                ],\n            ],\n            &#039;position&#039; =&gt; &#091;\n                &#039;arguments&#039; =&gt; &#091;\n                    &#039;data&#039; =&gt; &#091;\n                        &#039;config&#039; =&gt; &#091;\n                            &#039;dataType&#039; =&gt; Number::NAME,\n                            &#039;formElement&#039; =&gt; Input::NAME,\n                            &#039;componentType&#039; =&gt; Field::NAME,\n                            &#039;dataScope&#039; =&gt; &#039;position&#039;,\n                            &#039;sortOrder&#039; =&gt; 80,\n                            &#039;visible&#039; =&gt; false,\n                        ],\n                    ],\n                ],\n            ],\n        ];\n    }\n\n    \/**\n     * Retrieve text column structure\n     *\n     * @param string $dataScope\n     * @param bool $fit\n     * @param Phrase $label\n     * @param int $sortOrder\n     * @return array\n     * @since 101.0.0\n     *\/\n    protected function getTextColumn($dataScope, $fit, Phrase $label, $sortOrder)\n    {\n        $column = &#091;\n            &#039;arguments&#039; =&gt; &#091;\n                &#039;data&#039; =&gt; &#091;\n                    &#039;config&#039; =&gt; &#091;\n                        &#039;componentType&#039; =&gt; Field::NAME,\n                        &#039;formElement&#039; =&gt; Input::NAME,\n                        &#039;elementTmpl&#039; =&gt; &#039;ui\/dynamic-rows\/cells\/text&#039;,\n                        &#039;component&#039; =&gt; &#039;Magento_Ui\/js\/form\/element\/text&#039;,\n                        &#039;dataType&#039; =&gt; Text::NAME,\n                        &#039;dataScope&#039; =&gt; $dataScope,\n                        &#039;fit&#039; =&gt; $fit,\n                        &#039;label&#039; =&gt; $label,\n                        &#039;sortOrder&#039; =&gt; $sortOrder,\n                    ],\n                ],\n            ],\n        ];\n\n        return $column;\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Webkul\/CustomLink\/view\/adminhtml\/ui_component\/customlink_product_listing.xml<\/h4>\n\n\n\n<p>As because the UI target is set to $scope.&#8217;_product_listing&#8217; in the modifier class (where $scope is our custom product link type code), so we need to create the customlink_product_listing.xml component file.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n\n&lt;listing xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot; xsi:noNamespaceSchemaLocation=&quot;urn:magento:module:Magento_Ui:etc\/ui_configuration.xsd&quot;&gt;\n    &lt;argument name=&quot;data&quot; xsi:type=&quot;array&quot;&gt;\n        &lt;item name=&quot;js_config&quot; xsi:type=&quot;array&quot;&gt;\n            &lt;item name=&quot;provider&quot; xsi:type=&quot;string&quot;&gt;customlink_product_listing.customlink_product_listing_data_source&lt;\/item&gt;\n            &lt;item name=&quot;deps&quot; xsi:type=&quot;string&quot;&gt;customlink_product_listing.customlink_product_listing_data_source&lt;\/item&gt;\n        &lt;\/item&gt;\n        &lt;item name=&quot;spinner&quot; xsi:type=&quot;string&quot;&gt;product_columns&lt;\/item&gt;\n    &lt;\/argument&gt;\n    &lt;dataSource name=&quot;customlink_product_listing_data_source&quot;&gt;\n        &lt;argument name=&quot;dataProvider&quot; xsi:type=&quot;configurableObject&quot;&gt;\n            &lt;argument name=&quot;class&quot; xsi:type=&quot;string&quot;&gt;Webkul\\CustomLink\\Ui\\DataProvider\\Product\\CustomLinkDataProvider&lt;\/argument&gt;\n            &lt;argument name=&quot;name&quot; xsi:type=&quot;string&quot;&gt;customlink_product_listing_data_source&lt;\/argument&gt;\n            &lt;argument name=&quot;primaryFieldName&quot; xsi:type=&quot;string&quot;&gt;id&lt;\/argument&gt;\n            &lt;argument name=&quot;requestFieldName&quot; xsi:type=&quot;string&quot;&gt;id&lt;\/argument&gt;\n            &lt;argument name=&quot;data&quot; xsi:type=&quot;array&quot;&gt;\n                &lt;item name=&quot;config&quot; xsi:type=&quot;array&quot;&gt;\n                    &lt;item name=&quot;component&quot; xsi:type=&quot;string&quot;&gt;Magento_Ui\/js\/grid\/provider&lt;\/item&gt;\n                    &lt;item name=&quot;update_url&quot; xsi:type=&quot;url&quot; path=&quot;mui\/index\/render&quot;\/&gt;\n                    &lt;item name=&quot;storageConfig&quot; xsi:type=&quot;array&quot;&gt;\n                        &lt;item name=&quot;cacheRequests&quot; xsi:type=&quot;boolean&quot;&gt;false&lt;\/item&gt;\n                    &lt;\/item&gt;\n                &lt;\/item&gt;\n            &lt;\/argument&gt;\n        &lt;\/argument&gt;\n    &lt;\/dataSource&gt;\n    &lt;listingToolbar name=&quot;listing_top&quot;&gt;\n        &lt;filters name=&quot;listing_filters&quot;&gt;\n            &lt;argument name=&quot;data&quot; xsi:type=&quot;array&quot;&gt;\n                &lt;item name=&quot;config&quot; xsi:type=&quot;array&quot;&gt;\n                    &lt;item name=&quot;statefull&quot; xsi:type=&quot;array&quot;&gt;\n                        &lt;item name=&quot;applied&quot; xsi:type=&quot;boolean&quot;&gt;false&lt;\/item&gt;\n                    &lt;\/item&gt;\n                    &lt;item name=&quot;params&quot; xsi:type=&quot;array&quot;&gt;\n                        &lt;item name=&quot;filters_modifier&quot; xsi:type=&quot;array&quot;\/&gt;\n                    &lt;\/item&gt;\n                    &lt;item name=&quot;observers&quot; xsi:type=&quot;array&quot;&gt;\n                        &lt;item name=&quot;filters&quot; xsi:type=&quot;object&quot;&gt;Magento\\Catalog\\Ui\\Component\\Listing\\Filters&lt;\/item&gt;\n                    &lt;\/item&gt;\n                &lt;\/item&gt;\n            &lt;\/argument&gt;\n        &lt;\/filters&gt;\n        &lt;paging name=&quot;listing_paging&quot;\/&gt;\n    &lt;\/listingToolbar&gt;\n    &lt;columns name=&quot;product_columns&quot; class=&quot;Magento\\Ui\\Component\\Listing\\Columns&quot;&gt;\n        &lt;argument name=&quot;data&quot; xsi:type=&quot;array&quot;&gt;\n            &lt;item name=&quot;config&quot; xsi:type=&quot;array&quot;&gt;\n                &lt;item name=&quot;childDefaults&quot; xsi:type=&quot;array&quot;&gt;\n                    &lt;item name=&quot;fieldAction&quot; xsi:type=&quot;array&quot;&gt;\n                        &lt;item name=&quot;provider&quot; xsi:type=&quot;string&quot;&gt;customGrid&lt;\/item&gt;\n                        &lt;item name=&quot;target&quot; xsi:type=&quot;string&quot;&gt;selectData&lt;\/item&gt;\n                        &lt;item name=&quot;params&quot; xsi:type=&quot;array&quot;&gt;\n                            &lt;item name=&quot;0&quot; xsi:type=&quot;string&quot;&gt;${ $.$data.rowIndex }&lt;\/item&gt;\n                        &lt;\/item&gt;\n                    &lt;\/item&gt;\n                &lt;\/item&gt;\n            &lt;\/item&gt;\n        &lt;\/argument&gt;\n        &lt;selectionsColumn name=&quot;ids&quot; sortOrder=&quot;0&quot;&gt;\n            &lt;settings&gt;\n                &lt;indexField&gt;entity_id&lt;\/indexField&gt;\n                &lt;preserveSelectionsOnFilter&gt;true&lt;\/preserveSelectionsOnFilter&gt;\n            &lt;\/settings&gt;\n        &lt;\/selectionsColumn&gt;\n        &lt;column name=&quot;entity_id&quot; sortOrder=&quot;10&quot;&gt;\n            &lt;settings&gt;\n                &lt;filter&gt;textRange&lt;\/filter&gt;\n                &lt;label translate=&quot;true&quot;&gt;ID&lt;\/label&gt;\n                &lt;sorting&gt;asc&lt;\/sorting&gt;\n            &lt;\/settings&gt;\n        &lt;\/column&gt;\n        &lt;column name=&quot;thumbnail&quot; class=&quot;Magento\\Catalog\\Ui\\Component\\Listing\\Columns\\Thumbnail&quot; component=&quot;Magento_Ui\/js\/grid\/columns\/thumbnail&quot; sortOrder=&quot;20&quot;&gt;\n            &lt;settings&gt;\n                &lt;altField&gt;name&lt;\/altField&gt;\n                &lt;hasPreview&gt;1&lt;\/hasPreview&gt;\n                &lt;addField&gt;true&lt;\/addField&gt;\n                &lt;label translate=&quot;true&quot;&gt;Thumbnail&lt;\/label&gt;\n                &lt;sortable&gt;false&lt;\/sortable&gt;\n            &lt;\/settings&gt;\n        &lt;\/column&gt;\n        &lt;column name=&quot;name&quot; sortOrder=&quot;30&quot;&gt;\n            &lt;settings&gt;\n                &lt;addField&gt;true&lt;\/addField&gt;\n                &lt;filter&gt;text&lt;\/filter&gt;\n                &lt;label translate=&quot;true&quot;&gt;Name&lt;\/label&gt;\n            &lt;\/settings&gt;\n        &lt;\/column&gt;\n        &lt;column name=&quot;attribute_set_id&quot; component=&quot;Magento_Ui\/js\/grid\/columns\/select&quot; sortOrder=&quot;40&quot;&gt;\n            &lt;settings&gt;\n                &lt;options class=&quot;Magento\\Catalog\\Model\\Product\\AttributeSet\\Options&quot;\/&gt;\n                &lt;filter&gt;select&lt;\/filter&gt;\n                &lt;dataType&gt;select&lt;\/dataType&gt;\n                &lt;label translate=&quot;true&quot;&gt;Attribute Set&lt;\/label&gt;\n            &lt;\/settings&gt;\n        &lt;\/column&gt;\n        &lt;column name=&quot;attribute_set_text&quot; class=&quot;Magento\\Catalog\\Ui\\Component\\Listing\\Columns\\AttributeSetText&quot; sortOrder=&quot;41&quot;&gt;\n            &lt;settings&gt;\n                &lt;label translate=&quot;true&quot;&gt;AttributeSetText&lt;\/label&gt;\n                &lt;visible&gt;false&lt;\/visible&gt;\n            &lt;\/settings&gt;\n        &lt;\/column&gt;\n        &lt;column name=&quot;status&quot; component=&quot;Magento_Ui\/js\/grid\/columns\/select&quot; sortOrder=&quot;50&quot;&gt;\n            &lt;settings&gt;\n                &lt;options class=&quot;Magento\\Catalog\\Model\\Product\\Attribute\\Source\\Status&quot;\/&gt;\n                &lt;filter&gt;select&lt;\/filter&gt;\n                &lt;dataType&gt;select&lt;\/dataType&gt;\n                &lt;label translate=&quot;true&quot;&gt;Status&lt;\/label&gt;\n            &lt;\/settings&gt;\n        &lt;\/column&gt;\n        &lt;column name=&quot;status_text&quot; class=&quot;Magento\\Catalog\\Ui\\Component\\Listing\\Columns\\StatusText&quot; sortOrder=&quot;51&quot;&gt;\n            &lt;settings&gt;\n                &lt;label translate=&quot;true&quot;&gt;StatusText&lt;\/label&gt;\n                &lt;visible&gt;false&lt;\/visible&gt;\n            &lt;\/settings&gt;\n        &lt;\/column&gt;\n        &lt;column name=&quot;type_id&quot; component=&quot;Magento_Ui\/js\/grid\/columns\/select&quot; sortOrder=&quot;60&quot;&gt;\n            &lt;settings&gt;\n                &lt;options class=&quot;Magento\\Catalog\\Model\\Product\\Type&quot;\/&gt;\n                &lt;filter&gt;select&lt;\/filter&gt;\n                &lt;dataType&gt;select&lt;\/dataType&gt;\n                &lt;label translate=&quot;true&quot;&gt;Type&lt;\/label&gt;\n            &lt;\/settings&gt;\n        &lt;\/column&gt;\n        &lt;column name=&quot;sku&quot; sortOrder=&quot;70&quot;&gt;\n            &lt;settings&gt;\n                &lt;filter&gt;text&lt;\/filter&gt;\n                &lt;label translate=&quot;true&quot;&gt;SKU&lt;\/label&gt;\n            &lt;\/settings&gt;\n        &lt;\/column&gt;\n        &lt;column name=&quot;price&quot; class=&quot;Magento\\Catalog\\Ui\\Component\\Listing\\Columns\\Price&quot; sortOrder=&quot;80&quot;&gt;\n            &lt;settings&gt;\n                &lt;addField&gt;true&lt;\/addField&gt;\n                &lt;filter&gt;textRange&lt;\/filter&gt;\n                &lt;label translate=&quot;true&quot;&gt;Price&lt;\/label&gt;\n            &lt;\/settings&gt;\n        &lt;\/column&gt;\n    &lt;\/columns&gt;\n&lt;\/listing&gt;<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Webkul\/CustomLink\/Ui\/DataProvider\/Product\/CustomLinkDataProvider.php<\/h4>\n\n\n\n<p>Now, it&#8217;s time to create a data provider for our component.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\nnamespace Webkul\\CustomLink\\Ui\\DataProvider\\Product;\n\nuse Magento\\Catalog\\Model\\Product\\Visibility;\nuse Magento\\Catalog\\Ui\\DataProvider\\Product\\Related\\AbstractDataProvider;\n\nclass CustomLinkDataProvider extends AbstractDataProvider\n{\n    \/**\n     * {@inheritdoc}\n     *\/\n    protected function getLinkType()\n    {\n        return &#039;customlink&#039;;\n    }\n\n    \/**\n     * {@inheritdoc}\n     * @since 101.0.0\n     *\/\n    public function getCollection()\n    {\n        \/** @var Collection $collection *\/\n        $collection = parent::getCollection();\n        $collection-&gt;addAttributeToSelect(&#039;status&#039;);\n\n        if ($this-&gt;getStore()) {\n            $collection-&gt;setStore($this-&gt;getStore());\n        }\n\n        if (!$this-&gt;getProduct()) {\n            return $collection;\n        }\n\n        $collection-&gt;addAttributeToFilter(\n            $collection-&gt;getIdFieldName(),\n            &#091;&#039;nin&#039; =&gt; &#091;$this-&gt;getProduct()-&gt;getId()]]\n        );\n\n        $collection-&gt;setVisibility(\n            $this-&gt;getVisibleInSiteIds()\n        );\n\n        return $this-&gt;addCollectionFilters($collection);\n    }\n\n    \/**\n     * Return visible site ids\n     *\n     * @return array\n     *\/\n    private function getVisibleInSiteIds()\n    {\n        return &#091;\n            Visibility::VISIBILITY_IN_SEARCH,\n            Visibility::VISIBILITY_IN_CATALOG,\n            Visibility::VISIBILITY_BOTH\n        ];\n    }\n}<\/pre>\n\n\n\n<p>So now, you can see the custom product link section on the admin product edit page.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img decoding=\"async\" src=\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink-1200x574.png\" alt=\"Custom Link Products Tab\" class=\"wp-image-298397\" width=\"822\" height=\"393\" srcset=\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink-1200x574.png 1200w, https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink-300x143.png 300w, https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink-250x120.png 250w, https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink-768x367.png 768w, https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink.png 1215w\" sizes=\"(max-width: 822px) 100vw, 822px\" loading=\"lazy\" \/><figcaption>Custom Link Section<\/figcaption><\/figure>\n\n\n\n<p>This is how we can create <strong>Custom Linked Product Types<\/strong> in <strong>Magento 2<\/strong> and if you still have any issues, feel free to add a ticket.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Let&#8217;s suppose we need to add a product collection on the product view page and we want the admin to add those products on the basis of some specifications, so for that, we can use custom linked product types like Related products. Today we are going to see how can we create a custom product <a href=\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/\">[&#8230;]<\/a><\/p>\n","protected":false},"author":361,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[302,1],"tags":[2070],"class_list":["post-298356","post","type-post","status-publish","format-standard","hentry","category-magento2","category-uncategorized","tag-magento2"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Custom Linked Product Types Magento2 - Webkul Blog<\/title>\n<meta name=\"description\" content=\"We can use custom-linked product types when we want the admin to add some additional collection to the product details like related products.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Custom Linked Product Types Magento2 - Webkul Blog\" \/>\n<meta property=\"og:description\" content=\"We can use custom-linked product types when we want the admin to add some additional collection to the product details like related products.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/\" \/>\n<meta property=\"og:site_name\" content=\"Webkul Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webkul\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-07-29T09:45:05+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-08-26T08:02:03+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink-1200x574.png\" \/>\n<meta name=\"author\" content=\"Vishesh Dwivedi\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@webkul\" \/>\n<meta name=\"twitter:site\" content=\"@webkul\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Vishesh Dwivedi\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/\"},\"author\":{\"name\":\"Vishesh Dwivedi\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/person\/5cc3f110d01e2a543b6c428dd7d50082\"},\"headline\":\"Custom Linked Product Types Magento2\",\"datePublished\":\"2021-07-29T09:45:05+00:00\",\"dateModified\":\"2021-08-26T08:02:03+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/\"},\"wordCount\":540,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/webkul.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink-1200x574.png\",\"keywords\":[\"Magento2\"],\"articleSection\":[\"Magento2\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/\",\"url\":\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/\",\"name\":\"Custom Linked Product Types Magento2 - Webkul Blog\",\"isPartOf\":{\"@id\":\"https:\/\/webkul.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink-1200x574.png\",\"datePublished\":\"2021-07-29T09:45:05+00:00\",\"dateModified\":\"2021-08-26T08:02:03+00:00\",\"description\":\"We can use custom-linked product types when we want the admin to add some additional collection to the product details like related products.\",\"breadcrumb\":{\"@id\":\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#primaryimage\",\"url\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink.png\",\"contentUrl\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink.png\",\"width\":1215,\"height\":581,\"caption\":\"customLink\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/webkul.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Custom Linked Product Types Magento2\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/webkul.com\/blog\/#website\",\"url\":\"https:\/\/webkul.com\/blog\/\",\"name\":\"Webkul Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/webkul.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/webkul.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/webkul.com\/blog\/#organization\",\"name\":\"WebKul Software Private Limited\",\"url\":\"https:\/\/webkul.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png\",\"contentUrl\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png\",\"width\":380,\"height\":380,\"caption\":\"WebKul Software Private Limited\"},\"image\":{\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webkul\/\",\"https:\/\/x.com\/webkul\",\"https:\/\/www.instagram.com\/webkul\/\",\"https:\/\/www.linkedin.com\/company\/webkul\",\"https:\/\/www.youtube.com\/user\/webkul\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/person\/5cc3f110d01e2a543b6c428dd7d50082\",\"name\":\"Vishesh Dwivedi\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/dc989f00913b5a795e49f513661421421ab49040b61b7170ebb230c3a8b15680?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/dc989f00913b5a795e49f513661421421ab49040b61b7170ebb230c3a8b15680?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g\",\"caption\":\"Vishesh Dwivedi\"},\"url\":\"https:\/\/webkul.com\/blog\/author\/vishesh-dwivedi981\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Custom Linked Product Types Magento2 - Webkul Blog","description":"We can use custom-linked product types when we want the admin to add some additional collection to the product details like related products.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/","og_locale":"en_US","og_type":"article","og_title":"Custom Linked Product Types Magento2 - Webkul Blog","og_description":"We can use custom-linked product types when we want the admin to add some additional collection to the product details like related products.","og_url":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/","og_site_name":"Webkul Blog","article_publisher":"https:\/\/www.facebook.com\/webkul\/","article_published_time":"2021-07-29T09:45:05+00:00","article_modified_time":"2021-08-26T08:02:03+00:00","og_image":[{"url":"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink-1200x574.png","type":"","width":"","height":""}],"author":"Vishesh Dwivedi","twitter_card":"summary_large_image","twitter_creator":"@webkul","twitter_site":"@webkul","twitter_misc":{"Written by":"Vishesh Dwivedi","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#article","isPartOf":{"@id":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/"},"author":{"name":"Vishesh Dwivedi","@id":"https:\/\/webkul.com\/blog\/#\/schema\/person\/5cc3f110d01e2a543b6c428dd7d50082"},"headline":"Custom Linked Product Types Magento2","datePublished":"2021-07-29T09:45:05+00:00","dateModified":"2021-08-26T08:02:03+00:00","mainEntityOfPage":{"@id":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/"},"wordCount":540,"commentCount":0,"publisher":{"@id":"https:\/\/webkul.com\/blog\/#organization"},"image":{"@id":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#primaryimage"},"thumbnailUrl":"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink-1200x574.png","keywords":["Magento2"],"articleSection":["Magento2"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/","url":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/","name":"Custom Linked Product Types Magento2 - Webkul Blog","isPartOf":{"@id":"https:\/\/webkul.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#primaryimage"},"image":{"@id":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#primaryimage"},"thumbnailUrl":"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink-1200x574.png","datePublished":"2021-07-29T09:45:05+00:00","dateModified":"2021-08-26T08:02:03+00:00","description":"We can use custom-linked product types when we want the admin to add some additional collection to the product details like related products.","breadcrumb":{"@id":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#primaryimage","url":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink.png","contentUrl":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/07\/customLink.png","width":1215,"height":581,"caption":"customLink"},{"@type":"BreadcrumbList","@id":"https:\/\/webkul.com\/blog\/create-custom-link-product-type-magento2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/webkul.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Custom Linked Product Types Magento2"}]},{"@type":"WebSite","@id":"https:\/\/webkul.com\/blog\/#website","url":"https:\/\/webkul.com\/blog\/","name":"Webkul Blog","description":"","publisher":{"@id":"https:\/\/webkul.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/webkul.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/webkul.com\/blog\/#organization","name":"WebKul Software Private Limited","url":"https:\/\/webkul.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png","contentUrl":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png","width":380,"height":380,"caption":"WebKul Software Private Limited"},"image":{"@id":"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webkul\/","https:\/\/x.com\/webkul","https:\/\/www.instagram.com\/webkul\/","https:\/\/www.linkedin.com\/company\/webkul","https:\/\/www.youtube.com\/user\/webkul\/"]},{"@type":"Person","@id":"https:\/\/webkul.com\/blog\/#\/schema\/person\/5cc3f110d01e2a543b6c428dd7d50082","name":"Vishesh Dwivedi","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/webkul.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/dc989f00913b5a795e49f513661421421ab49040b61b7170ebb230c3a8b15680?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dc989f00913b5a795e49f513661421421ab49040b61b7170ebb230c3a8b15680?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g","caption":"Vishesh Dwivedi"},"url":"https:\/\/webkul.com\/blog\/author\/vishesh-dwivedi981\/"}]}},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts\/298356","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/users\/361"}],"replies":[{"embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/comments?post=298356"}],"version-history":[{"count":18,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts\/298356\/revisions"}],"predecessor-version":[{"id":298424,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts\/298356\/revisions\/298424"}],"wp:attachment":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/media?parent=298356"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/categories?post=298356"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/tags?post=298356"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}