5

I have created custom shipping method.

I want to add additional comment after shipping method name.

Following xml file Vendor_Namespace\etc\adminhtml\system.xml

<group id="flatrate2" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
  <field id="name" translate="label" type="text" sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1">
    <label>Method Name</label>
    <depends>
      <field id="active">1</field>
    </depends>
  </field>
  <field id="addcomment" translate="label" type="text" sortOrder="15" showInDefault="1" showInWebsite="1" showInStore="0">
    <label>Comment</label>
    <depends>
      <field id="active">1</field>
    </depends>
  </field>
</group>

I want addcomment field in shipping.html

Following js file Vendor_Namespace\js\view\checkout\shipping\additional-block.js

define([
    'uiComponent'

], function (Component) {
    'use strict';

    return Component.extend({
        defaults: {
            template: 'Vendor_Namespace/checkout/shipping/additional-block'
        }
    });
});

Following html file Vendor_Namespace\template\checkout\shipping\additional-block.html

<div class="checkout-block" id="block-custom">
   <span> Addtional Comment </span>
</div>

Following layout file Vendor\Namespace\view\frontend\layout\checkout_index_index.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" 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="steps" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="shipping-step" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="shippingAddress" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="shippingAdditional" xsi:type="array">
                                                            <item name="component" xsi:type="string">uiComponent</item>
                                                            <item name="displayArea" xsi:type="string">shippingAdditional</item>
                                                            <item name="children" xsi:type="array">
                                                                <item name="additional_block" xsi:type="array">
                                                                    <item name="component" xsi:type="string">Vendor_Namespace/js/view/checkout/shipping/additional-block</item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

I want Custom Comment value in additional-block.html file.

How can I apply it ?

enter image description here

12

I am not sure if you can achieve that. Table with carrier rates is rendered based on rest request to rest/en/V1/guest-carts/estimate-shipping-methods. You need to add extension attributes to ShippingMethodInterface and add your extension attributes for the output of ShipmentEstimationInterface::estimateByExtendedAddress and ShippingMethodManagementInterface::estimateByAddressId. Then you'd need to override html file that is used for rendering (magento/module-checkout/view/frontend/web/template/shipping.html either by changing elementTmplconfig in xml file or by creating the file in the correct path in your design folder) and change structure of the table by adding additional column.

[EDIT]

I am not sure if you still haven't found the answer but here is what need to be done to achieve this. Since I do not knwo what exactly do you want to display I will provide an example for adding information about delivery time for each carrier.

First we need to include data we want to display to the rest request for shipping rates. Magento can makes rest call to 2 endpoint depending on whether you are logged in and using saved address or not. One request is processed by Magento\Quote\Model\ShippingMethodManagement class. Whichever method is actually used they all fetch rates from magento and create a list of Magento\Quote\Api\Data\ShippingMethodInterface objects. Luckily for us this interface extends Magento\Framework\Api\ExtensibleDataInterface so we can use magento2 extension attributes feature to hook in and add whatever we want.

In file Vendor/Namespace/etc/extension_attributes.xml I add the following configuration

<?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\Quote\Api\Data\ShippingMethodInterface">
        <attribute code="delivery_time" type="string" />
    </extension_attributes>
</config>

This will inform magento that we want to allow delivery_date attribute to be in the api rest output. Without that definition whatever we add to the ShippingMethodInterface object will be filtered out by magento and won't appear in the response.

Now we need to actually create some logic and insert data to the response. Since there are several methods which can be called from the frontend the best way to do this is to hook into Magento\Quote\Model\Cart\ShippingMethodConverter::modelToDataObject() method. This method is called in each function that handles the request and actually it creates ShippingMethodInterface object from data fetch from the carrier rate collector. We will define a plugin in Vendor/Namespace/etc/webapi_rest/di.xml (this could also be defined in etc/di.xml but moving the plugin definition to webapi_rest scope will run it only for rest calls.

<?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\Cart\ShippingMethodConverter">
        <plugin name="add_delivery_date_to_carrier" type="Vendor\Namespace\Plugin\Carrier\DeliveryDate" disabled="false" sortOrder="30"/>
    </type>
</config>

So now we create the file

<?php

namespace Vendor\Namespace\Plugin\Carrier;

use Magento\Quote\Model\Cart\ShippingMethodConverter;
use Magento\Quote\Api\Data\ShippingMethodInterface;
use Magento\Quote\Api\Data\ShippingMethodExtensionFactory;

class DeliveryDate
{
    /**
     * @var ShippingMethodExtensionFactory
     */
    protected $extensionFactory;

    /**
     * DeliveryDate constructor.
     * 
     * @param ShippingMethodExtensionFactory $extensionFactory
     */
    public function __construct(ShippingMethodExtensionFactory $extensionFactory)
    {
        $this->extensionFactory = $extensionFactory;
    }

    /**
     * Add delivery date information to the carrier data object
     * 
     * @param ShippingMethodConverter $subject
     * @param ShippingMethodInterface $result
     * @return ShippingMethodInterface
     */
    public function afterModelToDataObject(ShippingMethodConverter $subject, ShippingMethodInterface $result)
    {
        $extensibleAttribute =  ($result->getExtensionAttributes())
            ? $result->getExtensionAttributes()
            : $this->extensionFactory->create();

        $extensibleAttribute->setDeliveryTime(rand(1,5) . " days");

        $result->setExtensionAttributes($extensibleAttribute);

        return $result;
    }
}

The plugin hooks after modelToDataObject method which returns ShippingMethodInterface with single carrier data. From this object we try to get ExtensionAttributes object as other modules might have defined their own extension attributes and already added values. If not we create new object from factory class. This factory class will be generated by magento and can be found in var/generation folder after doing setup di:compile command. The logic here is simple, you can use any kind of custom logic you want. The most important part of this method however is to not forget returning the modified object. Otherwise we will see empty response as nothing will be passed from the call.

Ok. So now we have reponse like this:

[{
    "carrier_code": "flatrate",
    "method_code": "flatrate",
    "carrier_title": "UPS/GLS",
    "amount": 9.5,
    "base_amount": 9.5,
    "available": 1,
    "extension_attributes": {
        "delivery_time": "2 days"
    },
    "error_message": "",
    "price_excl_tax": 9.5,
    "price_incl_tax": 11.69,
}]

It's time to show it on the screen. And here is the biggest problem, we cannot easily (or at least I haven't found a way) hook data into the table. We need to replace template file that defines shipping methods table with our own. This can obviously cause conflicts with other modules as well be a reason why our changes won't be visible with custom checkout module (like one step checkout implementation). To make it work with magento default checkout we need to create file Vendor/Namespace/view/frontend/layout/checkout_index_index.xml with the following content

<?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="steps" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="shipping-step" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="shippingAddress" xsi:type="array">
                                                    <item name="config" xsi:type="array">
                                                        <item name="template" xsi:type="string">Vendor_Namespace/shipping</item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

What we actually do here is only changing the html file that will be used by the shipping section. Default file is defined in Magento_Checkout/view/frontend/web/js/view/shipping.js file. The path we provided resolves to file Vendor/Namespace/view/frontend/web/template/shipping.html. Here is the content of the file.

        <!-- ko if: (!quoteIsVirtual) -->
        <!-- ko foreach: getRegion('customer-email') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->
        <!--/ko-->

        <!-- ko foreach: getRegion('address-list') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->

        <!-- ko foreach: getRegion('address-list-additional-addresses') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->

        <!-- Address form pop up -->
        <!-- ko if: (!isFormInline) -->
        <button type="button"
                data-bind="click: showFormPopUp, visible: !isNewAddressAdded()"
                class="action action-show-popup">
            <span data-bind="i18n: 'New Address'"></span></button>
        <div id="opc-new-shipping-address" data-bind="visible: isFormPopUpVisible()">
            <!-- ko template: 'Magento_Checkout/shipping-address/form' --><!-- /ko -->
        </div>
        <!-- /ko -->

        <!-- ko foreach: getRegion('before-form') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->

        <!-- Inline address form -->
        <!-- ko if: (isFormInline) -->
        <!-- ko template: 'Magento_Checkout/shipping-address/form' --><!-- /ko -->
        <!-- /ko -->
    </div>
</li>


<!--Shipping method template-->
<li id="opc-shipping_method"
    class="checkout-shipping-method"
    data-bind="fadeVisible: visible(), blockLoader: isLoading"
    role="presentation">
    <div class="checkout-shipping-method">
        <div class="step-title" data-bind="i18n: 'Shipping Methods'" data-role="title"></div>
        <!-- ko foreach: getRegion('before-shipping-method-form') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!-- /ko -->
        <div id="checkout-step-shipping_method"
             class="step-content"
             data-role="content"
             role="tabpanel"
             aria-hidden="false">
            <!-- ko if: rates().length  -->
            <form class="form methods-shipping" id="co-shipping-method-form" data-bind="submit: setShippingInformation" novalidate="novalidate">
                <div id="checkout-shipping-method-load">
                    <table class="table-checkout-shipping-method">
                        <thead>
                        <tr class="row">
                            <th class="col col-method" data-bind="i18n: 'Select Method'"></th>
                            <th class="col col-price" data-bind="i18n: 'Price'"></th>
                            <th class="col col-method" data-bind="i18n: 'Method Title'"></th>
                            <th class="col col-carrier" data-bind="i18n: 'Carrier Title'"></th>
                            <th class="col col-delivery" data-bind="i18n: 'Delivery Date'"></th>
                        </tr>
                        </thead>
                        <tbody>

                        <!--ko foreach: { data: rates(), as: 'method'}-->
                        <tr class="row" data-bind="click: $parent.selectShippingMethod">
                            <td class="col col-method">
                                <!-- ko ifnot: method.error_message -->
                                <!-- ko if: $parent.rates().length == 1 -->
                                <input class="radio"
                                       type="radio"
                                       data-bind="attr: {
                                                    checked: $parent.rates().length == 1,
                                                    'value' : method.carrier_code + '_' + method.method_code,
                                                    'id': 's_method_' + method.method_code,
                                                    'aria-labelledby': 'label_method_' + method.method_code + '_' + method.carrier_code + ' ' + 'label_carrier_' + method.method_code + '_' + method.carrier_code
                                                 }" />
                                <!-- /ko -->
                                <!--ko ifnot: ($parent.rates().length == 1)-->
                                <input type="radio"
                                       data-bind="
                                                value: method.carrier_code + '_' + method.method_code,
                                                checked: $parent.isSelected,
                                                attr: {
                                                    'id': 's_method_' + method.carrier_code + '_' + method.method_code,
                                                    'aria-labelledby': 'label_method_' + method.method_code + '_' + method.carrier_code + ' ' + 'label_carrier_' + method.method_code + '_' + method.carrier_code
                                                },
                                                click: $parent.selectShippingMethod"
                                       class="radio"/>
                                <!--/ko-->
                                <!-- /ko -->
                            </td>
                            <td class="col col-price">
                                <!-- ko foreach: $parent.getRegion('price') -->
                                <!-- ko template: getTemplate() --><!-- /ko -->
                                <!-- /ko -->
                            </td>

                            <td class="col col-method"
                                data-bind="text: method.method_title, attr: {'id': 'label_method_' + method.method_code + '_' + method.carrier_code}"></td>

                            <td class="col col-carrier"
                                data-bind="text: method.carrier_title, attr: {'id': 'label_carrier_' + method.method_code + '_' + method.carrier_code}"></td>

                            <td class="col col-delivery"
                                data-bind="text: method.extension_attributes.delivery_time"></td>
                        </tr>

                        <!-- ko if:  method.error_message -->
                        <tr class="row row-error">
                            <td class="col col-error" colspan="4">
                                <div class="message error">
                                    <div data-bind="text: method.error_message"></div>
                                </div>
                                <span class="no-display">
                                    <input type="radio" data-bind="attr: {'value' : method.method_code, 'id': 's_method_' + method.method_code}"/>
                                </span>
                            </td>
                        </tr>
                        <!-- /ko -->

                        <!-- /ko -->
                        </tbody>
                    </table>
                </div>

                <div id="onepage-checkout-shipping-method-additional-load">
                    <!-- ko foreach: getRegion('shippingAdditional') -->
                    <!-- ko template: getTemplate() --><!-- /ko -->
                    <!-- /ko -->
                </div>
                <!-- ko if: errorValidationMessage().length > 0 -->
                <div class="message notice">
                    <span><!-- ko text: errorValidationMessage()--><!-- /ko --></span>
                </div>
                <!-- /ko -->
                <div class="actions-toolbar" id="shipping-method-buttons-container">
                    <div class="primary">
                        <button data-role="opc-continue" type="submit" class="button action continue primary">
                            <span><!-- ko i18n: 'Next'--><!-- /ko --></span>
                        </button>
                    </div>
                </div>
            </form>
            <!-- /ko -->
            <!-- ko ifnot: rates().length > 0 --><div class="no-quotes-block"><!-- ko i18n: 'Sorry, no quotes are available for this order at this time'--><!-- /ko --></div><!-- /ko -->
        </div>
    </div>
</li>

I used default file from Magento_Checkout module and added 2 elements: <th class="col col-delivery" data-bind="i18n: 'Delivery Date'"></th> and <td class="col col-delivery"data-bind="text: method.extension_attributes.delivery_time"></td>

I hope this will be detailed enough to make it work with whatever data you want to display.

  • can you please elaborate ? – Hardik Visa Feb 13 '17 at 13:21
  • @NewBeeInMagento sorry for the delay but I prepared and tested the solution. – Zefiryn Feb 15 '17 at 23:16
  • I modified question I want addcomment field from admin – Hardik Visa Feb 16 '17 at 5:47
  • Logic for fetching data to show should be inside plugin class. You can inject any additional classes and use them to prepare data as you want. – Zefiryn Feb 16 '17 at 7:09
  • I fetched data which I want thank you for you answer – Hardik Visa Feb 16 '17 at 10:05
0

One Important thing if you create your di.xml in

Vendor/Namespace/etc/webapi_rest/di.xml

You were able to add extra parameter only on API call. on page load, your data will not be added into the response. for that you need to create di.xml on below path.

Vendor/Namespace/etc/di.xml

Thanks

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.