HowTo: Create an Alternative Success Page for a Payment Method in Magento2

This week I had the task to build an alternative success page for customers who pay with a specific payment method. If the customers select Bank Transfer method they should be redirected to https://magento2.test/checkout/banktransfer/success. If any other payment method is selected the customer should be redirected to the default success page https://magento2.test/checkout/onepage/success/.

Looks simple right? Let's see how can we achieve this.

This post assumes that there is already a custom module created in app/code/Vendor/BanckTransfer. If you need to know how to create a custom module, please look at How to create a custom module for Magento 2.

What we need to do

  1. First, we need a controller to handle the request for https://magento2.test/checkout/BanckTransfer/success url.
  2. Next we will need a way to redirect customers when selecting the BanTransfer Payment method to the new success page.

The Controller

To create a controller, first declare the route.

<?xml version="1.0"?>
<!--//app/code/Vendor/BanTransfer/etc/frontend/routes.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route id="checkout">
            <module name="Vendor_BanTransfer"/>
        </route>
    </router>
</config>

Notice: Because we are adding an extra page to the checkout we use checkout for the route and we don't need to specify a frontName.

Next, we need to make sure our module extends Magento_Checkout. If we don't, our custom success page is not going to work. Also and because we are going to modify the behavior of Bank Transfer payment method, a method that comes with Magento, we need to load our custom module AFTER it.

<?xml version="1.0"?>
<!--//app/code/Vendor/BanTransfer/etc/module.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Vendor_BanTransfer" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Checkout"/>
            <module name="Magento_OfflinePayments"/>
        </sequence>
    </module>
</config>

With these two changes in place, we can now proceed to create the Controller.

<?php
/** app/code/Vendor/BanTransfer/Controller/BanTransfer/Success.php */
namespace Vendor\BanTransfer\Controller\BanTransfer;

use Magento\Checkout\Model\Session\SuccessValidator;
use Magento\Checkout\Model\Type\Onepage;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\Result\Redirect;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\View\Result\Page;
use Magento\Framework\View\Result\PageFactory;

class Success extends Action
{
    /**
     * @var SuccessValidator
     */
    private $successValidator;

    /**
     * @var Onepage
     */
    private $onepage;

    /**
     * @var PageFactory
     */
    private $resultPageFactory;

    /**
     * Success constructor.
     * @param SuccessValidator $successValidator
     * @param Onepage          $onepage
     * @param PageFactory      $resultPageFactory
     * @param Context          $context
     */
    public function __construct(
        SuccessValidator $successValidator,
        Onepage $onepage,
        PageFactory $resultPageFactory,
        Context $context
    ) {
        $this->successValidator = $successValidator;
        $this->onepage = $onepage;
        $this->resultPageFactory = $resultPageFactory;
        parent::__construct($context);
    }

    /**
     * @return ResponseInterface|Redirect|ResultInterface|Page
     */
    public function execute()
    {
        $checkout = $this->onepage->getCheckout();
        if (!$this->successValidator->isValid()) {
            return $this->resultRedirectFactory->create()->setPath('checkout/cart');
        }

        $checkout->clearQuote();
        $resultPage = $this->resultPageFactory->create();
        $this->_eventManager->dispatch(
            'checkout_onepage_controller_success_action',
            ['order_ids' => [$checkout->getLastOrderId()]]
        );
        return $resultPage;
    }
}

You can see this is pretty much a copy of the core Controller in vendor/magento/module-checkout/Controller/Onepage/Success.php.

Now we need to create a layout to specify the template file.

<?xml version="1.0"?>
<!-- // app/code/Vendor/BanTransfer/view/frontend/layout/checkout_banTransfer_success.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <title>BanTransfer Success Page</title>
    </head>
    <body>
        <referenceBlock name="page.main.title">
            <block class="Magento\Checkout\Block\Onepage\Success" name="checkout.success.print.button" template="Magento_Checkout::button.phtml"/>
            <action method="setPageTitle">
                <argument translate="true" name="title" xsi:type="string">Thank you for your purchase!</argument>
            </action>
        </referenceBlock>
        <referenceContainer name="content">
            <block class="Magento\Checkout\Block\Onepage\Success" name="checkout.success" template="Vendor_BanTransfer::checkout/success.phtml" cacheable="false">
                <container name="order.success.additional.info" label="Order Success Additional Info"/>
            </block>
            <block class="Magento\Checkout\Block\Registration" name="checkout.registration" template="Magento_Checkout::registration.phtml" cacheable="false"/>
        </referenceContainer>
    </body>
</page>

Again this is a copy of the file in vendor/magento/module-checkout/view/frontend/layout/checkout_onepage_success.xml. The only difference is the success.phtml where we specified our custom template.

Finally, we will create the template file that is going to be rendered when a customer visit the new url.

<?php /** app/code/Vendor/BanTransfer/view/frontend/templates/checkout/success.phtml */ ?>
<?php /** @var $block \Magento\Checkout\Block\Onepage\Success */ ?>
<div class="checkout-success">
    <?php if ($block->getOrderId()):?>
        <?php if ($block->getCanViewOrder()) :?>
            <p><?= __('Your order number is: %1.', sprintf('<a href="%s" class="order-number"><strong>%s</strong></a>', $block->escapeHtml($block->getViewOrderUrl()), $block->escapeHtml($block->getOrderId()))) ?></p>
        <?php  else :?>
            <p><?= __('Your order # is: <span>%1</span>.', $block->escapeHtml($block->getOrderId())) ?></p>
        <?php endif;?>
            <p><?= /* @escapeNotVerified */ __('We\'ll email you an order confirmation with details and tracking info.') ?></p>
    <?php endif;?>

    <?= $block->getAdditionalInfoHtml() ?>

    <div class="actions-toolbar">
        <div class="primary">
            <a class="action primary continue" href="<?= /* @escapeNotVerified */ $block->getContinueUrl() ?>"><span><?= /* @escapeNotVerified */ __('Continue Shopping') ?></span></a>
        </div>
    </div>
</div>

So far we have a controller that handles the request when a customer visit the url https://magento2.test/checkout/banTransfer/success but now we need a mechanism to redirect customers to the new url when placing an order is place using Bank Transfer Payment method.

The Redirect

<?xml version="1.0"?>
<!-- // app/code/Vendor/BanTransfer/view/frontend/layout/checkout_index_index.xml-->
<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="billing-step" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="payment" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="renders" xsi:type="array">
                                                            <item name="children" xsi:type="array">
                                                                <item name="offline-payments" xsi:type="array">
                                                                    <item name="component" xsi:type="string">Vendor_BanTransfer/js/view/payment/offline-payments</item>
                                                                    <item name="methods" xsi:type="array">
                                                                        <item name="banktransfer" 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>

Next we create the component file

// app/code/Vendor/BanTransfer/view/frontend/web/js/view/payment/offline-payments.js
define([
    'uiComponent',
    'Magento_Checkout/js/model/payment/renderer-list'
], function (Component, rendererList) {
    'use strict';

    rendererList.push(
        {
            type: 'checkmo',
            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/checkmo-method'
        },
        {
            type: 'banktransfer',
            component: 'Vendor_BanTransfer/js/view/payment/method-renderer/banktransfer-method'
        },
        {
            type: 'cashondelivery',
            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/cashondelivery-method'
        },
        {
            type: 'purchaseorder',
            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/purchaseorder-method'
        }
    );

    return Component.extend({});
});

Finally, we add the new banktransfer-method file.

// app/code/Vendor/Finance/view/frontend/web/js/view/payment/offline-payments.js
define([
    'uiComponent',
    'Magento_Checkout/js/model/payment/renderer-list'
], function (Component, rendererList) {
    'use strict';

    rendererList.push(
        {
            type: 'checkmo',
            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/checkmo-method'
        },
        {
            type: 'banktransfer',
            component: 'Vendor_Finance/js/view/payment/method-renderer/banktransfer-method'
        },
        {
            type: 'cashondelivery',
            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/cashondelivery-method'
        },
        {
            type: 'purchaseorder',
            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/purchaseorder-method'
        }
    );
    return Component.extend({});
});

Before test the result, make sure to flush the cache.

Conclusion

Comments

Next Post Previous Post