7

I would like to create attributes with swatch option programatically in Magento 2.

  • By programmatically, do you mean using the API or using PHP coding? – Steve Johnson Aug 27 '16 at 13:26
  • @SteveJohnson I mean by PHP coding – Gideon Aug 30 '16 at 5:06
  • I also want solution for this. Have you found any solution then please post here. – Magecode Dec 6 '17 at 12:20
3

This is similar to Magento 1, with a few differences.

Step 1

Start by creating a basic setup script for it, if you don't already have one.

<?php
namespace Package\Module\Setup;
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;

class UpgradeData implements UpgradeDataInterface
{
    const PRODUCT_GROUP = 'Product Details';

    /** @var \Magento\Framework\App\State */
    protected $state;

    /** @var \Magento\Catalog\Model\Product\Attribute\Repository $attributeRepository */
    protected $attributeRepository;

    /** @var \Magento\Framework\Filesystem  */
    protected $filesystem;

    /** @var \Magento\Swatches\Helper\Media */
    protected $swatchHelper;

    /** @var \Magento\Catalog\Model\Product\Media\Config */
    protected $productMediaConfig;

    /** @var \Magento\Framework\Filesystem\Driver\File */
    protected $driverFile;

    /** @var \Magento\Eav\Setup\EavSetupFactory */
    protected $eavSetupFactory;

    public function __construct(
        \Magento\Eav\Setup\EavSetupFactory $eavSetupFactory,
        \Magento\Framework\App\State $state,
        \Magento\Catalog\Model\Product\Attribute\Repository $attributeRepository,
        \Magento\Framework\Filesystem $filesystem,
        \Magento\Swatches\Helper\Media $swatchHelper,
        \Magento\Catalog\Model\Product\Media\Config $productMediaConfig,
        \Magento\Framework\Filesystem\Driver\File $driverFile
    ) {
        $this->eavSetupFactory = $eavSetupFactory;
        $this->state = $state;
        $this->attributeRepository = $attributeRepository;
        $this->filesystem = $filesystem;
        $this->swatchHelper = $swatchHelper;
        $this->productMediaConfig = $productMediaConfig;
        $this->driverFile = $driverFile;
    }

    /**
     * {@inheritdoc}
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $setup->startSetup();

        if (version_compare($context->getVersion(), '1.0.0', '<')) {
            $attributesData = [
               // to add in step 2
            ];

            $attributesOptionsData = [
                // to add in step 2
            ];

            $this->addProductAttributes($attributesData, $attributesOptionsData, $setup);
        }

        $setup->endSetup();
    }

    /**
     * Add product attributes.
     *
     * @param $attributesData
     * @param $attributesOptionsData
     * @param ModuleDataSetupInterface $setup
     *
     * @throws \Exception
     */
    public function addProductAttributes($attributesData, $attributesOptionsData, ModuleDataSetupInterface $setup)
    {
        // to implement in step 3
    }
}

Step 2

Secondly, prepare your data. Replace \\ to add in step 2 comments from Step 1 with something similar:

$attributesData = [
    'fit' => [
        'type' => 'int',
        'label' => 'Fit',
        'input' => 'select',
        'backend' => 'Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend',
        'source' => 'Magento\Eav\Model\Entity\Attribute\Source\Table',
        'required' => false,
        'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
        'group' => self::PRODUCT_GROUP,
        'used_in_product_listing' => true,
        'visible_on_front' => true,
        'user_defined' => true,
        'filterable' => 2,
        'filterable_in_search' => true,
        'used_for_promo_rules' => true,
        'is_html_allowed_on_front' => true,
        'used_for_sort_by' => true,
    ],
];
$attributesOptionsData = [
    'fit' => [
        \Magento\Swatches\Model\Swatch::SWATCH_INPUT_TYPE_KEY => \Magento\Swatches\Model\Swatch::SWATCH_INPUT_TYPE_VISUAL,
        'optionvisual' => [
            'value'     => [
                'option_0' => [
                    0 => 'FITTED'
                ],
                'option_1' => [
                    0 => 'RELAXED'
                ],
                'option_2' => [
                    0 => 'REGULAR'
                ],
            ],
        ],
        'swatchvisual' => [
            'value'     => [
                'option_0' => 'Fitted.png',
                'option_1' => 'Relaxed.png',
                'option_2' => 'Regular.png',
            ],
        ],
    ]
];

Step 3

Finally, finish implementation for addProductAttributes method:

/**
 * Add product attributes.
 *
 * @param $attributesData
 * @param $attributesOptionsData
 * @param ModuleDataSetupInterface $setup
 *
 * @throws \Exception
 */
public function addProductAttributes($attributesData, $attributesOptionsData, ModuleDataSetupInterface $setup)
{
    try {
        // Make sure we don't get error "Area code is not set".
        $this->state->setAreaCode('admin');
    } catch (\Exception $ignored) {}
    try {
        /** @var \Magento\Eav\Setup\EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);

        // Add attributes.
        foreach ($attributesData as $code => $attributeData) {
            $eavSetup->addAttribute(\Magento\Catalog\Model\Product::ENTITY, $code, $attributeData);
        }

        // Add order if it doesn't exist. This is an important step to make sure everything will be created correctly.
        foreach ($attributesOptionsData as &$attributeOptionsData) {
            $order = 0;
            $swatchVisualFiles = isset($attributeOptionsData['optionvisual']['value'])
                ? $attributeOptionsData['optionvisual']['value']
                : [];
            foreach ($swatchVisualFiles as $index => $swatchVisualFile) {
                if (!isset($attributeOptionsData['optionvisual']['order'][$index])) {
                    $attributeOptionsData['optionvisual']['order'][$index] = ++$order;
                }
            }
        }

        // Prepare visual swatches files.
        $mediaDirectory = $this->filesystem->getDirectoryRead(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA);
        $tmpMediaPath = $this->productMediaConfig->getBaseTmpMediaPath();
        $fullTmpMediaPath = $mediaDirectory->getAbsolutePath($tmpMediaPath);
        $this->driverFile->createDirectory($fullTmpMediaPath);
        foreach ($attributesOptionsData as &$attributeOptionsData) {
            $swatchVisualFiles = $attributeOptionsData['swatchvisual']['value'] ?? [];
            foreach ($swatchVisualFiles as $index => $swatchVisualFile) {
                $this->driverFile->copy(
                    __DIR__ . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . $swatchVisualFile,
                    $fullTmpMediaPath . DIRECTORY_SEPARATOR . $swatchVisualFile
                );
                $newFile = $this->swatchHelper->moveImageFromTmp($swatchVisualFile);
                if (substr($newFile, 0, 1) == '.') {
                    $newFile = substr($newFile, 1); // Fix generating swatch variations for files beginning with ".".
                }
                $this->swatchHelper->generateSwatchVariations($newFile);
                $attributeOptionsData['swatchvisual']['value'][$index] = $newFile;
            }
        }

        // Add attribute options.
        foreach ($attributesOptionsData as $code => $attributeOptionsData) {
            /* @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */
            $attribute = $this->attributeRepository->get($code);
            $attribute->addData($attributeOptionsData);
            $attribute->save();
        }
    } catch (\Exception $ex) {
        throw new \Exception(__('There was an error adding product attributes.'), 0, $ex);
    }
}
  • Mimarcel, it is always best to post your entire answer so people don't link out to an outside site. – brentwpeterson Sep 22 '16 at 21:45
  • I have to import attribute option with visual swatch and swatch value is colorcode. I am following this link for upload attribute options but not getting solution to add visual swatch value. Please help me. pearlbells.co.uk/… – Magecode Dec 6 '17 at 12:19
1

Recently tried below code for creating visual swatch attribute options pro-grammatically. Created file within root "import-visual-swatch.php" with below code:

<?php

use Magento\Framework\App\Bootstrap;
require __DIR__ . '/app/bootstrap.php';
// adding bootstrap
$bootstraps = Bootstrap::create(BP, $_SERVER);
$object_Manager = $bootstraps->getObjectManager();

$app_state = $object_Manager->get('\Magento\Framework\App\State');
$app_state->setAreaCode('frontend');

// Visual Swatch option values array containing name, unique code as key and image url for swatch
// Swatch image are to be placed within "project_root\import" directory
// After code execution swatch images will be uploaded to "project_root\pub\media\attribute\swatch" directory
$finalProductData = array(
    'BLKV' => array("label" => "Black", "url" => "Black.JPG"),
    'BLKV1' => array("label" => "Black1", "url" => "Black1.JPG")
 );

$stores = getAllStores($object_Manager);

$eavConfig = $object_Manager->get('\Magento\Eav\Model\Config');
$attribute = $eavConfig->getAttribute('catalog_product', 'color');

// Generating options as we are creating Visual Swatch hence passing 'visual' as parameter 
$data = generateOptions($finalProductData, 'visual');
$filesystem = $object_Manager->create('\Magento\Framework\Filesystem');

// Prepare visual swatches files.
$mediaDirectory = $filesystem->getDirectoryRead(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA);
$productMediaConfig = $object_Manager->create('\Magento\Catalog\Model\Product\Media\Config');
$tmpMediaPath = $productMediaConfig->getBaseTmpMediaPath();
$fullTmpMediaPath = $mediaDirectory->getAbsolutePath($tmpMediaPath);

$driverFile = $object_Manager->create('\Magento\Framework\Filesystem\Driver\File');
$driverFile->createDirectory($fullTmpMediaPath);
$swatchHelper = $object_Manager->create('\Magento\Swatches\Helper\Media');

foreach ($data as $key => $attributeOptionsData) {
    if($key == "swatchvisual" ){
        $swatchVisualFiles = isset($attributeOptionsData['value'])
        ? $attributeOptionsData['value']
        : [];

        foreach ($swatchVisualFiles as $index => $swatchVisualFile) {
            if(!empty($swatchVisualFile)){
                if(file_exists(__DIR__ . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . $swatchVisualFile)) {
                    $driverFile->copy(
                    __DIR__ . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . $swatchVisualFile,
                    $fullTmpMediaPath . '/' . $swatchVisualFile
                    );

                    $newFile = $swatchHelper->moveImageFromTmp($swatchVisualFile);
                    if (substr($newFile, 0, 1) == '.') {
                        $newFile = substr($newFile, 1); // Fix generating swatch variations for files beginning with ".".
                    }
                    $swatchHelper->generateSwatchVariations($newFile);
                    $data[$key]['value'][$index] = $newFile;
                } else {
                    $data[$key]['value'][$index] = "";
                }
            }
        }
    }    
}

function generateOptions($values, $swatchType = 'visual')
{
    $i = 0;
    foreach($values as $key => $value) {
        $order["option_{$i}"] = $i;
        $optionsStore["option_{$i}"] = array(
            0 => $key, // admin
            1 => $value['label'], // default store view
        );
        $textSwatch["option_{$i}"] = array(
            1 => $value['label'],
        );
        $visualSwatch["option_{$i}"] = $value['url'];
        $delete["option_{$i}"] = '';
        $i++;
    }

    switch($swatchType)
    {
        case 'text':
            return [
                'optiontext' => [
                    'order'     => $order,
                    'value'     => $optionsStore,
                    'delete'    => $delete,
                ],
                'swatchtext' => [
                    'value'     => $textSwatch,
                ],
            ];
            break;
        case 'visual':
            return [
                'optionvisual' => [
                    'order'     => $order,
                    'value'     => $optionsStore,
                    'delete'    => $delete,
                ],
                'swatchvisual' => [
                    'value'     => $visualSwatch,
                ],
            ];
            break;
        default:
            return [
                'option' => [
                    'order'     => $order,
                    'value'     => $optionsStore,
                    'delete'    => $delete,
                ],
            ];
    }
}

$attribute->addData($data)->save();
?>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.