I have finally gave up. I spent 2 whole days trying to do this but I finally could not.
I am developing a custom payment method which needs to show instructions for the customer before the actual purchase.
That simple thing could not be made.
First, this is the layout definition (checkout_index_index.xml):
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/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="billing-step" xsi:type="array"> <item name="component" xsi:type="string">uiComponent</item> <item name="children" xsi:type="array"> <item name="payment" xsi:type="array"> <item name="children" xsi:type="array"> <item name="renders" xsi:type="array"> <!-- merge payment method renders here --> <item name="children" xsi:type="array"> <item name="desytec_transbank_methods" xsi:type="array"> <item name="component" xsi:type="string">Desytec_Transbank/js/view/payment/method-renderer</item> <item name="methods" xsi:type="array"> <item name="webpay" xsi:type="array"> <item name="isBillingAddressRequired" xsi:type="boolean">true</item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </argument> </arguments> </referenceBlock> </body> </page>
The renderer is:
define( [ 'uiComponent', 'Magento_Checkout/js/model/payment/renderer-list' ], function ( Component, rendererList ) { 'use strict'; rendererList.push( { type: 'webpay', component: 'Desytec_Transbank/js/view/payment/method-renderer/webpay' } ); return Component.extend({}); } );
And the webpay renderer is:
/*browser:true*/ /*global define*/ define( [ 'ko', 'Magento_Checkout/js/view/payment/default', ], function (ko, Component) { return Component.extend({ defaults: { template: 'Desytec_Transbank/payment/webpay' }, /** * Get value of instruction field. * @returns {String} */ getInstructions: function () { return window.checkoutConfig.payment.instructions[this.item.method]; } }); } );
The template is:
<div class="payment-method" data-bind="css: {'_active': (getCode() == isChecked())}"> <div class="payment-method-title field choice"> <input type="radio" name="payment[method]" class="radio" data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()"/> <label data-bind="attr: {'for': getCode()}" class="label"><span data-bind="text: getTitle()"></span></label> </div> <div class="payment-method-content"> <div class="payment-method-billing-address"> <!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) --> <!-- ko template: getTemplate() --><!-- /ko --> <!--/ko--> </div> <p data-bind="html: getInstructions()"></p> <div class="checkout-agreements-block"> <!-- ko foreach: $parent.getRegion('before-place-order') --> <!-- ko template: getTemplate() --><!-- /ko --> <!--/ko--> </div> <div class="actions-toolbar"> <div class="primary"> <button class="action primary checkout" type="submit" data-bind=" click: placeOrder, attr: {title: $t('Place Order')}, css: {disabled: !isPlaceOrderActionAllowed()}, enable: (getCode() == isChecked()) " disabled> <span data-bind="text: $t('Place Order')"></span> </button> </div> </div> </div> </div>
And finally, this is the block:
<?php /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ namespace Desytec\Transbank\Block\Form; /** * Abstract class for Cash On Delivery and Bank Transfer payment method form */ abstract class Transbank extends \Magento\Payment\Block\Form { /** * Instructions text * * @var string */ protected $_instructions; protected $_template = 'form/webpay.phtml'; /** * Get instructions text from config * * @return null|string */ public function getInstructions() { if ($this->_instructions === null) { /** @var \Magento\Payment\Model\Method\AbstractMethod $method */ $method = $this->getMethod(); $this->_instructions = $method->getConfigData('instructions'); } return $this->_instructions; } }
What is missing here?
Regards
Jaime
As you can see from your code, the instructions are not passed from PHP (server) to JavaScript (browser).
You should pass it through a config provider: https://mage2.pro/t/630
https://mage2.pro/tags/checkout-config-provider
Thanks, it does not work, or it is not clear at all.
I have added a di.xml file:
<?xml version="1.0"?> <!-- /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ --> <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="offline_payment_instructions_config_provider" xsi:type="object">Desytec\Transbank\Model\InstructionsConfigProvider</item> </argument> </arguments> </type> </config>
Then, I added the model:
<?php /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ namespace Desytec\Transbank\Model; use Magento\Checkout\Model\ConfigProviderInterface; use Magento\Framework\Escaper; use Magento\Payment\Helper\Data as PaymentHelper; class InstructionsConfigProvider implements ConfigProviderInterface { /** * @var string[] */ protected $methodCodes = [ WebPay::CODE, ]; /** * @var \Magento\Payment\Model\Method\AbstractMethod[] */ protected $methods = []; /** * @var Escaper */ protected $escaper; /** * @param PaymentHelper $paymentHelper * @param Escaper $escaper */ public function __construct( PaymentHelper $paymentHelper, Escaper $escaper ) { $this->escaper = $escaper; foreach ($this->methodCodes as $code) { $this->methods[$code] = $paymentHelper->getMethodInstance($code); } } /** * {@inheritdoc} */ public function getConfig() { $config = []; foreach ($this->methodCodes as $code) { if ($this->methods[$code]->isAvailable()) { $config['payment']['instructions'][$code] = $this->getInstructions($code); } } return $config; } /** * Get instructions text from config * * @param string $code * @return string */ protected function getInstructions($code) { return nl2br($this->escaper->escapeHtml($this->methods[$code]->getInstructions())); } }
I have copied them from banktransfer payment method. Other code that your page shows is not really useful, since they belong to magento2 core.
I think a little explanation is missing besides just put some lines of code.
Thanks
And finally, I gave up again. It was impossible.
How can I expose getInstructions() method to JS? it seems it is defined in Magento core as a default implementation, but how can I actually call it?
Thanks
Jaime
I had the same mistake as you and finally found where I was wrong.
In fact, I've put the di.xml file (with config provider path) into etc folder. But to make it work, this file has to be in etc/frontend folder.
Hope this helps !
Hi,
I know this thread is a little old, but do you have the complete working code. I have to do something similar and I am missing something following what you wrote.
Thanks!