Skip to content
intermediate Phase 30 · Core XML Files

routes.xml Deep Dive

Multiple routes, router class overrides, route priority, and advanced routing configuration.

45m
0 problems
Topic Progress 0%

Multiple Routes Configuration

A single module can register multiple routes for different URL patterns.

Multiple routes in routes.xml:

<?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="vendor_blog" frontName="blog">
            <module name="Vendor_Blog"/>
        </route>
        <route id="vendor_news" frontName="news">
            <module name="Vendor_Blog"/>
        </route>
        <route id="vendor_blog_admin" frontName="blog_admin">
            <module name="Vendor_Blog" area="adminhtml"/>
        </route>
    </router>
</config>

URL mapping:

blog/post/view/id/1 → Vendor_Blog::Post::view
blog/category/list → Vendor_Blog::Category::list
news/article/read → Vendor_Blog::Article::read
blog_admin/post/edit → Vendor_Blog::Post::edit (admin area)

Route attributes:

  • id — Unique route identifier within the router
  • frontName — First URL segment (the front controller name)
  • area — Optional: restrict to specific area (adminhtml, frontend)

Area-specific routes:

<!-- etc/frontend/routes.xml -->
<router id="standard">
    <route id="vendor_blog" frontName="blog">
        <module name="Vendor_Blog"/>
    </route>
</router>

<!-- etc/adminhtml/routes.xml -->
<router id="admin">
    <route id="vendor_blog_admin" frontName="blog_admin">
        <module name="Vendor_Blog" area="adminhtml"/>
    </route>
</router>

Router Class Overrides

Magento allows overriding the default router class for custom URL matching logic.

Default router:

<router id="standard">
    <class>Magento\Framework\App\Router\Base</class>
</router>

Custom router:

<router id="standard">
    <class>Vendor\Module\Router\CustomRouter</class>
</router>

Custom router class:

<?php
namespace Vendor\Module\Router;

use Magento\Framework\App\Action\Forward;
use Magento\Framework\App\Action\Redirect;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\RouterInterface;

class CustomRouter implements RouterInterface
{
    public function __construct(
        private \Magento\Framework\App\ActionFactory $actionFactory,
        private \Magento\Framework\App\Config\ScopeConfigInterface $config
    ) {}
    
    public function match(RequestInterface $request): ?ActionInterface
    {
        $urlKey = trim($request->getPathInfo(), '/');
        
        // Custom URL matching logic
        if (preg_match('/^product\/([\w-]+)$/', $urlKey, $matches)) {
            $request->setRouteName('catalog');
            $request->setControllerName('product');
            $request->setActionName('view');
            $request->setParam('url_key', $matches[1]);
            
            return $this->actionFactory->create(
                \Magento\Catalog\Controller\Product\View::class
            );
        }
        
        return null; // Let next router handle it
    }
}

Multiple routers (priority order):

<!-- Routers execute in order -->
<router id="standard">
    <class>Magento\Framework\App\Router\Base</class>
</router>

<!-- Custom router added via di.xml -->
<type name="Magento\Framework\App\Router\Base">
    <arguments>
        <argument name="actionList" xsi:type="array">
            <item name="custom_router" xsi:type="object">
                Vendor\Module\Router\CustomRouter
            </item>
        </argument>
    </arguments>
</type>

Route Priority and Matching

Understanding how Magento matches URLs to routes and controllers.

URL structure:

https://example.com/{frontName}/{controller}/{action}/{param}/{value}

Example:

https://example.com/blog/post/view/id/5
         └─ frontName ─┘└─ controller ─┘└─ action ─┘└─ param/value ─┘

Route matching process:

1. Extract frontName from URL
2. Find matching route in routes.xml
3. Map frontName → controller → action
4. Execute action class

Controller mapping:

frontName: blog
controller: post
action: view

→ Vendor/Blog/Controller/Post/View.php

Custom URL key in controller:

namespace Vendor\Blog\Controller\Post;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;

class View extends Action
{
    public function execute()
    {
        $id = $this->getRequest()->getParam('id');
        $urlKey = $this->getRequest()->getParam('url_key');
        
        // URL key can be used for custom matching
        if ($urlKey) {
            // Load by URL key instead of ID
        }
        
        return $this->resultFactory->create(
            \Magento\Framework\View\Result\Page::class
        );
    }
}

Priority rules:

1. Exact match wins over pattern match
2. First matching router returns the action
3. If no router matches, 404 is returned
4. URL rewrites are checked before routes

URL Rewrite Integration

Magento's URL rewrite system integrates with routing for SEO-friendly URLs.

URL rewrite storage:

url_rewrite table:
├── entity_type (product, category, cms)
├── entity_id
├── request_path (/my-product.html)
├── target_path (catalog/product/view/id/5)
└── redirect_type (301, 302)

Custom URL rewrite in code:

$rewrite = $this->rewriteFactory->create();
$rewrite->setEntityType('custom');
$rewrite->setEntityId(123);
$rewrite->setRequestPath('custom/url.html');
$rewrite->setTargetPath('custom_module/controller/action/id/123');
$rewrite->save();

Route + URL rewrite flow:

1. User visits: /my-product.html
2. URL rewrite table lookup
3. Found: target_path = catalog/product/view/id/5
4. Route: frontName = catalog
5. Controller: Product::View
6. Action executed with id=5

Custom URL rewrite module:

<?php
namespace Vendor\SEO\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;

class ProductUrlObserver implements ObserverInterface
{
    public function execute(Observer $observer)
    {
        $product = $observer->getEvent()->getProduct();
        
        // Create custom URL rewrite for product
        $this->createRewrite(
            $product->getUrlKey(),
            'catalog/product/view/id/' . $product->getId()
        );
    }
}

Debugging routes:

# Check route configuration
php bin/magento dev:router:list

# View URL rewrites
php bin/magento urlrewrite:index

# Clear URL rewrites
php bin/magento urlrewrite:reindex

Quiz

1. What attribute in routes.xml sets the first URL segment?

Question 1 options

2. How does URL mapping work for blog/post/view?

Question 2 options

3. What happens when no router matches a URL?

Question 3 options

4. Where are URL rewrites stored?

Question 4 options

Flashcards

Question

What does frontName represent in a URL?

Answer

The first path segment that maps to a route (e.g., 'blog' in /blog/post/view)

Question

What is the controller mapping for catalog/product/view?

Answer

Catalog controller, Product class, view action

Question

How do multiple routes resolve?

Answer

First matching router returns the action; priority goes to exact matches

Question

What is checked before routes during URL resolution?

Answer

URL rewrites (from url_rewrite table)

Question

What CLI command lists available routes?

Answer

php bin/magento dev:router:list

Revision Notes

Key Takeaways

  • 1. A single module can have multiple routes with different frontNames
  • 2. Router classes can be overridden for custom URL matching
  • 3. URL structure: frontName/controller/action/params
  • 4. URL rewrites are checked before route matching
  • 5. Route priority favors exact matches over patterns
  • 6. area attribute restricts routes to specific areas

Interview Tips

  • Explain the URL-to-controller mapping process
  • Describe how to create a custom router
  • Discuss URL rewrite integration with routing
  • Know how to debug route configuration

Cheat Sheet

routes.xml Cheat Sheet

URL Structure:
/frontName/controller/action/param/value

Route attributes:

  • id: Unique route identifier
  • frontName: First URL segment
  • area: adminhtml/frontend (optional)

Controller mapping:
frontName/post → Vendor/Module/Controller/Post.php
frontName/post/view → Vendor/Module/Controller/Post/View.php

Priority:

  1. URL rewrites (url_rewrite table)
  2. Exact route match
  3. First matching router
  4. 404 if nothing matches

CLI:

  • dev:router:list — List routes
  • urlrewrite:index — Reindex rewrites