1

I am trying to implement Extention Attributes. I want to send the e-mail and a subscribe boolean to the backend in the checkout.

In ShippingInformationManagementPlugin the var_dump(getExtensionAttributes()) returns null. When I look in $addressInformation I also see the extention attributes as null.

model/shipping-save-processor/default.js

 define([
'ko',
'Magento_Checkout/js/model/quote',
'Magento_Checkout/js/model/resource-url-manager',
'mage/storage',
'Magento_Checkout/js/model/payment-service',
'Magento_Checkout/js/model/payment/method-converter',
'Magento_Checkout/js/model/error-processor',
'Magento_Checkout/js/model/full-screen-loader',
'Magento_Checkout/js/action/select-billing-address',
'Magento_Checkout/js/model/shipping-save-processor/payload-extender',
'jquery'
], function (
ko,
quote,
resourceUrlManager,
storage,
paymentService,
methodConverter,
errorProcessor,
fullScreenLoader,
selectBillingAddressAction,
payloadExtender,
$
 ) {
'use strict';

return {
    /**
     * @return {jQuery.Deferred}
     */
    saveShippingInformation: function () {
        var payload;

        if (!quote.billingAddress()) {
            selectBillingAddressAction(quote.shippingAddress());
        }

        console.log('E-mail:', $('[name="username"]').val());
        console.log('Subscribe:', Boolean($('[name="newsletter-subscribe"]').attr('checked')));

        payload = {
            addressInformation: {
                shipping_address: quote.shippingAddress(),
                billing_address: quote.billingAddress(),
                shipping_method_code: quote.shippingMethod().method_code,
                shipping_carrier_code: quote.shippingMethod().carrier_code,
                extension_attributes: {
                    email: $('[name="username"]').val(),
                    subscribe: Boolean($('[name="newsletter-subscribe"]').attr('checked'))
                }
            }
        };

        payloadExtender(payload);

        fullScreenLoader.startLoader();

        return storage.post(
            resourceUrlManager.getUrlForSetShippingInformation(quote),
            JSON.stringify(payload)
        ).done(
            function (response) {
                quote.setTotals(response.totals);
                paymentService.setPaymentMethods(methodConverter(response['payment_methods']));
                fullScreenLoader.stopLoader();
            }
        ).fail(
            function (response) {
                errorProcessor.process(response);
                fullScreenLoader.stopLoader();
            }
        );
    }
};
 });

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\Checkout\Api\Data\ShippingInformationInterface">
    <attribute code="email" type="string" />
    <attribute code="subscribe" type="boolean" />
</extension_attributes>

Model/Checkout/ShippingInformationManagementPlugin.php

<?php

namespace BB\Checkout\Model\Checkout;

class ShippingInformationManagementPlugin
{
protected $quoteRepository;

/**
 * @var \Magento\Newsletter\Model\SubscriberFactory
 */
protected $subscriberFactory;

public function __construct(
    \Magento\Quote\Model\QuoteRepository $quoteRepository,
    \Magento\Newsletter\Model\SubscriberFactory $subscriberFactory,
    \Magento\Framework\Api\ExtensionAttributesFactory $extensionAttributesFactory,
    \Magento\Framework\Event\Observer $observer
) {
    $this->quoteRepository = $quoteRepository;
    $this->subscriberFactory = $subscriberFactory;
    $this->extensionAttributesFactory = $extensionAttributesFactory;
    $this->observer = $observer;
}

/**
 * @param \Magento\Checkout\Model\ShippingInformationManagement $subject
 * @param $cartId
 * @param \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
 */
public function beforeSaveAddressInformation(
    \Magento\Checkout\Model\ShippingInformationManagement $subject,
    $cartId,
    \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
) {
    $extAttributes = $addressInformation->getExtensionAttributes();

    $email = $extAttributes->getEmail();

    var_dump(getExtensionAttributes()); die();
}
}

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\Checkout\Model\ShippingInformationManagement">
    <plugin name="save-in-quote" type="BB\Checkout\Model\Checkout\ShippingInformationManagementPlugin" sortOrder="10"/>
</type>
</config>

Am I missing something?

1
  • When plugin ProcessorLayout ? Jun 5, 2018 at 9:51

3 Answers 3

8

While Aleksandr's answer works, this approach overrides the entire payload-extender.js file which is not the intended purpose of this. This approach, if used among multiple extensions on your site at the same time, will have a "winner takes all" result in that only one extension will be allowed to add its own extension attributes.

The purpose of this payload-extender to be used with a mixin to add your extension_attributes after the original payload-extender has been called.

// VendorName/ModuleName/view/frontend/requirejs-config.js
var config = {
    config: {
        mixins: {
            'Magento_Checkout/js/model/shipping-save-processor/payload-extender': {
                'VendorName_ModuleName/js/model/shipping-save-processor/payload-extender-mixin': true
            }
        }
    }
};
// VendorName/ModuleName/view/frontend/web/js/model/shipping-save-processor/payload-extender-mixin.js
define([
    'jquery',
    'mage/utils/wrapper'
], function ($, wrapper) {
    'use strict';

    return function (payloadExtender) {
        return wrapper.wrap(payloadExtender, function (originalAction, payload) {
            payload = originalAction(payload);

            // Add your values to the payload here

            return payload;
        });
    };
});

Credit goes to Briteskies LLC for their contribution to Magento's code base for this feature.

2
  • For example to use it we can add our value like this payload.addressInformation.extension_attributes.delivery_message = delivery_message_value; return payload;
    – Abbas
    Jul 2, 2020 at 7:17
  • This is the correct answer as of 2020. Although in development you might want to map your extension attributes initially to get to see if the backend part of your module works. In final tidy up this is the definitive approach. Including Abbas comment - that is useful too.
    – Theodores
    Aug 19, 2020 at 9:26
5

In Magento v2.2.2 payload extender has been added to checkout. This feature allows third-party extension to modify the payload for the shipping address selection process. Magento Open Source 2.2.2 Release Notes

So, now it can be done more easily, just override payload-extender, creating Vendor/Module/view/base/requirejs-config.js

var config = {
   map: {
      "*": {
         'Magento_Checkout/js/model/shipping-save-processor/payload-extender': 'Vendor_Module/js/model/shipping-save-processor/payload-extender-override'
      }
   }
};

and add your data to extension_attributes in Vendor/Module/view/base/web/js/model/shipping-save-processor/payload-extender-override.js

define([
    'jquery',
], function ($) {
    'use strict';
    return function (payloadExtender) {
        payloadExtender.addressInformation['extension_attributes'] = {
            custom_attribute: $('[name="custom-attribute"]').val()
        };

        return payloadExtender;
    };
});
1
  • 1
    Please see my answer for an approach that utilizes a mixin rather than overriding the original payload-extender.js file. Oct 28, 2019 at 17:09
2

Apparently the only use of

payloadExtender(payload);

in default.js is to empty out the extension_attributes.... Why Magento?!

/js/model/shipping-save-processor/payload-extender.js

define(function () {
    'use strict';

    return function (payload) {
        payload.addressInformation['extension_attributes'] = {};

        return payload;
    };
});

By deleting that it works.

1
  • 2
    payload-extender was intended to be used with mixins to add attributes to it after the original payload-extender is called. More information can be found here: github.com/Briteskies-LLC/… Oct 28, 2019 at 16:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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