5

In my magento 2 store I need to return and print a custom product attribute in mini cart for each product in the cart. But it seems data are load using KO js so I have no idea , how to get attribute value please help me

1
  • How to get item attribute values based on store-level on order summary section at checkout Magento 2 Mar 31, 2020 at 10:35

3 Answers 3

2

Whole minicart rendering process is explained clearly here https://mage2.pro/t/topic/905

Under checkout module, you have CustomerData/Cart.php folder which does the rendering of the cart items. Each items are rendered based on the product type.

So, for Example, if you want to modify configurable product, go to configurable product module CustomerData folder.

For simple products, you need to look into the checkout module CustomerData/DefaultItem.php doGetItemData() To load Custom attributes over there and pass it as additional JSON param, you can load the product obj and get the value

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$productObj = $objectManager->get('Magento\Catalog\Model\Product')->load($product_id);
$short_desc = $productObj->getShortDescription();

You need to rewrite the Core modules to add your custom attribute values on minicart.

1
1

I know this is an old question, but since it doesn't have an accepted answer yet, and I ran into the same thing, I figured I'd share my answer here:

@ansar-husain's answer is partially correct. First you need to add your custom attribute to catalog_attributes.xml:

YourName/YourModule/etc/catalog_attributes.xml

<?xml version="1.0" encoding="UTF-8"?>
<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="your_custom_attribute" />
</group>
</config>

Then create a di.xml in the same folder that contains the following:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Checkout\CustomerData\AbstractItem">
        <plugin name="your_module_abstract_item_after_get_item_data" type="YourName\YourModule\Plugin\Checkout\CustomerData\AbstractItem" sortOrder="100" />
    </type>
</config>

Now we need to create the Plugin-class which we defined in our di.xml.

YourName/YourModule/Plugin/Checkout/CustomerData/AbstractItem

<?php
namespace YourName\YourModule\Plugin\Checkout\CustomerData;

use Magento\Checkout\Model\Session;

class AbstractItem
{
    /**
     * AbstractItem constructor.
     *
     * @param Session $session
     */
    public function __construct(
        Session $session
    ) {
        $this->session = $session;
    }

    /**
     * Add Your Custom Attribute to frontend storage (CustomerData)
     *
     * @param $subject
     * @param $item
     *
     * @return array
     * @throws \Magento\Framework\Exception\LocalizedException
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function afterGetItemData($subject, $item)
    {
        $quote = $this->session->getQuote();

        foreach ($quote->getItems() as $quoteItem) {
            $item = array_merge(
                $item,
                [ 'your_custom_attribute' => (bool) $quoteItem->getProduct()->getYourCustomAttribute() ]
            );
        }

        return $item;
    }
}

Now, you can capture the attribute in the frontend by creating your own custom JS component and providing it with the CustomerData component as follows:

define(
    [
        "uiComponent",
        'ko',
        'Magento_Customer/js/customer-data'
    ],
    function(
        Component,
        ko,
        customerData
    ) {
        'use strict';
        return Component.extend({
            checkForYourCustomAttribute: function () {
                var items = customerData.get('cart')().items;

                items.forEach(item => {
                    if (item.your_custom_attribute === true) {
                        return 'Yay!';
                    }
                });

                return 'Aw...';
            }
        });
    }
);

I didn't provide a file path for the code snippet above, because this can be any JS file that you added using map: { '*': { your_component: 'YourName_YourModule/js/your-file } } in requirejs-config.js.

That's it, and it seems like an elegant solution. Hope it helps!

0

For displaying product attribute in minicart

1. Create file catalog_attributes.xml Vendor/Module/etc

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

2.Create di.xml in Vendor/Module/etc

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
   <preference for="Magento\Checkout\CustomerData\DefaultItem" type="Vendor\Module\CustomerData\DefaultItem" />
</config>

3.Create file DefaultItem.php inside Vendor\Module\CustomerData

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

namespace Vendor\Module\CustomerData;

use Magento\Framework\App\ObjectManager;

/**
 * Default item
 */
class DefaultItem extends \Magento\Checkout\CustomerData\DefaultItem
{
         /**
         * @var \Magento\Catalog\Helper\Image
         */
        protected $imageHelper;

        /**
         * @var \Magento\Msrp\Helper\Data
         */
        protected $msrpHelper;

        /**
         * @var \Magento\Framework\UrlInterface
         */
        protected $urlBuilder;

        /**
         * @var \Magento\Catalog\Helper\Product\ConfigurationPool
         */
        protected $configurationPool;

        /**
         * @var \Magento\Checkout\Helper\Data
         */
        protected $checkoutHelper;

        /**
         * Escaper
         *
         * @var \Magento\Framework\Escaper
         */
        private $escaper;
    public function __construct(
        \Magento\Catalog\Helper\Image $imageHelper,
        \Magento\Msrp\Helper\Data $msrpHelper,
        \Magento\Framework\UrlInterface $urlBuilder,
        \Magento\Catalog\Helper\Product\ConfigurationPool $configurationPool,
        \Magento\Checkout\Helper\Data $checkoutHelper,
        \Magento\Framework\Escaper $escaper = null
    ) {
        $this->configurationPool = $configurationPool;
        $this->imageHelper = $imageHelper;
        $this->msrpHelper = $msrpHelper;
        $this->urlBuilder = $urlBuilder;
        $this->checkoutHelper = $checkoutHelper;
        $this->escaper = $escaper ?: ObjectManager::getInstance()->get(\Magento\Framework\Escaper::class);
    }

    protected function doGetItemData()
    {
        $imageHelper = $this->imageHelper->init($this->getProductForThumbnail(), 'mini_cart_product_thumbnail');
        $productName = $this->escaper->escapeHtml($this->item->getProduct()->getName());

        return [
            'options' => $this->getOptionList(),
            'qty' => $this->item->getQty() * 1,
            'item_id' => $this->item->getId(),
            'configure_url' => $this->getConfigureUrl(),
            'is_visible_in_site_visibility' => $this->item->getProduct()->isVisibleInSiteVisibility(),
            'product_id' => $this->item->getProduct()->getId(),
            'product_name' => $productName,
            'product_sku' => $this->item->getProduct()->getSku(),
            'product_url' => $this->getProductUrl(),
            'product_has_url' => $this->hasProductUrl(),
            'product_price' => $this->checkoutHelper->formatPrice($this->item->getCalculationPrice()),
            'product_price_value' => $this->item->getCalculationPrice(),
            'product-attribute' => $this->item->getProduct()->getProductAttribute(),
            'product_image' => [
                'src' => $imageHelper->getUrl(),
                'alt' => $imageHelper->getLabel(),
                'width' => $imageHelper->getWidth(),
                'height' => $imageHelper->getHeight(),
            ],
            'canApplyMsrp' => $this->msrpHelper->isShowBeforeOrderConfirm($this->item->getProduct())
                && $this->msrpHelper->isMinimalPriceLessMsrp($this->item->getProduct()),
        ];
    }

}
?>

4.Create File defualt.html inside Current Theme app/design/frontend/Vendor/Themename/Magento_Checkout/web/template/minicart/item

<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<li class="item product product-item" data-role="product-item">
    <div class="product">
        <!-- ko if: product_has_url -->
        <a data-bind="attr: {href: product_url, title: product_name}" tabindex="-1" class="product-item-photo">
            <!-- ko foreach: $parent.getRegion('itemImage') -->
                <!-- ko template: {name: getTemplate(), data: item.product_image} --><!-- /ko -->
            <!-- /ko -->
        </a>
        <!-- /ko -->
        <!-- ko ifnot: product_has_url -->
        <span class="product-item-photo">
            <!-- ko foreach: $parent.getRegion('itemImage') -->
                <!-- ko template: {name: getTemplate(), data: item.product_image} --><!-- /ko -->
            <!-- /ko -->
        </span>
        <!-- /ko -->

        <div class="product-item-details">
            <strong class="product-item-name">
                <!-- ko if: product_has_url -->
                <a data-bind="attr: {href: product_url}, html: product_name"></a>
                <!-- /ko -->
                <!-- ko ifnot: product_has_url -->
                    <!-- ko text: product_name --><!-- /ko -->
                <!-- /ko -->
            </strong>

            <!-- ko if: options.length -->
            <div class="product options" data-mage-init='{"collapsible":{"openedState": "active", "saveState": false}}'>
                <span data-role="title" class="toggle"><!-- ko i18n: 'See Details' --><!-- /ko --></span>

                <div data-role="content" class="content">
                    <strong class="subtitle"><!-- ko i18n: 'Options Details' --><!-- /ko --></strong>
                    <dl class="product options list">
                        <!-- ko foreach: { data: options, as: 'option' } -->
                        <dt class="label"><!-- ko text: option.label --><!-- /ko --></dt>
                        <dd class="values">
                            <!-- ko if: Array.isArray(option.value) -->
                                <span data-bind="html: option.value.join('<br>')"></span>
                            <!-- /ko -->
                            <!-- ko ifnot: Array.isArray(option.value) -->
                                <span data-bind="html: option.value"></span>
                            <!-- /ko -->
                        </dd>
                        <!-- /ko -->
                    </dl>
                </div>
            </div>
            <!-- /ko -->
            <!-- ko if: product-attribute -->
            <div data-bind="html: 'Product Attribute : ' + product-attribute"></div>
            <!-- /ko -->
            <div class="product-item-pricing">
                <!-- ko if: canApplyMsrp -->

                <div class="details-map">
                    <span class="label" data-bind="i18n: 'Price'"></span>
                    <span class="value" data-bind="i18n: 'See price before order confirmation.'"></span>
                </div>
                <!-- /ko -->
                <!-- ko ifnot: canApplyMsrp -->
                <!-- ko foreach: $parent.getRegion('priceSidebar') -->
                    <!-- ko template: {name: getTemplate(), data: item.product_price, as: 'price'} --><!-- /ko -->
                <!-- /ko -->
                <!-- /ko -->

                <div class="details-qty qty">
                    <label class="label" data-bind="i18n: 'Qty', attr: {
                           for: 'cart-item-'+item_id+'-qty'}"></label>
                    <input data-bind="attr: {
                           id: 'cart-item-'+item_id+'-qty',
                           'data-cart-item': item_id,
                           'data-item-qty': qty,
                           'data-cart-item-id': product_sku
                           }, value: qty"
                           type="number"
                           size="4"
                           class="item-qty cart-item-qty">
                    <button data-bind="attr: {
                           id: 'update-cart-item-'+item_id,
                           'data-cart-item': item_id,
                           title: $t('Update')
                           }"
                            class="update-cart-item"
                            style="display: none">
                        <span data-bind="i18n: 'Update'"></span>
                    </button>
                </div>
            </div>

            <div class="product actions">
                <!-- ko if: is_visible_in_site_visibility -->
                <div class="primary">
                    <a data-bind="attr: {href: configure_url, title: $t('Edit item')}" class="action edit">
                        <span data-bind="i18n: 'Edit'"></span>
                    </a>
                </div>
                <!-- /ko -->
                <div class="secondary">
                    <a href="#" data-bind="attr: {'data-cart-item': item_id, title: $t('Remove item')}"
                       class="action delete">
                        <span data-bind="i18n: 'Remove'"></span>
                    </a>
                </div>
            </div>
        </div>
    </div>
</li>
2
  • 1
    This isn't the correct way to do this. You can't overwritte protected method with di.xml preference. He needs to create plugin for Magento\Checkout\CustomerData\AbstractItem::getItemData() which calls doGetItemData() to modify it
    – Trenox
    Oct 18, 2018 at 10:47
  • How to get item attribute values based on store-level on order summary section at checkout Magento 2 Mar 31, 2020 at 10:34

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.