app/code/Vendor/Module/etc/catalog_attributes.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Catalog:etc/catalog_attributes.xsd">
<group name="quote_item">
<attribute name="custom_attribute"/>
</group>
</config>
app/code/Vendor/Module/Setup/InstallData.php
<?php
namespace [Vendor]\[Module]\Setup;
use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\DB\Ddl\Table;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Sales\Setup\SalesSetupFactory;
use Magento\Quote\Setup\QuoteSetupFactory;
/**
* @codeCoverageIgnore
*/
class InstallData implements InstallDataInterface
{
/**
* EAV setup factory
*
* @var EavSetupFactory
*/
private $eavSetupFactory;
/**
* @var QuoteSetupFactory
*/
private $quoteSetupFactory;
/**
* @var SalesSetup
*/
private $salesSetupFactory;
/**
* InstallData constructor.
* @param EavSetupFactory $eavSetupFactory
* @param QuoteSetupFactory $quoteSetupFactory
*/
public function __construct(
EavSetupFactory $eavSetupFactory,
QuoteSetupFactory $quoteSetupFactory,
SalesSetupFactory $salesSetupFactory
)
{
$this->eavSetupFactory = $eavSetupFactory;
$this->quoteSetupFactory = $quoteSetupFactory;
$this->salesSetupFactory = $salesSetupFactory;
}
public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
/** @var EavSetup $eavSetup */
$eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
/** @var QuoteSetup $quoteSetup */
$quoteSetup = $this->quoteSetupFactory->create(['setup' => $setup]);
/** @var SalesSetup $salesSetup */
$salesSetup = $this->salesSetupFactory->create(['setup' => $setup]);
/**
* Add attributes to the eav/attribute
*/
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'custom_attribute',
[
'type' => 'int',
'label' => 'Custom Attribute',
'input' => 'select',
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
'visible' => true,
'required' => false,
'user_defined' => true,
'default' => '',
'searchable' => false,
'filterable' => false,
'comparable' => false,
'visible_on_front' => false,
'used_in_product_listing' => false,
'unique' => false,
'option' => [
'values' => [
'Option 1',
'Option 2',
'Option 3'
],
]
]
);
$attributeSetId = $eavSetup->getDefaultAttributeSetId('catalog_product');
$eavSetup->addAttributeToSet(
'catalog_product',
$attributeSetId,
'General',
'custom_attribute'
);
$attributeOptions = [
'type' => Table::TYPE_TEXT,
'visible' => true,
'required' => false
];
$quoteSetup->addAttribute('quote_item', 'custom_attribute', $attributeOptions);
$salesSetup->addAttribute('order_item', 'custom_attribute', $attributeOptions);
}
}
app/code/Vendor/Module/etc/events.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="sales_quote_item_set_product">
<observer name="set_item_custom_attribute" instance="[Vendor]\[Module]\Observer\SetItemCustomAttribute" />
</event>
</config>
app/code/Vendor/Module/Observer/SetItemCustomAttribute.php
<?php
namespace [Vendor]\[Module]\Observer;
use Magento\Framework\Event\ObserverInterface;
class SetItemCustomAttribute implements ObserverInterface
{
/**
* @param \Magento\Framework\Event\Observer $observer
* @return void
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function execute(\Magento\Framework\Event\Observer $observer)
{
$quoteItem = $observer->getQuoteItem();
$product = $observer->getProduct();
$quoteItem->setCustomAttribute($product->getAttributeText('custom_attribute'));
}
}
app/code/Vendor/Module/etc/fieldset.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="lib/internal/Magento/Framework/Object/etc/fieldset.xsd">
<scope id="global">
<fieldset id="quote_convert_item">
<field name="custom_attribute">
<aspect name="to_order_item" />
</field>
</fieldset>
</scope>
</config>
app/code/Vendor/Module/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Quote\Model\Quote\Item\ToOrderItem">
<plugin name="custom_attribute_quote_to_order_item" type="[Vendor]\[Module]\Plugin\CustomAttributeQuoteToOrderItem"/>
</type>
</config>
app/code/Vendor/Module/Plugin/CustomAttributeQuoteToOrderItem.php
<?php
namespace [Vendor]\[Module]\Plugin;
class CustomAttributeQuoteToOrderItem
{
public function aroundConvert(
\Magento\Quote\Model\Quote\Item\ToOrderItem $subject,
\Closure $proceed,
\Magento\Quote\Model\Quote\Item\AbstractItem $item,
$additional = []
) {
/** @var $orderItem \Magento\Sales\Model\Order\Item */
$orderItem = $proceed($item, $additional);
$orderItem->setCustomAttribute($item->getCustomAttribute());
return $orderItem;
}
}