SHIPPING

   $rates = $quote->getShippingAddress()->getShippingRatesCollection();
   foreach ($rates as $rate)
     {
       $rate->setPrice(0.00)->save();
     }

For Returning the values you should recalculate the Rules

  $quote->getShippingAddress()->setCollectShippingRates(true)->collectShippingRates();

QUOTE ITEM

 foreach ($quote->getAllVisibleItems() as $item) {
   $item->setCustomPrice( $item->getProduct()
       ->getPrice())->setOriginalCustomPrice($item->getProduct()->getPrice())
       ->getProduct()->setIsSuperMode(false);
   $item ->getProduct()->setTaxClassId(0);
   $item->calcRowTotal();
}

Quick overview of the entity attribute system

Since the early days, Magento has offered an extensible entity attribute system based on the Entity-Attribute-Value (EAV) model.

Through this system, it’s straightforward to extend a Magento entity, with some limits:

  • only EAV entities can be extended with attributes; not all entities in a default Magento installation are EAV entities, just products, categories, customers, and customer addresses.
  • attributes can only contain scalar values, that is, booleanintfloat, or string values.

The extension attributes system, introduced in Magento 2, overcomes the above limits, making it easy to:

  • extend non-EAV entities to a condition: the entity should implement the \Magento\Framework\Api\ExtensibleDataInterface;
  • use objects to have more complex types.

Unluckily, some Magento core entities don’t implement the \Magento\Framework\Api\ExtensibleDataInterface thus they are not extensible with native extension attributes. Anyway, let’s focus on the half-full glass to explore some advantages of the extension attributes system.

What are custom attributes?

With the introduction of the extension attributes system, some new terminology comes in.

EAV attributes belong to one of the following sets:

  • system attributes – created by any default Magento installation;
  • custom attributes – created in the Admin Panel or through data patches.

So, simply put, a custom attribute is an EAV attribute created by someone else.

What are extension attributes?

We have already given a definition but let’s refresh it: an extension attribute is an attribute that extends a non-EAV entity.

But obviously, there is more.

First, the good news: an extension attribute allows us to overcome the limitations of scalar values. With an extension attribute, we can extend both EAV and non-EAV with complex objects.

For example, the gift_message extension attribute added to the order (Magento\Sales\Api\Data\OrderInterface) is of the following type:

<?php
namespace Magento\GiftMessage\Api\Data;

interface MessageInterface 
  extends \Magento\Framework\Api\ExtensibleDataInterface
{
    /**#@+
     * Constants for keys of data array. Identical to the name of the getter in snake case
     */
    const GIFT_MESSAGE_ID = 'gift_message_id';
    const CUSTOMER_ID = 'customer_id';
    const SENDER = 'sender';
    const RECIPIENT = 'recipient';
    const MESSAGE = 'message';
    /**#@-*/

    // ...
}

The price we pay for such flexibility is that extension attribute values persistency needs to be populated programmatically, whereas custom attribute values are loaded and saved automatically.

Refer to the official documentation for more details on how to add extension attributes to entity.

Let’s note that ExtensibleDataInterface doesn’t declare the methods to access extension attributes. Here is its declaration:

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Magento\Framework\Api;

/**
 * Interface for entities which can be extended with extension attributes.
 *
 * @api
 */
interface ExtensibleDataInterface
{
    /**
     * Key for extension attributes object
     */
    const EXTENSION_ATTRIBUTES_KEY = 'extension_attributes';
}

By convention, the methods are named setExtensionAttributes() and getExtensionAttributes() but we can’t give for granted that a class implementing ExtensibleDataInterface provides those methods, so my advice is to double check it.

It’s worth mentioning that to prevent performance degradation while fetching extension attributes in collections, Magento provides a native join functionality (documented here), but this feature is limited to scalar extension attributes.

To find an example, we can look at the declaration of the is_subscribed attribute added to a customer in the module-newsletter/etc/extension_attributes.xml file:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Customer\Api\Data\CustomerInterface">
        <attribute code="is_subscribed" type="boolean" >
            <join reference_table="newsletter_subscriber" 
                  reference_field="customer_id" 
                  join_on_field="entity_id">
                <field>subscriber_status</field>
            </join>
        </attribute>
    </extension_attributes>
</config>

💡 Let’s pay attention: for the join to work, it’s not enough to declare the above join; we also have to pass the collection to the \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface::process() method to have it populated with correct data. We can see an example in the getList() method of \Magento\Catalog\Model\ProductRepository:

<?php
namespace Magento\Catalog\Model;

// ...

class ProductRepository 
  implements \Magento\Catalog\Api\ProductRepositoryInterface
{
    // ...

    public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria)
    {
        /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */
        $collection = $this->collectionFactory->create();
        $this->extensionAttributesJoinProcessor->process($collection);
        // ..
    }

    // ...
}

Another relevant feature is that we can restrict access to the values of an entity’s extension attribute by declaring an ACL resource, as shown in the official documentation.

Where to store extension attributes?

Usually, extension attributes are non-EAV attributes, meaning that we should decide where to persist their values.

If the extension attribute is a complex object, the default choice would be to use a separate custom table.

But if the extension attribute is a scalar, extending core tables with a non-ambiguous custom column is acceptable. This way, persisting values will require less code and will be more performant because it avoids additional join conditions.

There isn’t a golden rule, though; we need to properly analyze every case before making the right decision.

Conclusions

Custom attributes are nothing new in the Magento world: just a new name given to EAV-entity attributes that Magento installation does not create.

Extension attributes, instead, are a new way to extend non-EAV entities.

With extension attributes also comes the possibility to define complex attributes, overcoming the limit of scalar types.

All this comes at a bit of cost: we have to carefully handle persistence to ensure that data is retrieved and saved the way we expect.

We often need to add more variables that we need to use on the checkout page at the time of checkout. Here is how we can do that.

The first step is to add the following code in Vendor/Module/etc/frontend/di.xml of your custom module –

<?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\Checkout\Model\CompositeConfigProvider">
       <arguments>
           <argument name="configProviders" xsi:type="array">
               <item name="additional_provider" xsi:type="object">Armmage\test\Model\AdditionalConfigVars</item>
           </argument>
       </arguments>
   </type>
</config>

After this, we will create AdditionalConfigVars.php in Vendor/Module/Model and add the following code to it –

<?php

namespace Armmage\Test\Model;

use \Magento\Checkout\Model\ConfigProviderInterface

class AdditionalConfigVars implements ConfigProviderInterface
{
   public function getConfig()
   {
       $additionalVariables['test_var'] = 'Test Var';
       return $additionalVariables;
   }
}

Now all you need to do is flush the Magento cache and check  ‘window.checkoutConfig.test_var’ in your js on the checkout page. It will return ‘Test Var’.

This is all for now.

Basic module create –> link

Magento is a fantastic platform for selling online, arguably the best, but there’s one thing that has always left me frustrated as an SEO… That pesky index.php directory in the URL of ALL internal pages – nightmare!

There’s no benefit to them.

They’re bad for SEO, bad for site structure and consistency, and then they’re even worse for a clean URL freak like me. They’re not sexy enough. Let’s clean things up.

SEO Friendly Magento URLs in Two Steps

Fortunately, whilst I was doing a Magento store for a client recently, I did a little bit of digging and found a pretty straightforward solution to the issue. It involves a couple of changes to the Magento admin settings and the addition, or modification, of a simple .htaccess file to sort out of the rewriting of their standard store URLs.

Follow the simple steps below and you’ll be a step closer to SEO success with your own Magento store, and your SEO won’t have an excuse for decreased relevancy.

1) Let’s Change a Setting, Admin

The first thing you need to do is to login to your Magento admin panel (index.php/admin) in order to change a very simple setting which will let Magento know that you intend to use URL rewriting throughout your store rather than their ugly default URLs.

Login, and change this setting:

Go to System > Configuration > Web > Search Engine Optimization

Use Web Server Rewrites: YES

That was easy, wasn’t it? Okay, now for the final step.

2) Let’s Use a .htaccess File to Rewrite the URLs

The final step involves creating a .htaccess file in the Magento installation folder in order to compliment the settings you changed within your admin settings earlier, and this will actually rewrite the URLs. Choose the applicable .htaccess version below.

If your Magento store is installed in root (public_html), use this:

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

If your Magento store is installed in a subfolder (public_html/shop), use this:

RewriteEngine On
RewriteBase /shop/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /shop/index.php [L]

You’re done – hope that helps!

The problem is happening from Magento upgrade v2.3 to v2.4.3-p1.

  1. Open file:
/vendor/magento/framework/Setup/Declaration/Schema/Db/DefinitionAggregator.php

2. Replace function fromDefinition:

			
public function fromDefinition(array $data)
{
	
	$type = $data['type'];
	
	if(in_array($type, ["tinytext", "enum"])){
		$data['type'] = 'text';
		$type = 'text';
	}
	
	if(in_array($type, ['time', 'mediumint'])){
		$data['type'] = 'datetime';
		$type = 'datetime';
	}
	
	if(in_array($type, ['mediumint'])){
		$data['type'] = 'int';
		$type = 'int';
	}
	
	if (!isset($this->definitionProcessors[$type])) {
		throw new \InvalidArgumentException(
			sprintf("Cannot process definition to array for type %s", $type)
		);
	}

	$definitionProcessor = $this->definitionProcessors[$type];
	return $definitionProcessor->fromDefinition($data);
}

I hope it will help you if you have any questions or need development assistance
Contact us

Two days before Canonical dropped the latest and greatest long term service release of Ubuntu, the Node.js Foundation dropped the latest and greatest (and eventually long term service release) of Node.js.

Due to the timing of things, Ubuntu 18.04 LTS was shipped with the current long term service release of Node.js, version 8.x (8.10.0 with the initial release).

This is great news if you’re content running the current long term service release of Node.js, but if you’re like me, you want the latest and greatest!

Side note, if you are good with Node.js 8 but want to run the latest version of the 8.x series, check out this post.

Back on the bleeding edge track, first, make sure you have curl installed:

sudo apt install curl

Then download and execute the Node.js 10.x installer:

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -

This shouldn’t take too long and will add a source file for the official Node.js 10.x repo, grabs the signing key and will run apt update.

Note, if you have used the installer script for an older version of Node.js, running the aforementioned will write over the previous changes.

Once the installer is done doing it’s the thing, you will need to install (or upgrade) Node.js:

sudo apt install nodejs

That’ll do it, you’re all set with the latest and greatest version of Node.js 10.x on Ubuntu 18.04 LTS!

src

First of all, let’s create some basic module and add order attribute into the database
See for the basic module here >>

Magento 2 comes with a new design pattern called the service contracts. A service contract is a set of PHP interfaces used in a module. You can check an interface in any module API folder. Service contract includes service and data interfaces, which hide business logic details.

In Magento 2 You can add extension attributes for Order by creating an extension_attributes.xml file. Extension attributes are the persistent Attribute so you can’t find extension_attributes values in a database.

Let’s assume we need to add a new Order Comment field to order entity.

You need to use interface Magento\Sales\Api\Data\OrderInterface for add extension_attributes in Order entity. Thus, we need to define our order_comment extension attribute for the order extensible data object.
FilePath: app/code/Rbj/OrderComment/etc/extension_attributes.xml


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Sales\Api\Data\OrderInterface">
        <attribute code="order_comment" type="string" />
    </extension_attributes>
</config>

Using above action we will define the additional setOrderComment( ) and getOrderComment( ) for auto-generated Magento\Sales\Api\Data\OrderExtension class.

We need to add the custom order_comment field value during the order data loaded. For this purpose, we need to create a plugin to get( ) and getList ( ) methods of order repository class. The plugin declaration is the following in global scope area,

File Path: app/code/Armmage/OrderFeedback/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\Sales\Api\OrderRepositoryInterface">
        <plugin name="ordercomment_extension_attribute"
                type="Armmage\OrderComment\Plugin\OrderRepositoryPlugin" />
    </type>
</config>

The afterGet and afterGetList methods will be called after the corresponding repository methods execution. So, this way we can affect the results:

/* File: app/code/Armmage/OrderFeedback/Plugin/OrderRepositoryPlugin.php */
 
namespace Rbj\OrderComment\Plugin;
 
use Magento\Sales\Api\Data\OrderExtensionFactory;
use Magento\Sales\Api\Data\OrderExtensionInterface;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\Data\OrderSearchResultInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
 
/**
 * Class OrderRepositoryPlugin
 */
class OrderRepositoryPlugin
{
    /**
     * Order Comment field name
     */
    const FIELD_NAME = 'order_comment';
 
    /**
     * Order Extension Attributes Factory
     *
     * @var OrderExtensionFactory
     */
    protected $extensionFactory;
 
    /**
     * OrderRepositoryPlugin constructor
     *
     * @param OrderExtensionFactory $extensionFactory
     */
    public function __construct(OrderExtensionFactory $extensionFactory)
    {
        $this->extensionFactory = $extensionFactory;
    }
 
    /**
     * Add "order_comment" extension attribute to order data object to make it accessible in API data of order record
     *
     * @return OrderInterface
     */
    public function afterGet(OrderRepositoryInterface $subject, OrderInterface $order)
    {
        $orderComment = $order->getData(self::FIELD_NAME);
        $extensionAttributes = $order->getExtensionAttributes();
        $extensionAttributes = $extensionAttributes ? $extensionAttributes : $this->extensionFactory->create();
        $extensionAttributes->setOrderComment($orderComment);
        $order->setExtensionAttributes($extensionAttributes);
 
        return $order;
    }
 
    /**
     * Add "order_comment" extension attribute to order data object to make it accessible in API data of all order list
     *
     * @return OrderSearchResultInterface
     */
    public function afterGetList(OrderRepositoryInterface $subject, OrderSearchResultInterface $searchResult)
    {
        $orders = $searchResult->getItems();
 
        foreach ($orders as &$order) {
            $orderComment = $order->getData(self::FIELD_NAME);
            $extensionAttributes = $order->getExtensionAttributes();
            $extensionAttributes = $extensionAttributes ? $extensionAttributes : $this->extensionFactory->create();
            $extensionAttributes->setOrderComment($orderComment);
            $order->setExtensionAttributes($extensionAttributes);
        }
 
        return $searchResult;
    }
}

Once the order entity is loaded, the Order Comment value will be added to the extension attributes data object.

Using the above way, You can get the OrderComment field in any third-party API service also.

source

Create a basic module, see the post

Create

app/code/Armmage/Custom/view/frontend/requirejs-config.js

var config = {
    config: {
        mixins: {
            'Magento_Checkout/js/view/summary/shipping': {
                'Armmage_Custom/js/view/summary/shipping-mixin': true
            },
            'Magento_Checkout/js/view/shipping-information': {
                'Armmage_Custom/js/view/summary/shipping-information-mixin': true
            },
        }
    }
};

create The files

app/code/Armmage/Custom/view/frontend/web/js/view/summary/shipping-information-mixin.js

/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

 define([
    'jquery',
    'uiComponent',
    'Magento_Checkout/js/model/quote',
    'Magento_Checkout/js/model/step-navigator',
    'Magento_Checkout/js/model/sidebar'
], function ($, Component, quote, stepNavigator, sidebarModel) {
    'use strict';

    var mixin = {
      
         /**
         * @return {String}
         */
          getShippingMethodTitle: function () {
            var shippingMethod = quote.shippingMethod();
        
            return shippingMethod ? shippingMethod['carrier_title'] + ' - ' + shippingMethod['method_title'] + ' some title' : '';
        },
    };

    /**
     * Override default getShippingMethodTitle
     */
    return function (OriginShipping) {
        return OriginShipping.extend(mixin);
    };
});

app/code/Armmage/Custom/view/frontend/web/js/view/summary/shipping-mixin.js

/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

 define([
    'mage/utils/wrapper',
    'Magento_Checkout/js/model/quote',
], function (wrapper, quote) {
    'use strict';

    var mixin = {
      
        /**
         * @return {*}
         */
         getShippingMethodTitle: function () {
            var shippingMethod = '',
                shippingMethodTitle = '';

            if (!this.isCalculated()) {
                return '';
            }
            shippingMethod = quote.shippingMethod();

            if (typeof shippingMethod['method_title'] !== 'undefined') {
                shippingMethodTitle = ' - ' + shippingMethod['method_title'];
            }
         
          return shippingMethod ?
          shippingMethod['carrier_title'] + shippingMethodTitle + 'some other title' :
          shippingMethod['carrier_title'];
        },
    };

    /**
     * Override default getShippingMethodTitle
     */
    return function (OriginShipping) {
        return OriginShipping.extend(mixin);
    };
});

Would you like to display another product attribute or a custom one in the checkout summary? Let’s see together how you can do that!

In our example, we will display below the product’s name, the product’s manufacturer. First of all, we have to include the manufacturer attribute in the quote item as in not included by default. So to achieve that we have to create a file under app/code/Armmage/ManufacturerAttriute/etc/catalog_attributes.xml and we add the following code.


<?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="manufacturer"/>
    </group>
</config>

As is well known, Magento 2 checkout is built up from a series of Knockout JS components which are then rendered using the Knockout JS templating system. Magento 2 defines each one of these components and their parent / child relationship in a large XML file which can be extended or overridden in your own theme or module. For Magento 2 checkout this large XML file can be found under

vendor/magento/module-checkout/view/frontend/layout/checkout_index_index.xmlThe definition of component item that is responsible for the summary item details in checkout is the following.<item name=”component” xsi:type=”string”>Armmage_ManufacturerAttriute/js/view/summary/item/details</item>So override this component we will have to create a new checkout_index_index.xml in our module, under
app/code/Armmage/ManufacturerAttriute/view/frontend/layout/checkout_index_index.xml

adding the following code which defines only the path to this component that we need to override.

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="checkout.root">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="checkout" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="sidebar" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="summary" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="cart_items" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="details" xsi:type="array">
                                                            <item name="component"
                                                                  xsi:type="string">Armmage_ManufacturerAttriute/js/view/summary/item/details</item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

As we can see on the code below the value of the component item is a path to JS file where also the template file for this component is declared. As we need to override this template file, this value has path to a JS file in our module. So you can easily copy the 

vendor/magento/module-checkout/view/frontend/web/js/view/summary/item/details.js

under

app/code/Armmage/ManufacturerAttriute/view/frontend/web/js/view/summary/item/details.js

and replace the file’s code with the code below.

*jshint browser:true jquery:true*/
/*global alert*/
define(
    [
        'uiComponent'
    ],
    function (Component) {
        "use strict";
        var quoteItemData = window.checkoutConfig.quoteItemData;
        return Component.extend({
            defaults: {
                template: 'Armmage_ManufacturerAttriute/summary/item/details'
            },
            quoteItemData: quoteItemData,
            getValue: function(quoteItem) {
                return quoteItem.name;
            },
            getManufacturer: function(quoteItem) {
                var item = this.getItem(quoteItem.item_id);
                return item.manufacturer;
            },
            getItem: function(item_id) {
                var itemElement = null;
                _.each(this.quoteItemData, function(element, index) {
                    if (element.item_id == item_id) {
                        itemElement = element;
                    }
                });
                return itemElement;
            }
        });
    }
);

Afterwards, create a html file and name it details.html under

app/code/Armmage/ManufacturerAttriute/view/frontend/web/template/summary/item/details.html

<!-- ko foreach: getRegion('before_details') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
<!-- /ko -->
<div class="product-item-details">

    <div class="product-item-inner">
        <div class="product-item-name-block">
            <strong class="product-item-name" data-bind="text: $parent.name"></strong>
            <!-- ko if: (getManufacturer($parent))-->
                <strong class="product-item-manufacturer" data-bind="text: getManufacturer($parent)"></strong>
            <!-- /ko -->
            <div class="details-qty">
                <span class="label"><!-- ko i18n: 'Qty' --><!-- /ko --></span>
                <span class="value" data-bind="text: $parent.qty"></span>
            </div>
        </div>

        <!-- ko foreach: getRegion('after_details') -->
            <!-- ko template: getTemplate() --><!-- /ko -->
        <!-- /ko -->
    </div>

    <!-- ko if: (JSON.parse($parent.options).length > 0)-->
    <div class="product options" data-bind="mageInit: {'collapsible':{'openedState': 'active'}}">
        <span data-role="title" class="toggle"><!-- ko i18n: 'View Details' --><!-- /ko --></span>
        <div data-role="content" class="content">
            <strong class="subtitle"><!-- ko i18n: 'Options Details' --><!-- /ko --></strong>
            <dl class="item-options">
                <!--ko foreach: JSON.parse($parent.options)-->
                <dt class="label" data-bind="text: label"></dt>
                    <!-- ko if: ($data.full_view)-->
                    <dd class="values" data-bind="html: full_view"></dd>
                    <!-- /ko -->
                    <!-- ko ifnot: ($data.full_view)-->
                    <dd class="values" data-bind="html: value"></dd>
                    <!-- /ko -->
                <!-- /ko -->
            </dl>
        </div>
    </div>
    <!-- /ko -->
</div>

The only change to the original file, which can be found under

vendor/magento/module-checkout/view/frontend/web/template/summary/item/details.html

is that we added to display the product’s manufacturer below the product’s name.

The vendor/magento/module-checkout/Model/DefaultConfigProvider.php class is used for retrieving data in checkout. In this class, the function getConfig() is returning an array of the data which is gonna used in different places in checkout. For the checkout, the summary template is the totalsData output array field. As we can see the product’s manufacturer data is not included in that array. So we have to extend this function by creating a plugin and add the product’s manufacturer to the totalsData. After having a deeper look, we found out that this is gonna work only in the shipping step, as in the payment step, the total data array is set again only with Magento’s default quote total values. So to display the product’s manufacturer in the checkout order summary in both steps we need to add the product’s manufacturer into the quoteItemData array.

Create a di.xml file to declare the plugin.

<?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\Checkout\Model\DefaultConfigProvider">
        <plugin name="checkout-summary-product-attribute" type="Armmage\ManufacturerAttriute\Plugin\Checkout\Model\DefaultConfigProvider" />
    </type>
</config>

Create a class under /app/code/Armmage/ManufacturerAttriute/Plugin/Checkout/Model/DefaultConfigProvider.php with an afterGetConfig() function, where we will add our logic of adding the product’s manufacturer information.

<?php
namespace Armmage\ManufacturerAttriute\Plugin\Checkout\Model;

use Magento\Checkout\Model\Session as CheckoutSession;

class DefaultConfigProvider
{
    /**
     * @var CheckoutSession
     */
    protected $checkoutSession;

    /**
     * Constructor
     *
     * @param CheckoutSession $checkoutSession
     */
    public function __construct(
        CheckoutSession $checkoutSession
    ) {
        $this->checkoutSession = $checkoutSession;
    }

    public function afterGetConfig(
        \Magento\Checkout\Model\DefaultConfigProvider $subject,
        array $result
    ) {
        $items = $result['totalsData']['items'];
        foreach ($items as $index => $item) {
            $quoteItem = $this->checkoutSession->getQuote()->getItemById($item['item_id']);
            $result['quoteItemData'][$index]['manufacturer'] = $quoteItem->getProduct()->getAttributeText('manufacturer');
        }
        return $result;
    }
}

So now the Attribute should be visible.

If you have any questions, just write in comments.

source



<?php

$bootstrap = realpath(__DIR__) . './app/bootstrap.php';
if (is_file($bootstrap )) {
    include $bootstrap 
}
​
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
​
$objectManager = $bootstrap->getObjectManager();
$state = $objectManager->get('Magento\Framework\App\State');
$state->setAreaCode('adminhtml');
$productCollectionFactory = $objectManager->get('\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory');
​
$collection = $productCollectionFactory->create()
->addAttributeToSelect('*')
->addAttributeToFilter('type_id', "[your type ]" );
foreach($collection  as $product){
    $product->setTypeId('simple')->save(); [changed type]
   echo "sku-> ". $product->getSku() ."\n";
}