To add tab in magento version 2.1.0 use below code
create vendor/module/etc/di.xml
<?xml version="1.0"?>
<!--
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<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" type="Magento\Ui\DataProvider\Modifier\Pool">
<arguments>
<argument name="modifiers" xsi:type="array">
<item name="customertab" xsi:type="array">
<item name="class" xsi:type="string">Vendor\Module\Ui\DataProvider\Product\Modifier\Customertab</item>
<item name="sortOrder" xsi:type="number">200</item>
</item>
</argument>
</arguments>
</virtualType>
<type name="Vendor\Module\Ui\DataProvider\Product\Modifier\Customertab">
<arguments>
<argument name="scopeName" xsi:type="string">product_form.product_form</argument>
</arguments>
</type>
<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
<arguments>
<argument name="collections" xsi:type="array">
<item name="customertab_customer_listing_data_source" xsi:type="string">Magento\Customer\Model\ResourceModel\Grid\Collection</item>
</argument>
</arguments>
</type>
</config>
create file Vendor\Module\Ui\DataProvider\Product\Modifier\Customertab.php
<?php
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Vendor\Module\Ui\DataProvider\Product\Modifier;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Catalog\Api\Data\ProductLinkInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Catalog\Model\Locator\LocatorInterface;
use Magento\Eav\Api\AttributeSetRepositoryInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Phrase;
use Magento\Framework\UrlInterface;
use Magento\Ui\Component\DynamicRows;
use Magento\Ui\Component\Form\Element\DataType\Number;
use Magento\Ui\Component\Form\Element\DataType\Text;
use Magento\Ui\Component\Form\Element\Input;
use Magento\Ui\Component\Form\Field;
use Magento\Ui\Component\Form\Fieldset;
use Magento\Ui\Component\Modal;
use Magento\Catalog\Helper\Image as ImageHelper;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory;
/**
* Class Customertab
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Customertab extends AbstractModifier
{
const DATA_SCOPE = '';
const DATA_SCOPE_CUSTOMER = 'customertab';
const GROUP_CUSTOMERTAB = 'customertab';
/**
* @var string
*/
private static $previousGroup = 'search-engine-optimization';
/**
* @var int
*/
private static $sortOrder = 90;
/**
* @var LocatorInterface
*/
protected $locator;
/**
* @var UrlInterface
*/
protected $urlBuilder;
/**
* @var ProductLinkRepositoryInterface
*/
protected $productLinkRepository;
/**
* @var ProductRepositoryInterface
*/
protected $CustomerInterface;
/**
* @var ImageHelper
*/
protected $imageHelper;
/**
* @var Status
*/
protected $status;
/**
* @var AttributeSetRepositoryInterface
*/
protected $attributeSetRepository;
/**
* @var string
*/
protected $scopeName;
/**
* @var string
*/
protected $scopePrefix;
/**
* @var \Magento\Catalog\Ui\Component\Listing\Columns\Price
*/
private $priceModifier;
private $collectionFactory;
/**
* @param LocatorInterface $locator
* @param UrlInterface $urlBuilder
* @param ProductLinkRepositoryInterface $productLinkRepository
* @param ProductRepositoryInterface $productRepository
* @param ImageHelper $imageHelper
* @param Status $status
* @param AttributeSetRepositoryInterface $attributeSetRepository
* @param string $scopeName
* @param string $scopePrefix
*/
public function __construct(
LocatorInterface $locator,
UrlInterface $urlBuilder,
CustomerInterface $CustomerInterface,
ImageHelper $imageHelper,
Status $status,
AttributeSetRepositoryInterface $attributeSetRepository,
CollectionFactory $collectionFactory,
$scopeName = '',
$scopePrefix = ''
) {
$this->locator = $locator;
$this->urlBuilder = $urlBuilder;
// $this->productLinkRepository = $productLinkRepository;
$this->CustomerInterface = $CustomerInterface;
$this->imageHelper = $imageHelper;
$this->status = $status;
$this->attributeSetRepository = $attributeSetRepository;
$this->scopeName = $scopeName;
$this->scopePrefix = $scopePrefix;
$this->collectionFactory = $collectionFactory;
}
/**
* {@inheritdoc}
*/
public function modifyMeta(array $meta)
{
$meta = array_replace_recursive(
$meta,
[
static::GROUP_CUSTOMERTAB => [
'children' => [
$this->scopePrefix . static::DATA_SCOPE_CUSTOMER => $this->getCustomerFieldset(),
],
'arguments' => [
'data' => [
'config' => [
'label' => __('Customer'),
'collapsible' => true,
'componentType' => Fieldset::NAME,
'dataScope' => static::DATA_SCOPE,
'sortOrder' =>
$this->getNextGroupSortOrder(
$meta,
self::$previousGroup,
self::$sortOrder
),
],
],
],
],
]
);
return $meta;
}
/**
* {@inheritdoc}
*/
public function modifyData(array $data)
{
/** @var \Magento\Catalog\Model\Product $product */
$product = $this->locator->getProduct();
$productId = $product->getId();
if (!$productId) {
return $data;
}
$customer = $this->CustomerInterface->getId();
$collection = $this->collectionFactory->create();
foreach ($this->getDataScopes() as $dataScope) {
$data[$productId]['links'][$dataScope] = [];
foreach ($collection as $linkItem) {
// if ($linkItem->getLinkType() !== $dataScope) {
// continue;
// }
// /** @var \Magento\Catalog\Model\Product $linkedProduct */
// $linkedProduct = $this->productRepository->get(
// $linkItem->getLinkedProductSku(),
// false,
// $this->locator->getStore()->getId()
// );
$data[$productId]['links'][$dataScope][] = $this->fillData($linkItem);
}
// if (!empty($data[$productId]['links'][$dataScope])) {
// $dataMap = $priceModifier->prepareDataSource([
// 'data' => [
// 'items' => $data[$productId]['links'][$dataScope]
// ]
// ]);
// $data[$productId]['links'][$dataScope] = $dataMap['data']['items'];
// }
}
$data[$productId][self::DATA_SOURCE_DEFAULT]['current_product_id'] = $productId;
$data[$productId][self::DATA_SOURCE_DEFAULT]['current_store_id'] = $this->locator->getStore()->getId();
return $data;
}
/**
* Prepare data column
*
* @param ProductInterface $linkedProduct
* @param ProductLinkInterface $linkItem
* @return array
*/
protected function fillData($linkItem)
{
return [
'id' => $linkItem->getId(),
'name' => $linkItem->getName(),
'email' => $linkItem->getEmail(),
];
}
/**
* Retrieve all data scopes
*
* @return array
*/
protected function getDataScopes()
{
return [
static::DATA_SCOPE_CUSTOMER,
];
}
/**
* Prepares config for the Related products fieldset
*
* @return array
*/
protected function getCustomerFieldset()
{
$content = __(
'This products are shown to customers in addition to the item the customer is looking at.'
);
return [
'children' => [
'button_set' => $this->getButtonSet(
$content,
__('Add Specific Customer'),
$this->scopePrefix . static::DATA_SCOPE_CUSTOMER
),
'modal' => $this->getGenericModal(
__('Add Specific Customer'),
$this->scopePrefix . static::DATA_SCOPE_CUSTOMER
),
static::DATA_SCOPE_CUSTOMER => $this->getGrid($this->scopePrefix . static::DATA_SCOPE_CUSTOMER),
],
'arguments' => [
'data' => [
'config' => [
'additionalClasses' => 'admin__fieldset-section',
'label' => __('Customer'),
'collapsible' => false,
'componentType' => Fieldset::NAME,
'dataScope' => '',
'sortOrder' => 10,
],
],
]
];
}
/**
* Retrieve button set
*
* @param Phrase $content
* @param Phrase $buttonTitle
* @param string $scope
* @return array
*/
protected function getButtonSet(Phrase $content, Phrase $buttonTitle, $scope)
{
$modalTarget = $this->scopeName . '.' . static::GROUP_CUSTOMERTAB . '.' . $scope . '.modal';
return [
'arguments' => [
'data' => [
'config' => [
'formElement' => 'container',
'componentType' => 'container',
'label' => false,
'content' => $content,
'template' => 'ui/form/components/complex',
],
],
],
'children' => [
'button_' . $scope => [
'arguments' => [
'data' => [
'config' => [
'formElement' => 'container',
'componentType' => 'container',
'component' => 'Magento_Ui/js/form/components/button',
'actions' => [
[
'targetName' => $modalTarget,
'actionName' => 'toggleModal',
],
[
'targetName' => $modalTarget . '.' . $scope . '_customer_listing',
'actionName' => 'render',
]
],
'title' => $buttonTitle,
'provider' => null,
],
],
],
],
],
];
}
/**
* Prepares config for modal slide-out panel
*
* @param Phrase $title
* @param string $scope
* @return array
*/
protected function getGenericModal(Phrase $title, $scope)
{
$listingTarget = $scope . '_customer_listing';
$modal = [
'arguments' => [
'data' => [
'config' => [
'componentType' => Modal::NAME,
'dataScope' => '',
'options' => [
'title' => $title,
'buttons' => [
[
'text' => __('Cancel'),
'actions' => [
'closeModal'
]
],
[
'text' => __('Add Selected Customers'),
'class' => 'action-primary',
'actions' => [
[
'targetName' => 'index = ' . $listingTarget,
'actionName' => 'save'
],
'closeModal'
]
],
],
],
],
],
],
'children' => [
$listingTarget => [
'arguments' => [
'data' => [
'config' => [
'autoRender' => false,
'componentType' => 'insertListing',
'dataScope' => $listingTarget,
'externalProvider' => $listingTarget . '.' . $listingTarget . '_data_source',
'selectionsProvider' => $listingTarget . '.' . $listingTarget . '.customer_columns.ids',
'ns' => $listingTarget,
'render_url' => $this->urlBuilder->getUrl('mui/index/render'),
'realTimeLink' => true,
'dataLinks' => [
'imports' => false,
'exports' => true
],
'behaviourType' => 'simple',
'externalFilterMode' => true,
'imports' => [
'productId' => '${ $.provider }:data.product.current_product_id',
'storeId' => '${ $.provider }:data.product.current_store_id',
],
'exports' => [
'productId' => '${ $.externalProvider }:params.current_product_id',
'storeId' => '${ $.externalProvider }:params.current_store_id',
]
],
],
],
],
],
];
return $modal;
}
/**
* Retrieve grid
*
* @param string $scope
* @return array
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
protected function getGrid($scope)
{
$dataProvider = $scope . '_customer_listing';
return [
'arguments' => [
'data' => [
'config' => [
'additionalClasses' => 'admin__field-wide',
'componentType' => DynamicRows::NAME,
'label' => null,
'columnsHeader' => false,
'columnsHeaderAfterRender' => true,
'renderDefaultRecord' => false,
'template' => 'ui/dynamic-rows/templates/grid',
'component' => 'Magento_Ui/js/dynamic-rows/dynamic-rows-grid',
'addButton' => false,
'recordTemplate' => 'record',
'dataScope' => 'data.links',
'deleteButtonLabel' => __('Remove'),
'dataProvider' => $dataProvider,
'map' => [
'id' => 'entity_id',
'name' => 'name',
'email' => 'email',
],
'links' => [
'insertData' => '${ $.provider }:${ $.dataProvider }'
],
'sortOrder' => 2,
],
],
],
'children' => [
'record' => [
'arguments' => [
'data' => [
'config' => [
'componentType' => 'container',
'isTemplate' => true,
'is_collection' => true,
'component' => 'Magento_Ui/js/dynamic-rows/record',
'dataScope' => '',
],
],
],
'children' => $this->fillMeta(),
],
],
];
}
/**
* Retrieve meta column
*
* @return array
*/
protected function fillMeta()
{
return [
'id' => $this->getTextColumn('id', false, __('ID'), 0),
'name' => $this->getTextColumn('name', false, __('Name'), 20),
'email' => $this->getTextColumn('email', true, __('Email'), 30),
'actionDelete' => [
'arguments' => [
'data' => [
'config' => [
'additionalClasses' => 'data-grid-actions-cell',
'componentType' => 'actionDelete',
'dataType' => Text::NAME,
'label' => __('Actions'),
'sortOrder' => 70,
'fit' => true,
],
],
],
],
];
}
/**
* Retrieve text column structure
*
* @param string $dataScope
* @param bool $fit
* @param Phrase $label
* @param int $sortOrder
* @return array
*/
protected function getTextColumn($dataScope, $fit, Phrase $label, $sortOrder)
{
$column = [
'arguments' => [
'data' => [
'config' => [
'componentType' => Field::NAME,
'formElement' => Input::NAME,
'elementTmpl' => 'ui/dynamic-rows/cells/text',
'component' => 'Magento_Ui/js/form/element/text',
'dataType' => Text::NAME,
'dataScope' => $dataScope,
'fit' => $fit,
'label' => $label,
'sortOrder' => $sortOrder,
],
],
],
];
return $column;
}
}
Create app/code/Vendor/Module/view/adminhtml/ui_component/customertab_customer_listing.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="provider" xsi:type="string">customertab_customer_listing.customertab_customer_listing_data_source</item>
<item name="deps" xsi:type="string">customertab_customer_listing.customertab_customer_listing_data_source</item>
</item>
<item name="spinner" xsi:type="string">customer_columns</item>
</argument>
<dataSource name="customertab_customer_listing_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">Magento\Customer\Ui\Component\DataProvider</argument>
<argument name="name" xsi:type="string">customertab_customer_listing_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">entity_id</argument>
<argument name="requestFieldName" xsi:type="string">id</argument>
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
<item name="update_url" xsi:type="url" path="mui/index/render"/>
<item name="storageConfig" xsi:type="array">
<item name="cacheRequests" xsi:type="boolean">false</item>
</item>
</item>
</argument>
</argument>
</dataSource>
<columns name="customer_columns" class="Magento\Customer\Ui\Component\Listing\Columns">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="childDefaults" xsi:type="array">
<item name="fieldAction" xsi:type="array">
<item name="provider" xsi:type="string">customertab_customer_listing.customertab_customer_listing.customer_columns_editor</item>
<item name="target" xsi:type="string">selectCustomer</item>
<item name="params" xsi:type="array">
<item name="0" xsi:type="string">${ $.$data.rowIndex }</item>
</item>
</item>
</item>
</item>
</argument>
<selectionsColumn name="ids">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="indexField" xsi:type="string">entity_id</item>
<item name="sortOrder" xsi:type="number">0</item>
<item name="preserveSelectionsOnFilter" xsi:type="boolean">true</item>
</item>
</argument>
</selectionsColumn>
<column name="entity_id">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="filter" xsi:type="string">textRange</item>
<item name="sorting" xsi:type="string">asc</item>
<item name="label" xsi:type="string" translate="true">ID</item>
<item name="sortOrder" xsi:type="number">10</item>
</item>
</argument>
</column>
<column name="name">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="filter" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Name</item>
<item name="sortOrder" xsi:type="number">30</item>
</item>
</argument>
</column>
<column name="email">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="filter" xsi:type="string">text</item>
<item name="editor" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Email</item>
<item name="sortOrder" xsi:type="number">40</item>
</item>
</argument>
</column>
</columns>
</listing>