Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento
front end book you'll ever need. Get your copy
today!

The new Magento parent/child infinite theme fallback system is the first time in years Magento’s added a new significant system to the framework code. As with any new system we need to reconcile our expectations vs. the actual behavior of the system. Put another way, we need to figure out how things work, what’s a bug, and what’s just intended-but-weird behavior.

This article is going to explore the root cause of some behavior discovered by Eric Wiese. The first half of the article we’ll be talking about code deep in Magento’s guts. If you don’t following along 100% don’t worry, there’s practical code samples starting at the Theme Based Layout XML Updates section.

File Fallback

Since the earliest days of Magento, the core/design_package model has handled the business logic for Magento’s theming system

The “business logic” here is how to resolve requests for a “design file” of a specific type (javascript, layout update XML, phtml template, etc) to a specific server file based on the currently configured package, theme, and any custom design settings at System -> Design.

Covering this implementation in its entirety would be a multiple article series. The the most important method, and the one we’ll look at, is getFilename

This method is the heart of the class, and all requests for design files run through it. The new infinite theme fallback system takes advantage of this. Since there’s a central method that handles giving out file names, it’s relatively easy to inject custom logic that implements a parent/child theme system.

In previous versions of Magento, this method used the _fallback method to reconcile a specific file path.

This new core/design_fallback object contains the logic that will detect a parent theme, and create a proper fallback scheme so the parent theme is referenced when looking for a file. Also of interest, the new core/design_config object is responsible for reading and parsing the theme.xml.

What’s a fallback scheme? It’s a list of package/theme names to check for a file. For example, let’s say I have a theme named pulsestorm/a that extends a theme pulsestorm/default. The pulsestorm/default theme, in turn, extends the rwd/default theme. In this case, my fallback scheme would look like this

The first item, an empty array, signals to 1.9’s _fallback method that it should look for the file in the current design package/theme (pulsestorm/a), the second array tells the system to look in pulsestorm/default, and the last tells the system to look in rwd/default.

The specifics are worth investigating on your own, but the broad takeaway here is the core/design_fallback object looks at the theme.xml file (via the core/design_config object), and comes up with a list of themes to look for design related files in. The current Magento team leveraged the original Magento teams’s “over engineering” to drop in a theme inheritance system. This ensures every design file is subject to infinite theme inheritance.

Theme Specific Layout Files

Eric’s a developer at Classy Llama, the company (along with Falkowski and — others? Let me know in the comments) responsible for the new responsive web design theme. While the Llamas didn’t build the theme fallback system, they were some of the first developers to use it. Eric’s article requires you understand all the features of theme.xml, so let’s start there.

The structure is similar to adding a layout update XML file via a module’s config.xml file. Your new files go under the layout/updates node. The child node <my_new_file_name/> needs to be unique but is not used for anything semantically, and the file name itself (my_new_file_name.xml) refers to files in your theme’s layout/ folder.

This is a huge win for theme designers. Prior to this the only way to add layout XML to the system was via local.xml, or by adding a new code module. The local.xml file quickly gets clogged up with customizations, and these updates are not easily distributable. Putting your updates into a module can alleviate these problems, but with the the added complexity of having a module and having to deal with the complications arising out of when your updates run vs. updates from other modules.

Having layout update XML files in theme.xml solves all this. Theme developers can specify which files their themes use in the theme itself, and Magento processes theme.xmlafter module configured layout update XML files but before local.xml.

There is, however, one catch to be aware of. This brings us to Eric’s article.

No Inheritance in Themes

The short version: Layout update files in theme.xml are ignored by Magento’s new inheritance system. When Magento examines the configuration for layout update xml files, it does so here.

As you can see, Magento directly queries the core/design_config object for the new layout update XML file names — it does nothing to resolve the theme inheritance chain. This means if you have a theme hierarchy like this

'pulsestorm/a` extends
`pulsestorm/default`
extends 'rwd/default`

then layout update XML configured in pulsestorm/default will be ignored when the theme is set to pulsestorm/a. As we learned earlier, the inheritance system works because every time you request a file, Magento references a fallback scheme to determine where the file should be loaded from. Since the layout update loading code never looks at information in other themes, it never sees the other files, and never has the chance to ask the fallback system where these files are located.

We’ve been talking theoretical concepts for a while now. Next we’re going to get concrete with some code that should make this a lot clearer. If you’re running into trouble with the examples below, the final theme code is located in this GitHub repository.

Theme Based Layout XML Updates

To start with, we’ll create a pulsestorm/default theme by creating the following folder structure/file

This is a pretty standard layout update XML file. We’re hooking into the cms_index_index handle (i.e. when the home page loads), getting a reference to the content block, and adding a new text block to it. What’s different is our next step. We’re going to add a layout/update node to our theme.xml file instead of a new module’s config.xml file.

To enable this theme all we’ll need to do is set the design package to pulsestorm and the theme name to a.

Now, if we clear our cache and reload the homepage, we’ll see our theme correctly displays the responsive design theme (picking up on the fact that pulsestorm/a‘s parent (pulsestorm/default) is a child of rwd/default).

However, there’s something odd going on with the Layout XML files. We’ve correctly inherited the cms.xml file from pulsestorm/default — we can tell because there’s no Home Page title. However, we have not inherited either hello.xml or goodbye.xml.

This is the problem Eric describes in his article — not that infinite fallback ignores all layout xml files, but that it ignores layout xml files configured via theme.xml.

Reasons and Solutions

Eric describes this as a failure of the infinite inheritance system — while he doesn’t use the word it’s clear he sees it as a bug, and like any good developer he created a great module to make the system behave more to his expectations.

When I look at this behavior, I’m not sure if it’s a bug, a deliberate design decision, or an unthought through consequence of a deliberate design decision.

If Magento was the product of one mind I’d say it was a deliberate choice to have the inheritance system ignore theme.xml layout files. If you want a layout file available to all parent and child themes, use a module. If you want it only available to your specific theme, use theme.xml. In this version of the world theme.xml becomes a way to organize updates that normally go into local.xml.

However, Magento’s not the product of one mind. It’s the product of executives directing product managers directing project managers/producers who direct the developers who implement features with the community throwing its weight behind certain things. Maybe this one line

was a deliberate decision to ignore other themes. Or maybe the engineers came up with the fallback solution to the theme problem, and didn’t think through how the layout update loading would work. Or maybe they did think it through and the new implementation details were too nuanced to complete in their given schedule so they went with the simpler solution.

Regardless, if this is a bug I’d expect to see it addressed in a future point release. In the meantime, if you want your 2nd and 3rd level child themes to use their parent’s layout update XML files, you have two choices. The first? Install Eric’s module and themes will inherit their parent’s theme.xml layout update files.

The other solution? Just configure your child’s theme.xml layout file to include the other layout update XML files. For example, if we wanted pulsestorm/a to have the hello.xml file, we’d create a theme.xml that looks like this

Clear you cache, reload the homepage, and you’ll see your Hello World message

Notice we didn’t move hello.xml into our theme, all we did was tell our theme about the file via theme.xml, and the fallback system found it in pulsestorm/default. So, from this point of view, it’s not that the fallback system fails to inherit files from theme.xml — it’s that it gives you full control over which layout update XML files get pulled in.

Wrap Up

I’ll be the first to admit this may be spinning a bug as a feature. At the same time I’ve met enough engineering folks to know this may be the intent of the system. The larger lesson here is modern software systems are complex — more complex than any one human can understand, and as humans we’re going to bring our own points of view to table. Being able to clearly and honestly communicate during a software project is hugely important, both in implementing the correct features and understanding intended system behavior.

If you can nurture the talent of adopting multiple points of view throughout your career, you’ll find not only will it help you deal with the people you meet along the way — but it will also help you better understand the systems you’ll be working with and building.