Create a controller in Magento

Learn how to create a controller in Magento to respond to web requests.

M Bytes Newsletter
Get the developer newsletter

    Fresh bytes every Thursday. No spam, ever. Unsubscribe anytime.

    Join 9,000+ developers and get three free video lessons every week.

    Let's create a controller to handle requests to /foo/bar in Magento.

    Controllers are responsible for responding to page requests, and they depend on routes.

    Here’s a simple configuration for a foo route, which is responsible for all requests made to /foo:

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
        <router id="standard">
            <route id="foo" frontName="foo">
                <module name="Vendor_Module"/>
            </route>
        </router>
    </config>

    This configuration tells Magento that our Vendor_Module should handle any requests that start with /foo.

    Quick MVC Primer: Magento URLs follow a Model-View-Controller pattern: /routeName/controllerName/actionName. If you leave out the controllerName or actionName, they default to "index". So /foo/bar is identical to /foo/bar/index, and /foo is the same as /foo/index/index.

    Now let's create our controller. The file structure in Magento is pretty straightforward – controllers live in a Controller directory in your module, with subdirectories matching your URL structure.

    For our /foo/bar URL, we need:

    • A Controller directory in our module
    • A Bar subdirectory (capitalized version of our controller name)
    • An Index.php file (capitalized version of our action name)

    So our full path will be: app/code/Vendor/Module/Controller/Bar/Index.php

    Here's our controller code:

    <?php
     
    declare(strict_types=1);
     
    namespace Vendor\Module\Controller\Bar;
     
    use Magento\Framework\App\Action\HttpGetActionInterface;
    use Magento\Framework\View\Result\Page;
    use Magento\Framework\View\Result\PageFactory;
     
    class Index implements HttpGetActionInterface
    {
        /**
         * Index constructor.
         *
         * @param PageFactory $pageFactory
         */
        public function __construct(
            private readonly PageFactory $pageFactory,
        ) {
        }
     
        /**
         * Execute a controller action.
         *
         * @return Page
         */
        public function execute(): Page
        {
            return $this->pageFactory->create();
        }
    }

    Every controller implements HttpGetActionInterface, which requires an execute() method, which is responsible for returning a response to the browser.

    If we now attempt to load /foo/bar in our browser, we’ll see a blank page with no errors. That's perfect! It means our controller is working.

    This fairly blank page is expected, because Magento will now look at the layout XML and templates to render the rest of the page.