credits: Jelly Beans via photopin (license). posted on May 30th, 2016.

Add a Product Attribute to all Attribute Sets programmatically in Magento 2

Very useful in update- or installation scripts!

When a Magento 2 shops grows, it gains more and more attribute sets. Adding new attributes to all attribute sets might become a cumbersome task. Especially when you first have to do it on your local development environment, and once again for your test- and production environments. Seems not very DRY to me. So why not automate this?

AttributeManagement

Magento 2 has a nifty little class that can help you with this task: Magento\Eav\Model\AttributeManagement. This class has a cool little assign()-method (and also a unassign()-method for that matter) that does a lot of heavy number crunching for you. Just look at it's signature:

public function assign(
    $entityTypeCode,
    $attributeSetId,
    $attributeGroupId,
    $attributeCode,
    $sortOrder
)

This is one part of the code, but most likely the part you were looking for. Since all other stuff can be easily calculated with all the factories Magento 2 provides. But in case you want the full monty:

use Magento\Eav\Model\Entity\Attribute;
use Magento\Eav\Model\Entity\AttributeFactory;
use Magento\Eav\Model\AttributeManagement;
use Magento\Eav\Model\Entity\Attribute\Group;
use Magento\Eav\Model\Entity\Attribute\GroupFactory;
use Magento\Eav\Model\Entity\Attribute\Set;
use Magento\Eav\Model\Entity\Attribute\SetFactory;
use Magento\Eav\Model\Entity\TypeFactory;

class Example {
    /**
     * @var AttributeFactory
     */
    protected $attributeFactory;

    /**
     * @var SetFactory
     */
    protected $attributeSetFactory;

    /**
     * @var TypeFactory
     */
    protected $eavTypeFactory;

    /**
     * @var GroupFactory
     */
    protected $attributeGroupFactory;

    /**
     * @var AttributeManagement
     */
    protected $attributeManagement;

    /**
     * Setup constructor.
     * @param AttributeFactory $attributeFactory
     * @param SetFactory $attributeSetFactory
     * @param GroupFactory $attributeGroupFactory
     * @param TypeFactory $typeFactory
     * @param AttributeManagement $attributeManagement
     * @param Context $context
     */
    public function __construct(
        AttributeFactory $attributeFactory,
        SetFactory $attributeSetFactory,
        GroupFactory $attributeGroupFactory,
        TypeFactory $typeFactory,
        AttributeManagement $attributeManagement,
        Context $context
    )
    {
        $this->attributeFactory = $attributeFactory;
        $this->attributeSetFactory = $attributeSetFactory;
        $this->eavTypeFactory = $typeFactory;
        $this->attributeGroupFactory = $attributeGroupFactory;
        $this->attributeManagement = $attributeManagement;
        parent::__construct($context);
    }

    /**
     * @param string $attributeCode
     * @param string $attributeGroupCode
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function addAttributeToAllAttributeSets(string $attributeCode, string $attributeGroupCode)
    {
        /** @var Attribute $attribute */
        $entityType = $this->eavTypeFactory->create()->loadByCode('catalog_product');
        $attribute = $this->attributeFactory->create()->loadByCode($entityType->getId(), $attributeCode);

        if (!$attribute->getId()) {
            return false;
        }

        /** @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\Collection $setCollection */
        $setCollection = $this->attributeSetFactory->create()->getCollection();
        $setCollection->addFieldToFilter('entity_type_id', $entityType->getId());

        /** @var Set $attributeSet */
        foreach ($setCollection as $attributeSet) {
            /** @var Group $group */
            $group = $this->attributeGroupFactory->create()->getCollection()
                ->addFieldToFilter('attribute_group_code', ['eq' => $attributeGroupCode])
                ->addFieldToFilter('attribute_set_id', ['eq' => $attributeSet->getId()])
                ->getFirstItem();

            $groupId = $group->getId() ?: $attributeSet->getDefaultGroupId();

            // Assign:
            $this->attributeManagement->assign(
                'catalog_product',
                $attributeSet->getId(),
                $groupId,
                $attributeCode,
                $attributeSet->getCollection()->count() * 10
            );
        }

        return true;
    }
}

That's it! One script to add a single attribute to all attribute sets at once.

Magento 2 Product Attributes