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.

Was it helpful?

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:

enter image description here

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);
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top