In this post, I will summarise my experiences with Magento’s „new“ infinite theme inheritance feature. It is not really new any more, because it was introduced with Magento 1.9, which is available for quite some time now. But since I now had the possibility to have a closer look at it, I encountered two „hickups“ of this system, which I present in this post. Replace hickup with problem, bug, weird behaviour or whatever you like 🙂 There may be some solutions, too, so keep on reading!
- Hickup #1: No Automatic /default Fallback
- Solution for Hickup #1: Define the Fallback Manually
- Hickup #2: local.xml Can Be Overridden
- Workarounds for Hickup #2: How to Properly Customise a Parent Theme
If you are not yet familiar with the basics of the infinite theme inheritance feature, have a look at the following articles (best to be read in this order):
- Alan Storm explains how to use the new infinite theme inheritance: Magento Imagine 2014: Parent/Child Themes
- Eric Wiese from Classy Llama explains how the new infinite theme inheritance works internally: An In-Depth Look at Magento Theme Fallback
- Eric Wiese reveals the [problem|bug|feature] that layout files defined in a parent’s theme.xml are not automatically loaded in a child theme and offers a solution in the form of a nice module: Magento Infinite Theme Fallback Fix
- Alan Storm shows a quick fix to Wiese’s problem and explains the issue in more detail: Imagine 2014: Magento 1.9 Infinite Theme Fallback
Hickup #1: No Automatic /default Fallback
Apart from the default themes, we build a rwd/myparent and a rwd/mychild theme. As the name suggests, rwd/mychild defines rwd/myparent as its parent in mychild/etc/theme.xml:
<?xml version="1.0"?> <theme> <parent>rwd/myparent</parent> </theme>
Besides from this child’s theme.xml, there are no files in the themes.
Now we set rwd as the package and mychild as the theme in the Magento configuration:
I would expect that I see a normal rwd/default site now. Because rwd/mychild should fall back to rwd/myparent as defined and rwd/myparent should fall back to rwd/default via the normal fallback mechanism. But no, the site is kind of „broken“ (basically it just shows the base/default view where no CSS is defined), because the „normal“ fallback mechanism to rwd/default does not work:
Solution for Hickup #1: Define the Fallback Manually
The solution in this case is of course quite straight forward. You have to explicitely define the fallback to rwd/default in myparent/etc/theme.xml to make it work:
<?xml version="1.0"?> <theme> <parent>rwd/default</parent> </theme>
Not really dramatic, because we can easily fix the issue, but I think that is not how the Magento fallback system is supposed to work. As far as I know, the idea was always that Magento falls back to the default theme of the current package and then to the base/default package. I do not see any reason why this has been changed now.
Hickup #2 local.xml Can Be Overridden
Magento’s local.xml was for many years the best practice for theme development (and basically still is). Keep your layout XML customisations all in one place, do not override core layout files, be upgrade safe. Nice! The reason why this worked was that the local.xml of a theme was always loaded last. With the new infinite fallback system in place, I would expect that the local.xml of each theme in the fallback chain is loaded as a last layout file of this specific theme. But unfortunately, if you define a local.xml in your child theme, you will automatically override the local.xml of the parent theme. Hence, if our parent theme from above uses a local.xml for its customisations and we also want to use a local.xml in our child theme, we have to copy all the parent local.xml stuff into out child’s local.xml. This is not the way it should be. To verify, just add a local.xml to the parent theme from above with the following content:
<?xml version="1.0"?> <layout version="0.1.0"> <default> <remove name="header"/> </default> </layout>
Have a look at the site and you will see that the header is missing now:
Now add an empty local.xml to your child theme:
<?xml version="1.0"?> <layout version="0.1.0"> <!-- nothing to see here --> </layout>
Now you will see the header again since the local.xml of the child theme overrides the one from the parent theme:
Once again, I do not have any idea why it is implemented like that. This makes it quite hard to properly customise a parent theme in an upgrade-safe way. Is it a bug? Was it simply overlooked? Or is there any good reason to do it like that?
Workarounds for Hickup #2: How to Properly Customise a Parent Theme
There are two possible workarounds for this problem I can think of. They are not really solutions, because the first method is not upgrade-safe and the second does not work in all cases. So if you have any clean solution available, please share!
- We can of course simply override the local.xml of the parent theme and make our customisations in our child’s local.xml. Although this works, it is not upgrade-safe, because changes in the parent’s local.xml are not automatically reflected in the child’s local.xml. Pity.
- In the new theme.xml, you cannot only define the parent theme, but you can also define new layout files. An example how to do that is shown below. These layout files are loaded after all layout files of the parent. After all? Well, almost. Unfortunately, if we did not define a local.xml in our child theme and there is one in the parent theme, the parent’s local.xml will be loaded after our custom layout file. Hence, we are not able to properly customise the stuff from the parent’s local.xml. Pity.
We can have a layout file under mychild/layout/mychild/default.xml and define it in the theme.xml, so that it is loaded:
<?xml version="1.0"?> <theme> <parent>rwd/myparent</parent> <layout> <updates> <mychild_default> <file>mychild/default.xml</file> </mychild_default> </updates> </layout> </theme>
Still reading? Crazy you! For those of you who ask theirselves how I encountered all these things: If customers are small on budget, they often buy a theme and want it to be slightly customised. Since Magento 1.9, I always try to make these customisations in a new child theme which defines the bought theme as its parent. And in this case, you will quickly come across these issues. Additionally, you may encounter the problem that your child CSS is not rendered last, so that you cannot properly customise the CSS.
6 Gedanken zu „Magento 1.9 Infinite Theme Inheritance Hickups“
Wow, that’s fucked up. So basically we should avoid using local.xml at all and manually define one theme specific file in each theme.xml explicitely (parent and children)?
This means you will have to change bought themes which use local.xml but at least it’s just a rename, so it’s still kind of update safe…
This kind of solves the issue, yeah. But you would still have to define the layout XML files of the parent in your child theme, because layout XML files of the parent theme are not automatically loaded (see Eric Wiese’s issue and fix).
Does not seem to be a very elaborate feature…
Thanks for taking the time to offer your thoughts on this. I especially appreciated that you took time to curate some supporting articles. Hard to say whether it is a bug or a feature. Like several areas of Magento, we’ve learned to walk both around and with some of its architecture.
Regarding Wiese’s post, he is right to be thankful for the
core_layout_update_updates_get_afterevent. It’s an event-driven system that will enable us as developers to complain less about core functionality and to do something about it through injection.
Thanks for this! And also for the child CSS article. I will most likely copy the parent local.xml over to the child theme, leave it untouched though (and copy it with every parent theme update again) and put all changes in a new file defined in theme.xml. This is really annoying. And it really looks like it was implemented half assed. No wonder it doesn’t get much attention in the magento community.