{"id":397,"date":"2019-04-30T10:23:30","date_gmt":"2019-04-30T10:23:30","guid":{"rendered":"https:\/\/meetanshi.com\/blog\/2019\/04\/30\/magento-2-module-development\/"},"modified":"2025-09-09T09:04:59","modified_gmt":"2025-09-09T03:34:59","slug":"magento-2-module-development","status":"publish","type":"post","link":"https:\/\/meetanshi.com\/blog\/magento-2-module-development\/","title":{"rendered":"A Complete Tutorial on Magento 2 Module Development"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">&#8220;Hello World&#8221; is where a new programmer is born!  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Starting with the ABCD of Magento 2 development, hello world module is mandatory!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So, here I am, with a post for newbies to create a simple module in Magento 2, for hello world. <i><strong>Magento 2 module development<\/strong><\/i> is a stepwise process and needs to be done with some prerequisites conditions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Follow the below tutorial and create your own basic module in Magento 2!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Things to take care of before you create a custom module in Magento 2:<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Switch to developer mode: Switch to developer mode in order to see every error Magento is throwing at you. Use the below command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>php bin\/magento deploy:mode:set developer<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Learn more about the <a href=\"https:\/\/meetanshi.com\/blog\/magento-2-modes\/\" target=\"_blank\" rel=\"noreferrer noopener\">Magento 2 Modes<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Method for Magento 2 Module Development:<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Module Setup<\/li>\n\n\n\n<li>Creating a Controller<\/li>\n\n\n\n<li>Creating a Block<\/li>\n\n\n\n<li>Creating a Layout and Template Files<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Getting to each step,<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Method 1: Module Setup<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step 1: <\/strong>Create the below folders<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>app\/code\/Meetanshi<\/em><\/li>\n\n\n\n<li><em>app\/code\/Meetanshi\/Helloworld<\/em> where Meetanshi folder is the module\u2019s&nbsp;<strong>namespace<\/strong>&nbsp;and our module\u2019s&nbsp;<strong>name<\/strong>&nbsp;is Helloworld! Note: You\u2019d be required to create the \u201ccode\u201d folder manually if it is not in the \u201capp\u201d directory.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step 2:<\/strong> Create a&nbsp;<strong>module.xml<\/strong>&nbsp;file in the&nbsp;<strong><em>app\/code\/Meetanshi\/Helloworld\/etc&nbsp;<\/em><\/strong>&nbsp;folder with the below code:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;?xml version=\"1.0\"?>\n\n&lt;config xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"urn:magento:framework:Module\/etc\/module.xsd\">\n    &lt;module name=\"Meetanshi_Helloworld\" setup_version=\"1.0.0\">\n    &lt;\/module>\n&lt;\/config><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step 3:<\/strong> Create a <strong>registration.php<\/strong> file in the <strong><em>app\/code\/Meetanshi\/Helloworld <\/em><\/strong>folder to register the module. Implement the below code:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;?php\n\n\\Magento\\Framework\\Component\\ComponentRegistrar::register(\n    \\Magento\\Framework\\Component\\ComponentRegistrar::MODULE,\n    'Meetanshi_Helloworld',\n    __DIR__\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step 4:<\/strong> Open the terminal and go to the Magento 2 root. Run the below command<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">php bin\/magento setup:upgrade<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Note: <\/strong>Make sure if your module is installed. Go to <strong>Admin &gt; Stores &gt; Configuration &gt; Advanced &gt; Advanced<\/strong>. Check if the module is present in the list. Else, open <strong>app\/etc\/config.php<\/strong> and check the array for the &#8220;Meetanshi_Helloworld&#8221; key whose value must be 1.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Method 2: Creating a Controller<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step 1:<\/strong> Define the router with <strong>routes.xml<\/strong> file in the <em><strong>app\/code\/Meetanshi\/Helloworld\/etc\/frontend<\/strong> <\/em>folder with the below code:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;?xml version=\"1.0\"?>\n\n&lt;config xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"urn:magento:framework:App\/etc\/routes.xsd\">\n    &lt;router id=\"standard\">\n        &lt;route id=\"helloworld\" frontName=\"helloworld\">\n            &lt;module name=\"Meetanshi_Helloworld\" \/>\n        &lt;\/route>\n    &lt;\/router>\n&lt;\/config><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We define the frontend router and router with an id \u201chelloworld\u201d. The Magento 2 URL syntax is <em>&lt;frontName&gt;\/&lt;controler_folder_name&gt;\/&lt;controller_class_name&gt;<\/em> and according to this, our URL will be&nbsp;<em>helloworld\/index\/index.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step 2:<\/strong> Create the <strong>Index.php<\/strong> file in the <strong><em>app\/code\/Meetanshi\/Helloworld\/Controller\/Index<\/em><\/strong>&nbsp;folder with the below code:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;?php\n\nnamespace Meetanshi\\Helloworld\\Controller\\Index;\n\nuse Magento\\Framework\\App\\Action\\Context;\nuse Magento\\Framework\\App\\Action\\Action;\nuse Magento\\Framework\\View\\Result\\PageFactory;\n\nclass Index extends Action\n{\n    protected $_resultPageFactory;\n\n    public function __construct(\n        Context $context,\n        PageFactory $resultPageFactory\n    )\n    {\n        $this->_resultPageFactory = $resultPageFactory;\n        parent::__construct($context);\n    }\n\n    public function execute()\n    {\n        $resultPage = $this->_resultPageFactory->create();\n        return $resultPage;\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In Magento 2 every action has its own class which implements the execute() method.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Method 3: Creating a block<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create a simple block class with the getHelloWorldTxt() method which returns the \u201cHello world\u201d string.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step 1: <\/strong>Create a <strong>Helloworld.php<\/strong>&nbsp;file in the <strong><em>app\/code\/Meetanshi\/Helloworld\/Block<\/em><\/strong> folder with the below code:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;?php\nnamespace Meetanshi\\Helloworld\\Block;\n\nuse Magento\\Framework\\View\\Element\\Template;\n\nclass Helloworld extends Template\n{\n    public function getHelloWorldText()\n    {\n        return 'Hello world!';\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Method 4: Creating a layout and template files<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Layout files and templates are placed in the view folder inside the module. We can have three subfolders inside the view folder: adminhtml, base, and frontend.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step 1:<\/strong> Use the below code to create a <strong>helloworld_index_index.xml<\/strong>&nbsp;file in the <strong><em>app\/code\/Meetanshi\/Helloworld\/view\/frontend\/layout <\/em><\/strong>folder:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;page xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"..\/..\/..\/..\/..\/..\/..\/lib\/internal\/Magento\/Framework\/View\/Layout\/etc\/page_configuration.xsd\" layout=\"1column\"> \n&lt;body> \n&lt;referenceContainer name=\"content\"> \n&lt;block class=\"Meetanshi\\Helloworld\\Block\\Helloworld\" name=\"helloworld\" template=\"helloworld.phtml\" \/> \n&lt;\/referenceContainer> \n&lt;\/body> \n&lt;\/page><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Every page has a layout hand. For our controller action, the layout handle is <strong>helloworld_index_index<\/strong>. You may create a layout configuration file for every layout handle. In our layout file, we have added a block to the content container and set the template of our block to helloworld.phtml, which we create in the next step.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step 2:<\/strong> Create a <strong>helloworld.phtml<\/strong>&nbsp;file in the <strong><em>app\/code\/Meetanshi\/Helloworld\/view\/frontend\/templates<\/em><\/strong>&nbsp;folder<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;h1>&lt;?php echo $this->getHelloWorldText(); ?>&lt;\/h1>\n&lt;!--  Display Text from block file --><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">$this variable refers to our block class. Our method getHelloWorldTxt() returns the string \u201cHello world!\u201d<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Open the <strong><em>\/helloworld\/index\/index<\/em><\/strong>&nbsp;URL in the browser to check the below output.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/meetanshi.com\/blog\/wp-content\/uploads\/2019\/04\/Hello-World-Module.png\"><img decoding=\"async\" src=\"https:\/\/meetanshi.com\/blog\/wp-content\/uploads\/2019\/04\/Hello-World-Module.png\" alt=\"Hello World Module by Meetanshi\" class=\"wp-image-5016\"\/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s it with the custom Magento 2 module development! Also <a href=\"https:\/\/meetanshi.com\/blog\/validate-condition-rules-in-a-custom-module-in-magento-2\/\">validate condition rules in custom module for Magento 2<\/a> using ruleFactory enhances e-commerce customization and efficiency, allowing dynamic promotions and improving the user experience.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Learn to <a title=\"Learn now\" href=\"https:\/\/meetanshi.com\/blog\/check-magento-2-coding-standards\/\" target=\"_blank\" rel=\"noopener\">check Magento 2 coding standards using code sniffer<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Hopefully, the post helps you go through the first Magento 2 module development stage!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Thank you.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;Hello World&#8221; is where a new programmer is born! Starting with the ABCD of Magento 2 development, hello world module is mandatory! So, here I&#8230;<\/p>\n","protected":false},"author":5,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[34],"tags":[],"class_list":["post-397","post","type-post","status-publish","format-standard","hentry","category-magento"],"acf":[],"_links":{"self":[{"href":"https:\/\/meetanshi.com\/blog\/wp-json\/wp\/v2\/posts\/397","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/meetanshi.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/meetanshi.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/meetanshi.com\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/meetanshi.com\/blog\/wp-json\/wp\/v2\/comments?post=397"}],"version-history":[{"count":4,"href":"https:\/\/meetanshi.com\/blog\/wp-json\/wp\/v2\/posts\/397\/revisions"}],"predecessor-version":[{"id":21544,"href":"https:\/\/meetanshi.com\/blog\/wp-json\/wp\/v2\/posts\/397\/revisions\/21544"}],"wp:attachment":[{"href":"https:\/\/meetanshi.com\/blog\/wp-json\/wp\/v2\/media?parent=397"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/meetanshi.com\/blog\/wp-json\/wp\/v2\/categories?post=397"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/meetanshi.com\/blog\/wp-json\/wp\/v2\/tags?post=397"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}