{"id":26772,"date":"2020-12-21T16:40:29","date_gmt":"2020-12-21T14:40:29","guid":{"rendered":"https:\/\/belvg.com\/blog\/?p=26772"},"modified":"2026-02-13T19:18:13","modified_gmt":"2026-02-13T17:18:13","slug":"modules-in-magento2","status":"publish","type":"post","link":"https:\/\/belvg.com\/blog\/modules-in-magento2.html","title":{"rendered":"Modules in Magento 2"},"content":{"rendered":"\n<p>In this article, we will consider the ways to enhance your product with the help of new Magento 2 modules (extensions), specifically, by adding the files to the&nbsp;directory via FTP or with the help of the configuration setting for Composer, as well as their custom structure, admin part, and debugging process.<\/p>\n<p><!--more--><\/p>\n<p><a href=\"#step_1\">How to install modules in Magento 2<br>\n<\/a><a href=\"#step_2\">Dependency injection<br>\n<\/a><a href=\"#step_3\">Custom structure<br>\n<\/a><a href=\"#step_4\">The admin part<br>\n<\/a><a href=\"#step_5\">Debugging process<\/a><\/p>\n<p>Magento 2 extensions are used for customization and extending existing <a href=\"https:\/\/belvg.com\/magento-development\" target=\"_blank\" rel=\"noopener\">Magento<\/a> functionality or adding new features.<\/p>\n<p>There is a good <a href=\"https:\/\/developer.adobe.com\/commerce\/php\/architecture\/modules\/overview\/\" target=\"_blank\" rel=\"noopener\">article<\/a>&nbsp;in Adobe devdocs with detailed information on the topic.<\/p>\n<h2 id=\"step_1\">How to install modules in Magento 2<\/h2>\n<p>There are two options how you can do it since the release of the 2.4.0 version:<\/p>\n<ul>\n<li>The first one is to add the Magento 2 extension files to app\/code\/&lt;Vendor&gt;\/&lt;Module&gt; directory.<\/li>\n<li>The second one is to install it via composer.<\/li>\n<\/ul>\n<p>There was a third one that was deprecated in Magento 2.3.6 and removed in Magento 2.4.0. It was a Setup Wizard feature.<\/p>\n<p>To begin the extension development in Magento 2, use&nbsp;Modules Manager. You can find more detailed information <a href=\"https:\/\/devdocs.magento.com\/guides\/v2.3\/comp-mgr\/module-man\/compman-start.html\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>You can&nbsp;find information on main composer&rsquo;s <strong><a href=\"https:\/\/experienceleague.adobe.com\/docs\/commerce-operations\/upgrade-guide\/developer\/manage-modules.html\" target=\"_blank\" rel=\"noopener\">commands<\/a><\/strong>, and composer <strong>config<\/strong> <a href=\"https:\/\/developer.adobe.com\/commerce\/php\/development\/build\/composer-integration\/\" target=\"_blank\" rel=\"noopener\">file<\/a>.<\/p>\n<h3>&nbsp;Option #1&nbsp;How to install modules in Magento 2<\/h3>\n<ol>\n<li>Copy module&rsquo;s files to app\/code\/&lt;Vendor&gt;\/&lt;Module&gt; directory via FTP.<\/li>\n<\/ol>\n<div class=\"module_in_content_container\"><a href=\"https:\/\/belvg.com\/contact\" class=\"link_to_module\" target=\"_blank\" rel=\"noopener\"><\/a><div class=\"module_content\"><div class=\"module_content_part\"><h3 class=\"title\">Modules in Magento 2<\/h3><p class=\"module_content_text\">Extend functionality with Magento 2 modules<\/p><a href=\"https:\/\/belvg.com\/contact\" class=\"link_2_to_module\" target=\"_blank\" style=\"display:inline-block\" rel=\"noopener\"><span class=\"read-more\">Contact us<\/span><\/a><\/div><\/div><\/div>\n<h3>Option#2 How to install modules in Magento 2<\/h3>\n<ol>\n<li style=\"text-align: left\">There is a&nbsp;<strong>configuration setting<\/strong> for <strong>Composer<\/strong> which indicates the location of the extension&rsquo;s files. They can be located remotely or locally.<\/li>\n<\/ol>\n<p>To add the configuration for composer, the following command is used:<\/p>\n<p><code>composer config repositories.&lt;module_name&gt; path \/path\/to\/magento\/module (there could be any path on your server which is convenient for you)<\/code><\/p>\n<p>If a repository is located remotely the command could be:<\/p>\n<p><code>composer config repositories.&lt;module_name&gt; git https:\/\/remote-repository-url.com<\/code><\/p>\n<ol start=\"2\">\n<li>To <strong>run composer<\/strong> &lt;vendor&gt;\/&lt;name&gt;:&lt;version&gt; is required<\/li>\n<\/ol>\n<p>If you do it for the first time Magento will ask you to enter Access Keys. You could get them in your account on https:\/\/magento.com\/.<\/p>\n<p>You can find an instruction on how to do it <a href=\"https:\/\/experienceleague.adobe.com\/docs\/commerce-operations\/installation-guide\/prerequisites\/authentication-keys.html\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>After you have placed the required extension files in Magento via Option 1 or Option 2, run the following commands to finish the installation:<\/p>\n<p>If the extension is being installed on the site in a <strong>production mode<\/strong>:<\/p>\n<pre class=\"lang:default decode:true\">bin\/magento maintenance:enable\r\n\r\nphp bin\/magento module:enable &lt;Vendor&gt;_&lt;Module&gt;\r\n\r\nphp bin\/magento setup:upgrade\r\n\r\nbin\/magento setup:di:compile\r\n\r\nbin\/magento setup:static-content:deploy\r\n\r\nbin\/magento maintenance:disable\r\n\r\n<\/pre>\n<p>If the extension is being installed on a site in <strong>developer mode<\/strong>:<\/p>\n<pre class=\"lang:default decode:true \">php bin\/magento module:enable &lt;Vendor&gt;_&lt;Module&gt;\r\n\r\nphp bin\/magento setup:upgrade<\/pre>\n<p>Below you will find several articles with detailed information about the commands used for installing extensions and the description of different options that could be selected for more specific purposes.<\/p>\n<p>You can find the instruction on how to <strong>enable or disable the maintenance mode <a href=\"https:\/\/devdocs.magento.com\/guides\/v2.4\/install-gde\/install\/cli\/install-cli-subcommands-maint.html\" target=\"_blank\" rel=\"noopener\">here<\/a><\/strong>.<\/p>\n<p>In this <a href=\"https:\/\/experienceleague.adobe.com\/docs\/commerce-operations\/configuration-guide\/cli\/code-compiler.html\" target=\"_blank\" rel=\"noopener\">article<\/a>, you can read more about <strong>code compilation<\/strong>.<\/p>\n<p>The topic of <strong>static files deployment<\/strong> is described <a href=\"https:\/\/experienceleague.adobe.com\/docs\/commerce-operations\/configuration-guide\/cli\/static-view\/static-view-file-deployment.html\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>You can study how to<strong> enable or disable modules<\/strong> in more detail <a href=\"https:\/\/experienceleague.adobe.com\/docs\/commerce-operations\/installation-guide\/tutorials\/manage-modules.html\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>More information about <strong>production\/developer\/default Magento modes<\/strong> is provided <a href=\"https:\/\/experienceleague.adobe.com\/docs\/commerce-operations\/configuration-guide\/setup\/application-modes.html\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<h2 id=\"step_2\"><strong>Dependency Injection<\/strong><\/h2>\n<p>Dependency Injection is an important concept of declaring dependencies of classes. You will find information on <strong>DI Concept <\/strong><a href=\"https:\/\/developer.adobe.com\/commerce\/php\/development\/components\/dependency-injection\/\" target=\"_blank\" rel=\"noopener\">here<\/a>, in <a href=\"https:\/\/alanastorm.com\/category\/magento-2\/#magento-2-object-system\" target=\"_blank\" rel=\"noopener\">this article<\/a>&nbsp;and about&nbsp;<strong>DI configuration in Magento 2 <\/strong><a href=\"https:\/\/developer.adobe.com\/commerce\/php\/development\/build\/dependency-injection-file\/\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>Example:<\/p>\n<p>Path is vendor\/magento\/module-store\/etc\/di.xml<\/p>\n<pre class=\"lang:default decode:true\">&lt;config xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"urn:magento:framework:ObjectManager\/etc\/config.xsd\"&gt;\r\n    &lt;preference for=\"Magento\\Store\\Api\\StoreRepositoryInterface\" type=\"Magento\\Store\\Model\\StoreRepository\"\/&gt;\r\n    ...\r\n&lt;\/config&gt;\r\n<\/pre>\n<p>Path is vendor\/magento\/module-store\/Model\/ScopeTreeProvider.php<\/p>\n<pre class=\"lang:default decode:true\">&lt;?php\r\n...\r\n\r\nnamespace Magento\\Store\\Model;\r\n\r\n...\r\nuse Magento\\Store\\Api\\StoreRepositoryInterface;\r\n...\r\n\r\n\/**\r\n * Class for building a scopes tree.\r\n *\/\r\nclass ScopeTreeProvider implements ScopeTreeProviderInterface\r\n{\r\n    ...\r\n\r\n    \/**\r\n     * @var StoreRepositoryInterface\r\n     *\/\r\n    private $storeRepository;\r\n\r\n    \/**\r\n     * @param WebsiteRepositoryInterface $websiteRepository\r\n     * @param GroupRepositoryInterface $groupRepository\r\n     * @param StoreRepositoryInterface $storeRepository\r\n     *\/\r\n    public function __construct(\r\n        ...\r\n        StoreRepositoryInterface $storeRepository\r\n    ) {\r\n        ...\r\n        $this-&gt;storeRepository = $storeRepository;\r\n    }\r\n<\/pre>\n<p>Class Magento\\Store\\Model\\StoreRepository is a realization of Magento\\Store\\Api\\StoreRepositoryInterface declared in di.xml<\/p>\n<p>So you could include an interface in your class and use the desired realization of it.<\/p>\n<h2 id=\"step_3\"><strong>&#1057;ustom structure<\/strong><\/h2>\n<p>There is an example of a <strong>custom structure<\/strong>. The extension implements an ability to set up a date of visiting the showroom. The customer should enter a name, an email, desired date and showroom from a list.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/belvg.com\/wp-content\/uploads\/2019\/06\/pixel.png\" data-src=\"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2020\/12\/modules-in-magento2-1-1.jpg\" alt=\"modules-in-magento2-1\" width=\"1340\" height=\"686\" class=\"lazy aligncenter size-full wp-image-26810\" title=\"Modules in Magento 2\"><\/p>\n<p>To create the <strong>form<\/strong> the next structure is required (front end part):<\/p>\n<ol>\n<li><strong>Declare a module<\/strong><\/li>\n<\/ol>\n<p>app\/code\/BelVG\/Showroom\/composer.json<\/p>\n<pre class=\"lang:default decode:true \">{\r\n    \"name\": \"belvg\/showroom\",\r\n    \"version\": \"1.0.0\",\r\n    \"require\": {\r\n        \"..\/..\/..\/..\/vendor\/magento\/framework\": \"&gt;=100.0.0\",\r\n        \"php\": \"~5.5.0|~5.6.0|&gt;=7.0.0\"\r\n    },\r\n    \"type\": \"magento2-module\",\r\n    \"extra\": [],\r\n    \"autoload\": {\r\n        \"files\": [\r\n          \"registration.php\"\r\n        ],\r\n        \"psr-4\": {\r\n            \"BelVG\\\\Showroom\\\\\": \"\"\r\n        }\r\n    },\r\n    \"license\": [\r\n        \"\"\r\n    ],\r\n    \"description\": \"\"\r\n}<\/pre>\n<p>app\/code\/BelVG\/Showroom\/registration.php<\/p>\n<pre class=\"lang:default decode:true \">&lt;?php\r\n\r\n\\Magento\\Framework\\Component\\ComponentRegistrar::register(\r\n    \\Magento\\Framework\\Component\\ComponentRegistrar::MODULE,\r\n    'BelVG_Showroom',\r\n    __DIR__\r\n);\r\n<\/pre>\n<p>app\/code\/BelVG\/Showroom\/etc\/module.xml<\/p>\n<pre class=\"lang:default decode:true\">&lt;?xml version=\"1.0\" ?&gt;\r\n&lt;config xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"urn:magento:framework:Module\/etc\/module.xsd\"&gt;\r\n    &lt;module name=\"BelVG_Showroom\" setup_version=\"1.0.0\"\/&gt;\r\n&lt;\/config&gt;\r\n<\/pre>\n<ol start=\"2\">\n<li><strong>Create controllers<\/strong><\/li>\n<\/ol>\n<p>Here is a <strong>controller<\/strong> for displaying a form on the site. It should be extended from Magento\\Framework\\App\\Action\\Action class.<\/p>\n<p>app\/code\/BelVG\/Showroom\/Controller\/Booking\/Index.php<\/p>\n<pre class=\"lang:default decode:true\">&lt;?php\r\nnamespace BelVG\\Showroom\\Controller\\Booking;\r\n\r\nuse BelVG\\Showroom\\Helper\\Data;\r\nuse Magento\\Framework\\App\\Action\\Context;\r\nuse Magento\\Framework\\Controller\\ResultFactory;\r\nuse Magento\\Framework\\App\\Action\\Action;\r\nuse Magento\\Framework\\View\\Result\\PageFactory;\r\n\r\nclass Index extends Action\r\n{\r\n    \/**\r\n     * @var Data\r\n     *\/\r\n    protected $helperData;\r\n\r\n    \/**\r\n     * @var PageFactory\r\n     *\/\r\n    protected $pageFactory;\r\n\r\n    public function __construct(\r\n        Context $context,\r\n        Data $helperData,\r\n        PageFactory $pageFactory\r\n    )\r\n    {\r\n        parent::__construct($context);\r\n        $this-&gt;helperData = $helperData;\r\n        $this-&gt;pageFactory = $pageFactory;\r\n    }\r\n\r\n    \/**\r\n     * @return \\Magento\\Framework\\App\\ResponseInterface|\\Magento\\Framework\\Controller\\ResultInterface|\\Magento\\Framework\\View\\Result\\Layout|\\Magento\\Framework\\View\\Result\\Page\r\n     *\/\r\n    public function execute()\r\n    {\r\n        if (!$this-&gt;helperData-&gt;isModuleOutputEnabled()) {\r\n            $resultRedirect = $this-&gt;resultFactory-&gt;create(ResultFactory::TYPE_REDIRECT);\r\n            $resultRedirect-&gt;setPath('\/');\r\n            return $resultRedirect;\r\n        }\r\n        return $this-&gt;pageFactory-&gt;create();\r\n    }\r\n}\r\n<\/pre>\n<p>Here is a <strong>controller<\/strong> for saving information from <strong>postData<\/strong> and notifying an administrator about booking:<\/p>\n<p>app\/code\/BelVG\/Showroom\/Controller\/Booking\/Save.php<\/p>\n<pre class=\"lang:default decode:true\">&lt;?php\r\nnamespace BelVG\\Showroom\\Controller\\Booking;\r\n\r\nuse BelVG\\Showroom\\Model\\BookingFactory;\r\nuse Magento\\Framework\\App\\Action\\Action;\r\nuse Magento\\Framework\\App\\Action\\Context;\r\nuse Magento\\Framework\\Controller\\ResultFactory;\r\nuse Magento\\Framework\\Exception\\LocalizedException;\r\nuse Magento\\Framework\\DataObject;\r\nuse Magento\\Framework\\Mail\\Template\\TransportBuilder;\r\nuse Magento\\Framework\\Escaper;\r\nuse BelVG\\Showroom\\Helper\\Data;\r\n\r\nclass Save extends Action\r\n{\r\n    \/**\r\n     * @var BookingFactory\r\n     *\/\r\n    protected $bookingFactory;\r\n\r\n    \/**\r\n     * @var TransportBuilder\r\n     *\/\r\n    protected $transportBuilder;\r\n\r\n    \/**\r\n     * @var Escaper\r\n     *\/\r\n    protected $escaper;\r\n\r\n    \/**\r\n     * @var Data\r\n     *\/\r\n    protected $helperData;\r\n\r\n    \/**\r\n     * Save constructor.\r\n     * @param Data $helperData\r\n     * @param BookingFactory $bookingFactory\r\n     * @param TransportBuilder $transportBuilder\r\n     * @param Escaper $escaper\r\n     * @param Context $context\r\n     *\/\r\n    public function __construct(\r\n        Data $helperData,\r\n        BookingFactory $bookingFactory,\r\n        TransportBuilder $transportBuilder,\r\n        Escaper $escaper,\r\n        Context $context\r\n    )\r\n    {\r\n        parent::__construct($context);\r\n        $this-&gt;bookingFactory = $bookingFactory;\r\n        $this-&gt;transportBuilder = $transportBuilder;\r\n        $this-&gt;escaper = $escaper;\r\n        $this-&gt;helperData = $helperData;\r\n    }\r\n\r\n    \/**\r\n     * @return \\Magento\\Framework\\App\\ResponseInterface|\\Magento\\Framework\\Controller\\ResultInterface|\\Magento\\Framework\\View\\Result\\Layout\r\n     * @throws \\Exception\r\n     *\/\r\n    public function execute()\r\n    {\r\n        $data = (array) $this-&gt;getRequest()-&gt;getPost();\r\n        if (!empty($data)) {\r\n            try {\r\n                $booking = $this-&gt;bookingFactory-&gt;create()-&gt;setData($data);\r\n                $booking-&gt;save();\r\n                $this-&gt;sendEmailToAdmin($data);\r\n                $this-&gt;messageManager-&gt;addSuccessMessage('Booking done!');\r\n            } catch (LocalizedException $e) {\r\n                $this-&gt;logger-&gt;error($e-&gt;getMessage());\r\n                $this-&gt;messageManager-&gt;addErrorMessage('Something went wrong during booking.');\r\n            }\r\n        }\r\n        $resultRedirect = $this-&gt;resultFactory-&gt;create(ResultFactory::TYPE_REDIRECT);\r\n        $resultRedirect-&gt;setPath('showroom\/booking');\r\n        return $resultRedirect;\r\n    }\r\n\r\n    \/**\r\n     * @param $data\r\n     *\/\r\n    private function sendEmailToAdmin($data)\r\n    {\r\n        $sender = [\r\n            'name' =&gt; $this-&gt;escaper-&gt;escapeHtml($data['customer_name']),\r\n            'email' =&gt; $this-&gt;escaper-&gt;escapeHtml($data['customer_email']),\r\n        ];\r\n        $postObject = new DataObject();\r\n        $postObject-&gt;setData($data);\r\n        try {\r\n            $transport =\r\n                $this-&gt;transportBuilder\r\n                    -&gt;setTemplateIdentifier('showroom_booking_email_template')\r\n                    -&gt;setTemplateOptions(\r\n                        ['area' =&gt; \\Magento\\Framework\\App\\Area::AREA_FRONTEND,\r\n                            'store' =&gt; \\Magento\\Store\\Model\\Store::DEFAULT_STORE_ID,]\r\n                    )\r\n                    -&gt;setTemplateVars(['data' =&gt; $postObject])\r\n                    -&gt;setFrom($sender)\r\n                    -&gt;addTo($this-&gt;helperData-&gt;getRecipient())\r\n                    -&gt;getTransport();\r\n            $transport-&gt;sendMessage();\r\n        } catch (LocalizedException $e) {\r\n            $this-&gt;logger-&gt;error($e-&gt;getMessage());\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p><strong>Configuration<\/strong> <strong>for<\/strong> <strong>controllers<\/strong> is placed in app\/code\/BelVG\/Showroom\/etc\/frontend\/routes.xml<\/p>\n<p>The form will be accessed on the page http:\/\/&lt;domain&gt;\/showroom\/booking\/<\/p>\n<pre class=\"lang:default decode:true\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;config xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"urn:magento:framework:App\/etc\/routes.xsd\"&gt;\r\n    &lt;router id=\"standard\"&gt;\r\n        &lt;route id=\"showroom\" frontName=\"showroom\"&gt;\r\n            &lt;module name=\"BelVG_Showroom\"\/&gt;\r\n        &lt;\/route&gt;\r\n    &lt;\/router&gt;\r\n&lt;\/config&gt;\r\n<\/pre>\n<ol start=\"3\">\n<li>Create the <strong>form<\/strong> <strong>displaying<\/strong> on the site<\/li>\n<\/ol>\n<p>app\/code\/BelVG\/Showroom\/Block\/Booking.php<\/p>\n<pre class=\"lang:default decode:true\">&lt;?php\r\n\r\nnamespace BelVG\\Showroom\\Block;\r\n\r\nuse Magento\\Framework\\View\\Element\\Template;\r\nuse Magento\\Framework\\View\\Element\\Template\\Context;\r\nuse BelVG\\Showroom\\Model\\ResourceModel\\Showroom\\Collection;\r\nuse BelVG\\Showroom\\Helper\\Data;\r\n\r\nclass Booking extends Template\r\n{\r\n    \/**\r\n     * @var Data\r\n     *\/\r\n    protected $helperData;\r\n\r\n    \/**\r\n     * @var Collection\r\n     *\/\r\n    protected $collection;\r\n\r\n    \/**\r\n     * Construct\r\n     *\r\n     * @param Data $helperData\r\n     * @param Collection $collection\r\n     * @param Context $context\r\n     * @param array $data\r\n     *\/\r\n    public function __construct(\r\n        Data $helperData,\r\n        Collection $collection,\r\n        Context $context,\r\n        array $data = []\r\n    ) {\r\n        $this-&gt;collection = $collection;\r\n        $this-&gt;helperData = $helperData;\r\n        parent::__construct($context, $data);\r\n    }\r\n\r\n    \/**\r\n     * @return string\r\n     *\/\r\n    public function getFormActionUrl()\r\n    {\r\n        return $this-&gt;getUrl('showroom\/booking\/save', ['_secure' =&gt; false]);\r\n    }\r\n\r\n    \/**\r\n     * @return Collection|null\r\n     *\/\r\n    public function getShowrooms()\r\n    {\r\n        $showrooms = $this-&gt;collection-&gt;getItems();\r\n        if (!empty($showrooms)) {\r\n            return $showrooms;\r\n        }\r\n        return null;\r\n    }\r\n\r\n    \/**\r\n     * @return \\Magento\\Customer\\Model\\Customer|null\r\n     *\/\r\n    public function getCustomer()\r\n    {\r\n        if ($customer = $this-&gt;helperData-&gt;getCustomer()) {\r\n            return $customer;\r\n        }\r\n        return null;\r\n    }\r\n}\r\n<\/pre>\n<p>The name of the <strong>layout file<\/strong> is &lt;route_name&gt;_&lt;controller_path&gt;<\/p>\n<p>app\/code\/BelVG\/Showroom\/view\/frontend\/layout\/showroom_booking_index.xml<\/p>\n<pre class=\"lang:default decode:true \">&lt;?xml version=\"1.0\"?&gt;\r\n&lt;page layout=\"2columns-left\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"urn:magento:framework:View\/Layout\/etc\/page_configuration.xsd\"&gt;\r\n    &lt;head&gt;\r\n        &lt;title&gt;Showroom Booking&lt;\/title&gt;\r\n    &lt;\/head&gt;\r\n    &lt;body&gt;\r\n        &lt;referenceBlock name=\"navigation.sections\" remove=\"true\" \/&gt;\r\n        &lt;referenceContainer name=\"content\"&gt;\r\n            &lt;block class=\"BelVG\\Showroom\\Block\\Booking\" name=\"showroom_booking\" template=\"BelVG_Showroom::showroom\/booking\/form.phtml\"\/&gt;\r\n        &lt;\/referenceContainer&gt;\r\n    &lt;\/body&gt;\r\n&lt;\/page&gt;<\/pre>\n<p>app\/code\/BelVG\/Showroom\/view\/frontend\/templates\/showroom\/booking\/form.phtml<\/p>\n<pre class=\"lang:default decode:true\">app\/code\/BelVG\/Showroom\/Helper\/Data.php\r\n\r\n&lt;?php\r\n\r\nnamespace BelVG\\Showroom\\Helper;\r\n\r\nuse Magento\\Framework\\App\\Helper\\AbstractHelper;\r\nuse Magento\\Framework\\App\\Helper\\Context;\r\nuse Magento\\Store\\Model\\ScopeInterface;\r\nuse Magento\\Customer\\Model\\Session;\r\n\r\nclass Data extends AbstractHelper\r\n{\r\n    const IS_ENABLED_PATH = 'showroom\/general\/enable';\r\n\r\n    \/**\r\n     * @var Session\r\n     *\/\r\n    protected $customerSession;\r\n\r\n    public function __construct(\r\n        Context $context,\r\n        Session $customerSession\r\n    )\r\n    {\r\n        parent::__construct($context);\r\n        $this-&gt;customerSession = $customerSession;\r\n    }\r\n\r\n    \/**\r\n     * @param null $storeId\r\n     * @return bool|mixed\r\n     *\/\r\n    public function isModuleOutputEnabled($storeId = null)\r\n    {\r\n        return $this-&gt;scopeConfig-&gt;getValue(\r\n            self::IS_ENABLED_PATH, ScopeInterface::SCOPE_STORE, $storeId\r\n        );\r\n    }\r\n\r\n    \/**\r\n     * @return \\Magento\\Customer\\Model\\Customer|null\r\n     *\/\r\n    public function getCustomer()\r\n    {\r\n        if ($this-&gt;customerSession-&gt;isLoggedIn()) {\r\n            return $this-&gt;customerSession-&gt;getCustomer();\r\n        }\r\n        return null;\r\n    }\r\n\r\n    \/**\r\n     * @return mixed\r\n     *\/\r\n    public function getRecipient()\r\n    {\r\n        return $this-&gt;scopeConfig-&gt;getValue('trans_email\/ident_support\/email',ScopeInterface::SCOPE_STORE);\r\n    }\r\n}\r\n<\/pre>\n<ol start=\"4\">\n<li><strong>Create<\/strong> <strong>database<\/strong> <strong>data<\/strong> and <strong>models<\/strong><\/li>\n<\/ol>\n<p>To create access to the database, data Models and Collection are used. Here is a base set of Models which are used for manipulating data.<\/p>\n<p>app\/code\/BelVG\/Showroom\/Model\/Showroom.php<\/p>\n<pre class=\"lang:default decode:true\">&lt;?php\r\n\r\nnamespace BelVG\\Showroom\\Model;\r\n\r\nuse Magento\\Framework\\Model\\AbstractModel;\r\nuse Magento\\Framework\\DataObject\\IdentityInterface;\r\n\r\nclass Showroom extends AbstractModel implements IdentityInterface\r\n{\r\n    const CACHE_TAG = 'belvg_showroom';\r\n\r\n    \/**\r\n     * @var string\r\n     *\/\r\n    protected $_cacheTag = 'belvg_showroom';\r\n\r\n    \/**\r\n     * @var string\r\n     *\/\r\n    protected $_eventPrefix = 'belvg_showroom';\r\n\r\n    protected function _construct()\r\n    {\r\n        $this-&gt;_init('BelVG\\Showroom\\Model\\ResourceModel\\Showroom');\r\n    }\r\n\r\n    \/**\r\n     * @return string[]\r\n     *\/\r\n    public function getIdentities()\r\n    {\r\n        return [self::CACHE_TAG . '_' . $this-&gt;getId()];\r\n    }\r\n\r\n    \/**\r\n     * @return array\r\n     *\/\r\n    public function getDefaultValues()\r\n    {\r\n        $values = [];\r\n\r\n        return $values;\r\n    }\r\n}<\/pre>\n<p>app\/code\/BelVG\/Showroom\/Model\/ResourceModel\/Showroom.php<\/p>\n<pre class=\"lang:default decode:true\">namespace BelVG\\Showroom\\Model\\ResourceModel;\r\n\r\nuse Magento\\Framework\\Model\\ResourceModel\\Db\\AbstractDb;\r\nuse Magento\\Framework\\Model\\ResourceModel\\Db\\Context;\r\n\r\nclass Showroom extends AbstractDb\r\n{\r\n    \/**\r\n     * Showroom constructor.\r\n     * @param Context $context\r\n     *\/\r\n    public function __construct(\r\n        Context $context\r\n    ) {\r\n        parent::__construct($context);\r\n    }\r\n\r\n    protected function _construct()\r\n    {\r\n        $this-&gt;_init('belvg_showroom', 'showroom_id');\r\n    }\r\n}\r\n<\/pre>\n<p>app\/code\/BelVG\/Showroom\/Model\/ResourceModel\/Showroom\/Collection.php<\/p>\n<p>&lt;?php namespace BelVG\\Showroom\\Model\\ResourceModel\\Showroom; use Magento\\Framework\\Model\\ResourceModel\\Db\\Collection\\AbstractCollection;&nbsp;class Collection extends AbstractCollection<\/p>\n<pre class=\"lang:default decode:true \">{\r\n    \/**\r\n     * @var string\r\n     *\/\r\n    protected $_idFieldName = 'showroom_id';\r\n\r\n    \/**\r\n     * @var string\r\n     *\/\r\n    protected $_eventPrefix = 'belvg_showroom_collection';\r\n\r\n    \/**\r\n     * @var string\r\n     *\/\r\n    protected $_eventObject = 'showroom_collection';\r\n\r\n    \/**\r\n     * Define resource model\r\n     *\r\n     * @return void\r\n     *\/\r\n    protected function _construct()\r\n    {\r\n        $this-&gt;_init('BelVG\\Showroom\\Model\\Showroom', 'BelVG\\Showroom\\Model\\ResourceModel\\Showroom');\r\n    }\r\n}<\/pre>\n<p>To add database data, <strong>InstallSchema<\/strong> and <strong>InstallData<\/strong> scripts are implemented.<\/p>\n<p>InstallSchema is used for adding tables, fields, etc.<\/p>\n<p>InstallData is used to add necessary content for the extension.<\/p>\n<p>I used InstallData to add a <strong>list of showrooms<\/strong>.<\/p>\n<p>app\/code\/BelVG\/Showroom\/Setup\/InstallData.php<\/p>\n<pre class=\"lang:default decode:true\">&lt;?php\r\n\r\nnamespace BelVG\\Showroom\\Setup;\r\n\r\nuse BelVG\\Showroom\\Model\\ShowroomFactory;\r\nuse Magento\\Framework\\Setup\\InstallDataInterface;\r\nuse Magento\\Framework\\Setup\\ModuleContextInterface;\r\nuse Magento\\Framework\\Setup\\ModuleDataSetupInterface;\r\n\r\nclass InstallData implements InstallDataInterface\r\n{\r\n    \/**\r\n     * @var ShowroomFactory\r\n     *\/\r\n    protected $showroomFactory;\r\n\r\n    \/**\r\n     * InstallData constructor.\r\n     * @param ShowroomFactory $showroomFactory\r\n     *\/\r\n    public function __construct(\r\n        ShowroomFactory $showroomFactory\r\n    ) {\r\n        $this-&gt;showroomFactory = $showroomFactory;\r\n    }\r\n\r\n    \/**\r\n     * @param ModuleDataSetupInterface $setup\r\n     * @param ModuleContextInterface $context\r\n     * @throws \\Exception\r\n     *\/\r\n    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)\r\n    {\r\n        $showrooms = [\r\n            ['showroom_name' =&gt; \"Test Showroom 1\"],\r\n            ['showroom_name' =&gt; \"Test Showroom 2\"],\r\n            ['showroom_name' =&gt; \"Test Showroom 3\"],\r\n            ['showroom_name' =&gt; \"Test Showroom 4\"],\r\n            ['showroom_name' =&gt; \"Test Showroom 5\"]\r\n        ];\r\n        foreach ($showrooms as $data) {\r\n            $showroom = $this-&gt;showroomFactory-&gt;create();\r\n            $showroom-&gt;addData($data)-&gt;save();\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>app\/code\/BelVG\/Showroom\/Setup\/InstallSchema.php<\/p>\n<pre class=\"lang:default decode:true\">&lt;?php\r\n\r\nnamespace BelVG\\Showroom\\Setup;\r\n\r\nuse Magento\\Framework\\DB\\Adapter\\AdapterInterface;\r\nuse Magento\\Framework\\DB\\Ddl\\Table;\r\nuse Magento\\Framework\\Setup\\InstallSchemaInterface;\r\nuse Magento\\Framework\\Setup\\ModuleContextInterface;\r\nuse Magento\\Framework\\Setup\\SchemaSetupInterface;\r\nuse Psr\\Log\\LoggerInterface;\r\n\r\nclass InstallSchema implements InstallSchemaInterface\r\n{\r\n    \/**\r\n     * @var LoggerInterface\r\n     *\/\r\n    protected $logger;\r\n\r\n    \/**\r\n     * InstallSchema constructor.\r\n     * @param LoggerInterface $logger\r\n     *\/\r\n    public function __construct(\r\n        LoggerInterface $logger\r\n    ) {\r\n        $this-&gt;logger = $logger;\r\n    }\r\n\r\n    \/**\r\n     * @param SchemaSetupInterface $setup\r\n     * @param ModuleContextInterface $context\r\n     *\/\r\n    public function install(\r\n        SchemaSetupInterface $setup,\r\n        ModuleContextInterface $context\r\n    ) {\r\n        $installer = $setup;\r\n        $installer-&gt;startSetup();\r\n        if (!$installer-&gt;tableExists('belvg_booking_showroom')) {\r\n            try {\r\n                $tableBookingShowroom = $installer-&gt;getConnection()-&gt;newTable(\r\n                    $installer-&gt;getTable('belvg_booking_showroom')\r\n                )\r\n                    -&gt;addColumn(\r\n                        'booking_id',\r\n                        Table::TYPE_INTEGER,\r\n                        null,\r\n                        [\r\n                            'identity' =&gt; true,\r\n                            'nullable' =&gt; false,\r\n                            'primary' =&gt; true,\r\n                            'unsigned' =&gt; true,\r\n                        ],\r\n                        'Booking ID'\r\n                    )\r\n                    -&gt;addColumn(\r\n                        'customer_name',\r\n                        Table::TYPE_TEXT,\r\n                        255,\r\n                        ['nullable =&gt; false'],\r\n                        'Customer Name'\r\n                    )\r\n                    -&gt;addColumn(\r\n                        'customer_email',\r\n                        Table::TYPE_TEXT,\r\n                        255,\r\n                        ['nullable =&gt; false'],\r\n                        'Customer Email'\r\n                    )\r\n                    -&gt;addColumn(\r\n                        'booking_date',\r\n                        Table::TYPE_TIMESTAMP,\r\n                        null,\r\n                        ['nullable' =&gt; false, 'default' =&gt; Table::TIMESTAMP_INIT_UPDATE],\r\n                        'Booking Date'\r\n                    )\r\n                    -&gt;addColumn(\r\n                        'showroom_name',\r\n                        Table::TYPE_TEXT,\r\n                        255,\r\n                        ['nullable =&gt; false'],\r\n                        'Showroom Name'\r\n                    )\r\n                    -&gt;setComment('Booking Showroom Table');\r\n                $installer-&gt;getConnection()-&gt;createTable($tableBookingShowroom);\r\n            } catch (\\Zend_Db_Exception $e) {\r\n                $this-&gt;logger-&gt;error($e-&gt;getMessage());\r\n            }\r\n\r\n            $installer-&gt;getConnection()-&gt;addIndex(\r\n                $installer-&gt;getTable('belvg_booking_showroom'),\r\n                $setup-&gt;getIdxName(\r\n                    $installer-&gt;getTable('belvg_booking_showroom'),\r\n                    ['customer_name', 'showroom_name', 'customer_email'],\r\n                    AdapterInterface::INDEX_TYPE_FULLTEXT\r\n                ),\r\n                ['customer_name', 'showroom_name', 'customer_email'],\r\n                AdapterInterface::INDEX_TYPE_FULLTEXT\r\n            );\r\n        }\r\n        if (!$installer-&gt;tableExists('belvg_showroom')) {\r\n            try {\r\n                $tableShowroom = $installer-&gt;getConnection()-&gt;newTable(\r\n                    $installer-&gt;getTable('belvg_showroom')\r\n                )\r\n                    -&gt;addColumn(\r\n                        'showroom_id',\r\n                        Table::TYPE_INTEGER,\r\n                        null,\r\n                        [\r\n                            'identity' =&gt; true,\r\n                            'nullable' =&gt; false,\r\n                            'primary' =&gt; true,\r\n                            'unsigned' =&gt; true,\r\n                        ],\r\n                        'Showroom ID'\r\n                    )\r\n                    -&gt;addColumn(\r\n                        'showroom_name',\r\n                        Table::TYPE_TEXT,\r\n                        255,\r\n                        ['nullable =&gt; false'],\r\n                        'Showroom Name'\r\n                    )\r\n                    -&gt;setComment('Showroom Table');\r\n                $installer-&gt;getConnection()-&gt;createTable($tableShowroom);\r\n            } catch (\\Zend_Db_Exception $e) {\r\n                $this-&gt;logger-&gt;error($e-&gt;getMessage());\r\n            }\r\n\r\n            $installer-&gt;getConnection()-&gt;addIndex(\r\n                $installer-&gt;getTable('belvg_showroom'),\r\n                $setup-&gt;getIdxName(\r\n                    $installer-&gt;getTable('belvg_showroom'),\r\n                    ['showroom_name'],\r\n                    AdapterInterface::INDEX_TYPE_FULLTEXT\r\n                ),\r\n                ['showroom_name'],\r\n                AdapterInterface::INDEX_TYPE_FULLTEXT\r\n            );\r\n        }\r\n        $installer-&gt;endSetup();\r\n    }\r\n}\r\n<\/pre>\n<p>Here is an example of <strong>Database tables<\/strong>:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/belvg.com\/wp-content\/uploads\/2019\/06\/pixel.png\" data-src=\"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2020\/12\/modules-in-magento2-2-1.jpg\" alt=\"modules-in-magento2-2\" width=\"1252\" height=\"686\" class=\"lazy aligncenter size-full wp-image-26811\" title=\"Modules in Magento 2\"><\/p>\n<h2><\/h2>\n<h2 id=\"step_4\">The admin part<\/h2>\n<p>The form will be accessed on the page http:\/\/&lt;domain&gt;\/&lt;backend_url&gt;\/showroom\/booking\/index<\/p>\n<p>Here is an example of&nbsp;<strong>Grid<\/strong>:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/belvg.com\/wp-content\/uploads\/2019\/06\/pixel.png\" data-src=\"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2020\/12\/modules-in-magento2-3.jpg\" alt=\"modules-in-magento2-3\" width=\"1338\" height=\"487\" class=\"lazy aligncenter size-full wp-image-26807\" title=\"Modules in Magento 2\"><\/p>\n<p>&nbsp;<\/p>\n<p>Here is an example of the&nbsp;<strong>Module&rsquo;s configuration<\/strong>:<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/belvg.com\/wp-content\/uploads\/2019\/06\/pixel.png\" data-src=\"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2020\/12\/modules-in-magento2-4.jpg\" alt=\"modules-in-magento2-4\" width=\"1337\" height=\"224\" class=\"lazy aligncenter size-full wp-image-26808\" title=\"Modules in Magento 2\"><\/p>\n<p>&nbsp;<\/p>\n<p>There are two more ways that are often used to <strong>extend<\/strong> the existing methods in Magento 2 concepts: <strong>plugins<\/strong> and <strong>observers<\/strong>.<\/p>\n<p>You can find more detailed information about <strong>plugins<\/strong>&nbsp;<a href=\"https:\/\/developer.adobe.com\/commerce\/php\/development\/components\/plugins\/\" target=\"_blank\" rel=\"noopener\">here<\/a>. They could be used for every public method allowing you to add the code before or after the method or override the whole method.<\/p>\n<p><strong>Observers<\/strong> allow you to put the code inside the method using special events. You could use an already existing event or create your own one to extend your own methods when needed.<\/p>\n<p>You can find more detailed information about <strong>observers<\/strong>&nbsp;<a href=\"https:\/\/developer.adobe.com\/commerce\/php\/development\/components\/events-and-observers\/\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<h2 id=\"step_5\">Debugging process<\/h2>\n<p>Magento should be turned to developer mode for the debugging process.<\/p>\n<p>To configure <strong>Xdebug<\/strong> in <strong>PhpStorm<\/strong> use the <a href=\"https:\/\/developer.adobe.com\/commerce\/testing\/functional-testing-framework\/debugging\/\" target=\"_blank\" rel=\"noopener\">guide<\/a>.<\/p>\n<p>To enable errors displaying two strings should be uncommented in app\/bootstrap.php<\/p>\n<pre class=\"lang:default decode:true \">error_reporting(E_ALL);\r\nini_set('display_errors', 1);\r\n<\/pre>\n<p>To download the full version of the extension to see the implementation of the <a href=\"https:\/\/github.com\/aleksmitskevich\/showroom\" target=\"_blank\" rel=\"noopener\">admin part<\/a><\/p>\n<p><strong>I hope that this article was helpful to you. Please feel free to share your opinion in the comments below!<\/strong><\/p>\n\n","protected":false},"excerpt":{"rendered":"In this article, we will consider the ways to enhance your product with the help &#8230;","protected":false},"author":12,"featured_media":26779,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"image","meta":{"_acf_changed":false,"footnotes":""},"categories":[474,491],"tags":[],"class_list":["post-26772","post","type-post","status-publish","format-image","has-post-thumbnail","hentry","category-ecommerce","category-magento-2","post_format-post-format-image"],"acf":[],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"In this article you will learn how to install modules in Magento 2, as well as about dependency injection, custom module structure, the admin part, debugging\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Aliaksandr Simonchik\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/belvg.com\/blog\/modules-in-magento2.html\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html#article\",\"name\":\"Modules in Magento 2 | BelVG Blog\",\"headline\":\"Modules in Magento 2\",\"author\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/author\\\/alex-simonchik#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#organization\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/modules-in-magento2-banner.jpg\",\"width\":1108,\"height\":590,\"caption\":\"modules-in-magento2-banner\"},\"datePublished\":\"2020-12-21T16:40:29+02:00\",\"dateModified\":\"2026-02-13T19:18:13+02:00\",\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html#webpage\"},\"articleSection\":\"ECOMMERCE, Magento 2, Image\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/belvg.com\\\/blog\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/category\\\/ecommerce#listItem\",\"name\":\"ECOMMERCE\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/category\\\/ecommerce#listItem\",\"position\":2,\"name\":\"ECOMMERCE\",\"item\":\"https:\\\/\\\/belvg.com\\\/blog\\\/category\\\/ecommerce\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html#listItem\",\"name\":\"Modules in Magento 2\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html#listItem\",\"position\":3,\"name\":\"Modules in Magento 2\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/category\\\/ecommerce#listItem\",\"name\":\"ECOMMERCE\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#organization\",\"name\":\"BelVG Blog\",\"description\":\"Magento and Prestashop articles\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/author\\\/alex-simonchik#author\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/author\\\/alex-simonchik\",\"name\":\"Aliaksandr Simonchik\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6553917a81b1da7866b8b875368df6cbbec56413c3438694df8539de7fb092c0?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"Aliaksandr Simonchik\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html#webpage\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html\",\"name\":\"Modules in Magento 2 | BelVG Blog\",\"description\":\"In this article you will learn how to install modules in Magento 2, as well as about dependency injection, custom module structure, the admin part, debugging\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/author\\\/alex-simonchik#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/author\\\/alex-simonchik#author\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/wp-content\\\/uploads\\\/2020\\\/12\\\/modules-in-magento2-banner.jpg\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html\\\/#mainImage\",\"width\":1108,\"height\":590,\"caption\":\"modules-in-magento2-banner\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/modules-in-magento2.html#mainImage\"},\"datePublished\":\"2020-12-21T16:40:29+02:00\",\"dateModified\":\"2026-02-13T19:18:13+02:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/\",\"name\":\"BelVG Blog\",\"description\":\"Magento and Prestashop articles\",\"inLanguage\":\"en-US\",\"publisher\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"Modules in Magento 2 | BelVG Blog","description":"In this article you will learn how to install modules in Magento 2, as well as about dependency injection, custom module structure, the admin part, debugging","canonical_url":"https:\/\/belvg.com\/blog\/modules-in-magento2.html","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/belvg.com\/blog\/modules-in-magento2.html#article","name":"Modules in Magento 2 | BelVG Blog","headline":"Modules in Magento 2","author":{"@id":"https:\/\/belvg.com\/blog\/author\/alex-simonchik#author"},"publisher":{"@id":"https:\/\/belvg.com\/blog\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2020\/12\/modules-in-magento2-banner.jpg","width":1108,"height":590,"caption":"modules-in-magento2-banner"},"datePublished":"2020-12-21T16:40:29+02:00","dateModified":"2026-02-13T19:18:13+02:00","inLanguage":"en-US","mainEntityOfPage":{"@id":"https:\/\/belvg.com\/blog\/modules-in-magento2.html#webpage"},"isPartOf":{"@id":"https:\/\/belvg.com\/blog\/modules-in-magento2.html#webpage"},"articleSection":"ECOMMERCE, Magento 2, Image"},{"@type":"BreadcrumbList","@id":"https:\/\/belvg.com\/blog\/modules-in-magento2.html#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/#listItem","position":1,"name":"Home","item":"https:\/\/belvg.com\/blog\/","nextItem":{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/category\/ecommerce#listItem","name":"ECOMMERCE"}},{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/category\/ecommerce#listItem","position":2,"name":"ECOMMERCE","item":"https:\/\/belvg.com\/blog\/category\/ecommerce","nextItem":{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/modules-in-magento2.html#listItem","name":"Modules in Magento 2"},"previousItem":{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/modules-in-magento2.html#listItem","position":3,"name":"Modules in Magento 2","previousItem":{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/category\/ecommerce#listItem","name":"ECOMMERCE"}}]},{"@type":"Organization","@id":"https:\/\/belvg.com\/blog\/#organization","name":"BelVG Blog","description":"Magento and Prestashop articles","url":"https:\/\/belvg.com\/blog\/"},{"@type":"Person","@id":"https:\/\/belvg.com\/blog\/author\/alex-simonchik#author","url":"https:\/\/belvg.com\/blog\/author\/alex-simonchik","name":"Aliaksandr Simonchik","image":{"@type":"ImageObject","@id":"https:\/\/belvg.com\/blog\/modules-in-magento2.html#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/6553917a81b1da7866b8b875368df6cbbec56413c3438694df8539de7fb092c0?s=96&d=mm&r=g","width":96,"height":96,"caption":"Aliaksandr Simonchik"}},{"@type":"WebPage","@id":"https:\/\/belvg.com\/blog\/modules-in-magento2.html#webpage","url":"https:\/\/belvg.com\/blog\/modules-in-magento2.html","name":"Modules in Magento 2 | BelVG Blog","description":"In this article you will learn how to install modules in Magento 2, as well as about dependency injection, custom module structure, the admin part, debugging","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/belvg.com\/blog\/#website"},"breadcrumb":{"@id":"https:\/\/belvg.com\/blog\/modules-in-magento2.html#breadcrumblist"},"author":{"@id":"https:\/\/belvg.com\/blog\/author\/alex-simonchik#author"},"creator":{"@id":"https:\/\/belvg.com\/blog\/author\/alex-simonchik#author"},"image":{"@type":"ImageObject","url":"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2020\/12\/modules-in-magento2-banner.jpg","@id":"https:\/\/belvg.com\/blog\/modules-in-magento2.html\/#mainImage","width":1108,"height":590,"caption":"modules-in-magento2-banner"},"primaryImageOfPage":{"@id":"https:\/\/belvg.com\/blog\/modules-in-magento2.html#mainImage"},"datePublished":"2020-12-21T16:40:29+02:00","dateModified":"2026-02-13T19:18:13+02:00"},{"@type":"WebSite","@id":"https:\/\/belvg.com\/blog\/#website","url":"https:\/\/belvg.com\/blog\/","name":"BelVG Blog","description":"Magento and Prestashop articles","inLanguage":"en-US","publisher":{"@id":"https:\/\/belvg.com\/blog\/#organization"}}]}},"aioseo_meta_data":{"post_id":"26772","title":"Modules in Magento 2 | #site_title","description":"In this article you will learn how to install modules in Magento 2, as well as about dependency injection, custom module structure, the admin part, debugging","keywords":null,"keyphrases":null,"focus_keyword":null,"additional_keywords":null,"truseo_locale":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_custom_url":null,"og_image_custom_fields":null,"og_image_url":null,"og_image_width":null,"og_image_height":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_image_url":null,"twitter_title":null,"twitter_description":null,"schema_type":"default","schema_type_options":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"limit_modified_date":false,"ai":null,"breadcrumb_settings":null,"seo_analyzer_scan_date":null,"created":"2026-11-03 18:36:25","updated":"2026-11-03 18:36:25"},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/belvg.com\/blog\/\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/belvg.com\/blog\/category\/ecommerce\" title=\"ECOMMERCE\">ECOMMERCE<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tModules in Magento 2\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/belvg.com\/blog\/"},{"label":"ECOMMERCE","link":"https:\/\/belvg.com\/blog\/category\/ecommerce"},{"label":"Modules in Magento 2","link":"https:\/\/belvg.com\/blog\/modules-in-magento2.html"}],"post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/posts\/26772","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/comments?post=26772"}],"version-history":[{"count":21,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/posts\/26772\/revisions"}],"predecessor-version":[{"id":27512,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/posts\/26772\/revisions\/27512"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/media\/26779"}],"wp:attachment":[{"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/media?parent=26772"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/categories?post=26772"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/tags?post=26772"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}