A very basic Magento 2 module with parameterized template

Last time, we experimented and learned how to create a simple module to display some text in Magento’s UI. In this article we use the same code and extends it to use a template page and a block in Magento 2.

Creating a new controller action

For the purpose of this article we will create a new action, called ‘hello’. We will add this action to the extension created in the previous post, A Very Basic Magento 2 Module.

/app/code/Clounce/DisplayHello/Controller/Index/Hello.php
 
<?php
/**
 * Copyright © 2015 Clounce. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Clounce\DisplayHello\Controller\Index;
 
/**
 * Display Hello on screen using a template
 */
class Hello extends \Magento\Framework\App\Action\Action
{
/**
     * @var \Magento\Framework\View\Result\PageFactory
     */
    protected $resultPageFactory;
 
    /**
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory
    ) {
        parent::__construct($context);
        $this->resultPageFactory = $resultPageFactory;
    }
 
    /**
     * Default hello page with layout
     *
     * @return void
     */
    public function execute()
    {
        /** @var \Magento\Framework\View\Result\Page $resultPage */
        $resultPage = $this->resultPageFactory->create();
        $resultPage->getLayout()->initMessages();
        return $resultPage;
    }
}

Why the class constructor has to be overridden? At the time of writing, the base class for action classes does not provide a way to access the layout object directly. In the early releases of Magento 2 the only way was to access the deprecated variable _view. Although this is still the main way of accessing the layout object, Magento started reviewing the access to this variable. The way forward is to use the ResultPageFactory object. As the ResultPageFactory is still not linked to the Action base class, the constructor had to be overridden to expose the link.

At this stage, if the cache is cleared and we type the URL /clounce_hello/index/hello in our web browser, a themed blank page will be loaded.

Creating the template

When accessing the URL a blank page is obtained. Interesting right? Let’s put some content in the page. To do this, we need to create a PHTML file with the content to be displayed on the page. In Magento 2, the PHTML files are placed inside the module under the view folder. This is different from Magento 1.X where the PHTML resided under app/design/frontend/<package>/<theme> structure.

/app/code/Clounce/DisplayHello/view/frontend/templates/hello.phtml
 
<h1>Hello from PHTML</h1>

Telling Magento to load the template when the controller is called

Now that the template file has been added, we need to instruct Magento to use the template when the hello action is called. This is done by defining a layout XML inside the module, as shown below:

/app/code/Clounce/DisplayHello/view/frontend/layout/Clounce_hello_index_hello.xml
 
<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Clounce. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <block class="Magento\Framework\View\Element\Template" name="Clounce_hello" template="Clounce_DisplayHello::hello.phtml" />
        </referenceContainer>
    </body>
</page>

Notes:

  • The XML file name must match the controller action path. This means that each controller action using layout XMLs need to have its own file defined. Note that this is different from Magento 1.X where a single layout XML file was shared between all controller actions in one module.
  • The block class “Magento\Framework\View\Element\Template” is the basic class for defining template blocks.
  • The template attribute must start with the module name before the path to the PHTML file in order for the template file to be loaded.

Passing values to template

Passing parameters to templates is done by setting data for the containing block. This is done through the magic getters and setters available in Magento. In the code snippet below we have updated the execute() method to retrieve the parameter ‘name’ value and pass it to the template block.

/app/code/Clounce/DisplayHello/Controller/Index/Hello.php
 
<?php
/**
 * Copyright © 2015 Clounce. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Clounce\DisplayHello\Controller\Index;
 
/**
 * Display Hello on screen using a template
 */
class Hello extends \Magento\Framework\App\Action\Action
{
/**
     * @var \Magento\Framework\View\Result\PageFactory
     */
    protected $resultPageFactory;
 
    /**
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory
    ) {
        parent::__construct($context);
        $this->resultPageFactory = $resultPageFactory;
    }
 
    /**
     * Default hello page with layout
     *
     * @return void
     */
    public function execute()
    {
        $name = $this->getRequest()->getParam('name');
 
        /** @var \Magento\Framework\View\Result\Page $resultPage */
        $resultPage = $this->resultPageFactory->create();
        $resultPage->getLayout()->initMessages();
        $resultPage->getLayout()->getBlock('Clounce_hello')->setName($name);
        return $resultPage;
    }
}

In the template accessing the object member is done by calling the magic getter, in this case getName().

/app/code/Clounce/DisplayHello/view/frontend/templates/hello.phtml
 
<h1>Hello <?php echo $this->getName(); ?> from PHTML</h1>

In summary

Passing parameters to template has not changed from Magento 1, except for the way the layout XML is created. However, although in Magento 1 considered it was considered a good practice to process parameter values outside of the phtml template, in Magento 2 this is defined in the Frontend coding standards.

Be Sociable, Share!
  • Sachin S

    Thanks, was helpful, could you please post on how to override core phtml templates in magento2.. im trying to override magento default search and my unable to call my custom layout file… i have posted in magento forum, need assistance http://magento.stackexchange.com/questions/122625/magento2-catalogsearch-result-not-displaying

    • Hi,

      For another article, I have overridden the customer edit form for the frontend. You can refer to the code on github, https://github.com/kdemanuele/Magento2-Adding-Customer-Attribute. Check the view/frontend/layout part of how to override the phtml template.

      I haven’t looked at the search of Magento as yet, but if the solution in the github link doesn’t work for you let me know.

      • Sachin S

        Hi Karlston, thanks for the reply.. I just need your suggestion in one of my custom module where im trying to override the magento default search engine, i am struck in one of the stage where after i give a keyword in the search box, the page shows blank. Please help on the same. I have posted the code in my github : https://github.com/Sachin-Suresh/Magento2x-Tagalys

  • It looks like the signature of __construct has changed since your post and Alan Storm’s post (or I am doing something wrong here).

    MagentoFrameworkAppActionAction::__construct receives only one parameter…

    public function __construct(Context $context)

    Am I missing something?