2.2.1: Routes and Layout Handles

2.2: Front-end Basics

In this section, we'll begin building out the real content of our Product Questions feature on the product detail page.

Routes and Layout Handles

Within our module, the file view/frontend/layout/catalog_product_view.xml controls the content we are injecting into the product detail page. We've more or less glossed over the mechanics of this file until now. It's time to get acquainted with it!

Before examining the contents of a layout XML file, however, the first question we ought to ask is why a file of this particular name affects this particular page. How do we know what filename to create when we want to update layout in a particular area?

To discover this, let's use an example a little more straightforward than the product detail page. On your storefront, if you haven't yet registered a customer account, do so now and log in. Visit My Account from the site's top navigation, then "My Orders" in the left navigation menu within your account. Once you've arrived here, you should be able to observe that the URL path for this particular page is:

/sales/order/history


Basically all destinations on your storefront have just such a three-segment URL path. (Even when a URL path contains only two segments - as you'll observe with /checkout/cart, there is an "implied" third segment: index. And the "implied" segments of the simple URL path /checkout expand out to /checkout/index/index.)

Core Concept

You may notice that some URLs on the storefront include more than three segments, such as the URL for viewing a specific order: /sales/order/view/order_id/{id}. Typically, all segments after the first three comprise key/value pairs that get passed in as if they were querystring parameters. So by the time the aforementioned URL path results in the /sales/order/view controller being executed, available request parameters include order_id with a value corresponding with the 5th URL segment.

Three significant URL segments ... that looks an awful lot like the pattern we see in our existing layout file. You might guess, then, that the proper layout filename for updating content on the My Account order view page is sales_order_history.xml. And you'd be right! Except ... there's a potential wrinkle. To understand it, let's go to the source of truth for how URLs are directed to the right application logic: routes.

The module config file routes.xml defines routes, which are responsible for matching a URL pattern (typically the first URL segment) to a module where controller classes will be located. This is another config file that is always applicable to one area of the site or other, and so the relevant route for /sales/order/history is located in vendor/magento/module-sales/etc/frontend/routes.xml. Let's take a peek at the contents:

<router id="standard">
    <route id="sales" frontName="sales">
        <module name="Magento_Sales" />
    </route>
</router>

Different "router" classes in Magento provide different logic, and we can see here that the routes being defined are within the scope of the "standard" router, which is the one virtually all of your front-end routes will use as well. A <route> is defined with a particular frontName, used to match the first segment of the URL, and with a <module> node instructing Magento where to look for controller classes. This route essentially says "when a URL begins with /sales, look for matching controller files in the Magento_Sales module." We'll look more closely at how the remaining URL segments are matched to a controller in a later lesson.

The key aspect of this route configuration to note here is the inclusion of both a frontName attribute and an id attribute. As mentioned, it is the frontName that is used to match the actual URL path of an actual request. The id attribute, on the other hand, is used to form the final name of the layout files matching a particular destination. If this same route file contained, say, this config:

<router id="standard">
    <route id="salesroutes" frontName="sales">
        <module name="Magento_Sales" />
    </route>
</router>

... then we would expect to find layout files named salesroutes_order_history.xml containing the layout affecting the /sales/order/history page. Fortunately, the id and frontName of virtually all routes in Magento are identical, so the URL segments themselves are more or less predictive of the relevant layout filenames.

Layout Update Handles

The string formed by a route ID and significant URL segments, such as sales_order_history, is what is called a layout update "handle." This type of handle - the one uniquely corresponding to a page - is the most common type of handle, but there are others.

The default handle is one that's applied to all pages. You can find default.xml files in the view/*/layout directory of many modules, and your own modules can include it when you want to inject layout instructions that are relevant to all pages. The version in the Magento_Theme module (vendor/magento/module-theme/view/frontend/layout/default.xml) contains the foundational layout components upon which all other layout is built.

When a controller renders a page, the layout system uses the default handle and the page-specific handle (like sales_order_history), then loads and merges all layout files with either of those filenames to form the final page layout structure.

Other layout handles can be applied as well, by controllers or by other layout files, to facilitate applying common layout elements to similar pages. Take, for example, the handle customer_account. The Magento_Customer module contains a file matching this handle (customer_account.xml), but the handle itself doesn't correspond with a particular URL. (customer_account_index does.) But if we look at some of the other layout files in the same module, we'll see this:

<update handle="customer_account"/>

This instructs the layout system to add the customer_account layout update handle to the list that is applied and loaded for the page. customer_account.xml contains layout instructions common to all "My Account" pages and avoids the need for repeating them in each unique layout file.

Finding the Product Page Handle

There's a reason we didn't start with the page our custom feature is actually concerned with - the product detail page - in our discussion of matching layout update handles to URL paths. Visit a product page on your site, and you'll notice the URL is something like /montana-wind-jacket.html or /zing-jump-rope.html. (At least, unless your store's configuration or the state of its data differs from ours.) Depending on your Store Config, the categories you used to navigate to the product might also be represented as URL segments, but nothing resembling a common "product detail page" URL path that we could have translated into a layout update handle.

To facilitate SEO-friendly URLs, Magento rewrites content-rich URL paths like the above to the "real" underlying paths that follow the usual frontname/segments pattern. You can crack open and examine the database table url_rewrite if you want to see this in action. When a product detail page is loaded, by the time Magento is resolving the route, the URL path being examined is /catalog/product/view.

Similar rewrite patterns are used to direct category pages to the path /catalog/category/view and CMS pages to the path /cms/page/view.

It's a perhaps frustrating amount of detective work to discover our ultimate goal - catalog_product_view.xml as the layout filename that affects the product detail page. But you'll deal with these layout update handles enough that you're unlikely to forget them!

Resources

Complete and Continue