Magento, PHP, Java, C#

Magento2 module – simple example

In this post will cover the topic of how to create a simple Magento2 module. Aim of this article is to create a simple module with minimal configuration of controller, block and template. Therefore we have to do go through the following points:

  • Create the modules file structure
  • Configure the module
  • Create register.php
  • Define a frontname
  • Setup a controller
  • Create a block
  • Create a template

The aim of the module is to request a certain URL that calls a controller action and renders a template file with it’s own block class.

You can download the module on Github, or follow the instructions in this post to create your own.

Create module folder structure

In Magento2 all custom modules are located in app/code/VendorNamespace. VendorNamespace is the name of your company, your individual or any name you choose for the first part of your modules name, in my case i chose “Bpoiss”. In your VendorNamespace directory you can create all your modules, in my case it is “MyModule”. The full module name now is “Bpoiss_MyModule”.

The folder structure for a minimal module would contain the folder “etc” and the file “registration.php”. In MyModule we want to create a custom block, a controller and a template. All controllers of our module live in the “Controller” directory, custom block classes in “Block”, and template files in “view”. The “etc” folder contains xml files that configure our module.

At first we want to create the folder structure and the files we need for our Magento2 module, listed in the screenshot below.

Magento2 module structure

Configure the module

To configure our Magento2 module we need to do two things:

  • Configure module in “etc/module.xml”
  • Create a registration.php file to enable our module

Configuration in module.xml

This is what our module.xml file should look like:

<!-- etc/module.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Bpoiss_MyModule" setup_version="1.0.0"></module>

The only settings defined in this configuration file are the module name and the setup_version. The module name is set with the name attribute of the module xml element. You can adjust it to “VendorNamespace_ModuleName” and it should match the folder structure of your module. The setup version tells Magento which version of your module this is. If you update the version of the module, Magento will look for update scripts and run them. This will be covered in another article.

Create registration.php

Every Magento2 module needs a registration.php file in it’s root directory. It does nothing more than tell Magento to enable the module.


This file will contain the same code for every Magento2 module. The only thing that changes is the module name, in our case Bpoiss_MyModule.

After creating this file, you need to clear all caches and run the following command in your Magento2 root directory to enable your module:

php bin/magento module:enable Bpoiss_MyModule

Configure a route for a Magento2 module

The file “etc/frontend/routes.xml” will configure our URL path, and tells Magento which controller to use when the specific URL is requested. The subfolder “frontend” determines that the route is a frontend route. If you want to configure routes for the backend, you have to create a routes.xml file in “etc/adminhtml/routes.xml”.

<!-- 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="mymodule" frontName="mymodule">
            <module name="Bpoiss_MyModule" />

The id attribute tells Magento if this is a frontend or a backend router. The value for frontend is “standard” and for backend it’s “admin”. The route id is a unique name for this router. The most interresting part is the frontName. The frontName specifies the path of your URL after your host path, e.g. www.magento.example.com/mymodule.  The module element only requires a name attribute that determines in which module the controller is that we want to use, so in our case it is the current module.

Setting up a Controller

// Controller/Index/Index.php

namespace Bpoiss\MyModule\Controller\Index;
use Magento\Framework\App\Action\Context;
use Magento\Framework\View\Result\PageFactory;

class Index extends \Magento\Framework\App\Action\Action
    protected $pageFactory;

    public function __construct(Context $context, PageFactory $pageFactory)
        $this->pageFactory = $pageFactory;
        return parent::__construct($context);

    public function execute()
        return $this->pageFactory->create();

This is a simple controller implementation that just implements the execute method that returns a “page” object. Every controller in Magento 2.0 has only one entry point, this is the execute method. In the constructor we inject a PageFactory object via dependency injection. For a detailed explanation on how constructor injection works, see Magento2 DI Documentation. The create method of our PageFactory object will create a Page object. It automatically adds the block that we define and configure in the next steps.

Defining a Block

Blocks are located in the modules Block subdirectory. Since our Block does not need any logic, we can create an empty Block class.

// Block/CustomBlock.php

namespace Bpoiss\MyModule\Block;
use Magento\Framework\View\Element\Template;

class CustomBlock extends Template
    protected function _prepareLayout() 

If you want to add any logic for presenting data in your view, your Block is the right place to set data or implement methods for retrieving data in your template file.

Create a layout handle

<!-- view/frontend/layout/mymodule_index_index.phtml -->
<?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">
    <referenceBlock name="content">
        <block template="content.phtml" class="Bpoiss\MyModule\Block\CustomBlock" name="bpoiss_my_module_main"/>

The layout handle configures that our Page object that is returned from our controller should contain our CustomBlock, and it will define a template file that the block will use. In this case it is content.phtml. The name of this xml file is important. Magento will only use this file, if the current layout handle matches the file name. The layout handle always consists of three parts, our frontName, and the name of the controller class. In our case the controllers full name is Bpoiss\MyModule\Controller\Index\Index. The layout handles second and third part, are the last to parts of our controllers name, so it is Index and Index. The layout handle is always in lower case and uses an underscore to divide the three parts. So our layout handle is mymodule_index_index and matches our filename.

Create a template file

The last thing we have to do is to create a template file.

<!– view/frontend/template/content.phtml –>
<h1>This is content.phtml</h1>

We will just display a simple message for now.

Run the module

To view the result, you need to clear all caches again, and request the configured URL in your Browser, e.g. www.magento.example.com/mymodule/index/index.

1 Comment

  1. Thanks for sharing this post, when i was stuck in creating controller, your guide helped me a lot, but for structure of module i followed this post, https://www.cloudways.com/blog/create-module-in-magento-2/

Leave a Reply

Your email address will not be published. Required fields are marked *

© 2019 bpoiss

Theme by Anders NorénUp ↑