Create Visual Swatch Attribute
Question
Can anyone provide a working example for creating a visual swatch (or even a text swatch) attribute as part of a setup script.
I've tried the example on Magento 2 create custom swatch attribute programmatically but it doesn't work for me.
The issue I've ran into there is that the the attribute repository cannot find the new attribute that was created. I tried putting some cache clearing in between but no luck.
Thanks.
Solution
Disclaimer: Parts of this code were taken from Magento_SwatchesSampleData
core module. Also you might not need colorMap
but I just put it there.
This code was tested on Magento 2.1.4.
I assume you have an extension called Goivvy_Custom
. I also assume you know how to install the extension and have magento run install scripts.
The code below will create new_swatch_attribute
Visual Swatch.
Here is Goivvy/Custom/Setup/InstallData.php
:
<?php
namespace Goivvy\Custom\Setup;
use Magento\Framework\Setup;
use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Catalog\Model\Product\Type;
use Magento\Catalog\Model\ResourceModel\Eav\Attribute as eavAttribute;
class InstallData implements Setup\InstallDataInterface
{
private $attrOptionCollectionFactory;
private $eavSetupFactory;
private $eavConfig;
protected $colorMap = [
'Black' => '#000000',
'Blue' => '#1857f7',
'Brown' => '#945454',
'Gray' => '#8f8f8f',
'Green' => '#53a828',
'Lavender' => '#ce64d4',
'Multi' => '#ffffff',
'Orange' => '#eb6703',
'Purple' => '#ef3dff',
'Red' => '#ff0000',
'White' => '#ffffff',
'Yellow' => '#ffd500',
];
public function __construct(EavSetupFactory $eavSetupFactory,
\Magento\Eav\Model\Config $eavConfig,
\Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory $attrOptionCollectionFactory
)
{
$this->eavConfig = $eavConfig;
$this->eavSetupFactory = $eavSetupFactory;
$this->attrOptionCollectionFactory = $attrOptionCollectionFactory;
}
public function install(Setup\ModuleDataSetupInterface $setup, Setup\ModuleContextInterface $moduleContext)
{
$eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
if(version_compare($moduleContext->getVersion(),'1.0.0') < 0){
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'new_swatch_attribute',
[
'type' => 'int',
'label' => 'New Swatch Attribute',
'input' => 'select',
'required' => false,
'user_defined' => true,
'searchable' => true,
'filterable' => true,
'comparable' => true,
'visible_in_advanced_search' => true,
'apply_to' => implode(',', [Type::TYPE_SIMPLE, Type::TYPE_VIRTUAL]),
'is_used_in_grid' => true,
'is_visible_in_grid' => false,
'option' => [
'values' => [
'Black',
'Blue',
'Brown',
'Gray',
'Green',
'Lavender',
'Multi',
'Orange',
'Purple',
'Red',
'White',
'Yellow'
]
]
]
);
$this->eavConfig->clear();
$attribute = $this->eavConfig->getAttribute('catalog_product', 'new_swatch_attribute');
if (!$attribute) {
return;
}
$attributeData['option'] = $this->addExistingOptions($attribute);
$attributeData['frontend_input'] = 'select';
$attributeData['swatch_input_type'] = 'visual';
$attributeData['update_product_preview_image'] = 1;
$attributeData['use_product_image_for_swatch'] = 0;
$attributeData['optionvisual'] = $this->getOptionSwatch($attributeData);
$attributeData['defaultvisual'] = $this->getOptionDefaultVisual($attributeData);
$attributeData['swatchvisual'] = $this->getOptionSwatchVisual($attributeData);
$attribute->addData($attributeData);
$attribute->save();
}
}
protected function getOptionSwatch(array $attributeData)
{
$optionSwatch = ['order' => [], 'value' => [], 'delete' => []];
$i = 0;
foreach ($attributeData['option'] as $optionKey => $optionValue) {
$optionSwatch['delete'][$optionKey] = '';
$optionSwatch['order'][$optionKey] = (string)$i++;
$optionSwatch['value'][$optionKey] = [$optionValue, ''];
}
return $optionSwatch;
}
private function getOptionSwatchVisual(array $attributeData)
{
$optionSwatch = ['value' => []];
foreach ($attributeData['option'] as $optionKey => $optionValue) {
if (substr($optionValue, 0, 1) == '#' && strlen($optionValue) == 7) {
$optionSwatch['value'][$optionKey] = $optionValue;
} else if ($this->colorMap[$optionValue]) {
$optionSwatch['value'][$optionKey] = $this->colorMap[$optionValue];
} else {
$optionSwatch['value'][$optionKey] = $this->colorMap['White'];
}
}
return $optionSwatch;
}
private function getOptionDefaultVisual(array $attributeData)
{
$optionSwatch = $this->getOptionSwatchVisual($attributeData);
if(isset(array_keys($optionSwatch['value'])[0]))
return [array_keys($optionSwatch['value'])[0]];
else
return [''];
}
private function addExistingOptions(eavAttribute $attribute)
{
$options = [];
$attributeId = $attribute->getId();
if ($attributeId) {
$this->loadOptionCollection($attributeId);
foreach ($this->optionCollection[$attributeId] as $option) {
$options[$option->getId()] = $option->getValue();
}
}
return $options;
}
private function loadOptionCollection($attributeId)
{
if (empty($this->optionCollection[$attributeId])) {
$this->optionCollection[$attributeId] = $this->attrOptionCollectionFactory->create()
->setAttributeFilter($attributeId)
->setPositionOrder('asc', true)
->load();
}
}
}
Here is how it looks in Magento 2.1.4:
Any questions - let me know.
OTHER TIPS
There is a different and more direct way to add visual swatch attributes. If you check this unit test from the Magento Native code: https://github.com/magento/magento2/blob/2.4-develop/dev/tests/integration/testsuite/Magento/Swatches/_files/product_visual_swatch_attribute.php
They propose the following solution:
$attribute->setData(
[
'frontend_label' => ['Visual swatch attribute'],
'entity_type_id' => $entityType,
'frontend_input' => 'select',
'backend_type' => 'int',
'is_required' => '0',
'attribute_code' => 'visual_swatch_attribute',
'is_global' => '1',
'is_user_defined' => 1,
'is_unique' => '0',
'is_searchable' => '0',
'is_comparable' => '0',
'is_filterable' => '1',
'is_filterable_in_search' => '0',
'is_used_for_promo_rules' => '0',
'is_html_allowed_on_front' => '1',
'used_in_product_listing' => '1',
'used_for_sort_by' => '0',
'swatch_input_type' => 'visual',
'swatchvisual' => [
'value' => [
'option_1' => '#555555',
'option_2' => '#aaaaaa',
'option_3' => '#ffffff',
],
],
'optionvisual' => [
'value' => [
'option_1' => ['option 1'],
'option_2' => ['option 2'],
'option_3' => ['option 3']
],
],
'options' => [
'option' => [
['label' => 'Option 1', 'value' => 'option_1'],
['label' => 'Option 2', 'value' => 'option_2'],
['label' => 'Option 3', 'value' => 'option_3'],
],
],
]
);
$attributeRepository->save($attribute);