Magento 2 has done a lot of work on themes including a improved inheritance structure. A lot of positive feedback has been received on the improvements. But that does not mean there is not even more potential to improve! So rather than have Magento resting on its laurels, I will like to describe a few remaining problem areas and possible solutions. Feedback and bright ideas welcome!
CMS Blocks and Inheritance
CMS blocks can be associated with a theme. If the theme is enabled on the store, the CMS block appears on the nominated pages. This is used by the Luma theme for example for home page content. It allows the Merchant to change the home page content (like the special of the day) without modifying the theme.
Magento 2 has added support for theme inheritance, where one theme can inherit from another theme. For example, a seasonal event theme (e.g. Christmas) can inherit from the main store theme, making only small tweaks (like putting some holiday images on the page). This inheritance approach greatly reduces the effort to set up and manage a theme and minor variants.
The issue some have encountered however is that themes inherit, CMS blocks do not. If you create a descendent of the Luma theme, the CMS blocks referenced by Luma do not appear on the page if the child theme is selected. You can fix this by going into the Admin panel and associating the CMS blocks with the parent theme and the child theme, but it’s a bit of an effort and easy to make a mistake. Is there a better solution?
- Add inheritance to the association of CMS blocks to themes. That is, instead of just saying “this CMS block should appear when theme X is selected”, change this to “this CMS block should appear when theme X or a descendant theme is selected”. Solves the inheritance problem, although a challenge is deciding if a child theme should be able to remove a CMS block from a page. If needed, that may add quite a bit of complexity.
- Alternatively, stick to the current approach for the Admin UI when associating CMS blocks with pages. Instead, add support for layout files to reference CMS blocks. Then the existing theme inheritance support will automatically kick in for CMS blocks as well. This might require a theme to be able to reference a block by name (currently only possible by id), with the ability to create the CMS block with default content if it does not exist. This automatic creation of CMS blocks makes it easier for a theme developer to sell a theme using CMS blocks – missing blocks are set up automatically when the theme is installed. For removing a CMS block in a child theme, layout files can be used – no new functionality is required.
I personally prefer the latter as it gives more power to theme developers who may want to sell a theme. It can create default blocks on the home page or other locations, with default text the merchant can customize for their site. Luma could then be converted to use this approach as well.
Themes and Extensions – Many to Many
Another problem is the many-to-many relationship between themes and extensions. By this I mean there are many extension developers out there who wish to develop new extensions. There are also theme developers who wish to develop turn-key themes. How to get them to work well together?
First, what is not a prolem?
- The Admin panel is not really an issue – there is not really a strong business driver to have multiple themes for the Admin UI. The issue is really for the consumer store front experience.
- Custom themes for a particular site, developed say by a solution partner, are not an issue. They know the exact theme and exact set of modules that will be present and so can make sure the theme works for the site.
The challenge is to allow a theme designer to develop a theme that is likely to work for a wide range of extensions, without the theme designer knowing what those extensions are.
What Themes can Change
First, it is worth reviewing what themes can change.
- Themes can replace PHTML template files, changing the HTML markup generated by a block. This seems too hard to allow a theme to replace HTML markup in an extension not known when the theme was designed. You need to know what the block is you are adjusting. I cannot see any silver bullet here. A theme can specify per module what PHTML files to override, even if the modules is not loaded. This means a theme developer can already get their PHTML overrides to work for a range of key modules they want to support. I cannot see scope for improvement here.
- Themes can apply layout changes. Generic layout changes related to a theme are more likely to be global page structure changes – e.g. moving the side bar to the other side, or the top of the page. Page structure (2 column, 3 column, etc) changes can already be done as extensions tend to inject themselves within the current page structure. Layout changes specific to a module can also be done if needed, just like PHTML files above. It feels like there is sufficient support here, so again, no real scope for improvement.
- CSS/Less file changes, to change the colors and styles of a site, is however a problem. A theme would like to change the overall coloring of a site to say a dark background with light colored fonts, without having to know what modules have been loaded. How to make these sorts of changes global? This is what the following discussion focusses on.
First, let’s look at a success. The Magento UI Library is a set of Less definitions that define the styles for generic concepts such as breadcrumbs, buttons, drop downs, forms, grids, messages, popups, ratings, tables, tooltips, and more. Modules can use the mixins (macros/functions) defined in the Magento UI library as required. Themes can adjust the mixins (e.g. the default colors to use). The mixins form a common agreement between themes and modules.
That is, rather than have each of many themes have dependencies on multiple specific modules (including third party extensions), themes adjust variables and mixins in the Magento UI library only. Then modules base all styling requirements on the Magento UI library. This turns a many-to-many relationship between themes and modules to a many-to-one relationship between themes and the Magento UI library plus a many-to-one relationship between modules and the Magento UI library. This makes it easier to add a new theme or extension.
A problem I fear (personal opinion here!) is the Magento UI library is not understood well enough yet. (This could in part be due to a lack of documentation.) If extension developers do not use the Magento UI library and its mixins/variables for new modules, if a theme only changes the Magento UI library won’t be change the styling for the new module.
The end result would be themes in the marketplace may be a good starting point for real sites, but you really need an expert to add support for the extra module.
So how to overcome this problem? A few early ideas:
- Make sure any modules that need new CSS at least try to build upon the Magento UI library rather than starting from scratch. That is, avoid using raw CSS – look at how the Magento UI library is put together and mimic it. Use the same Less variables as the Magento UI library as often as possible, so if a theme adjusts a Magento UI library variable it will also be applied to the module. Obviously this requires in depth understanding of the base Less files to achieve.
- As new styles are needed by new modules, try to work out how to merge into the Magento UI library. That is, create pull requests against Magento on GitHub to extend the Magento UI library.
- Come up with conventions around extending the UI library so new UI concepts can be built upon the current styles.
- It could be possible to make modules define CSS for specific themes (themes can already specify styling for specific modules). I dislike this approach however as modules are then only designed to work with particular themes, rather than be applicable for all themes.
My feeling is the best solution is to have new UI concepts merged into the Magento UI Library, or at least be built on the same variables as the Magento UI Library. This increases the chance that changing Magento UI library variable will automatically be picked up by the extension. This approach does require careful design of the Less source to make sure it is easily extended.
What Gives with Enterprise Edition Styles in Community Edition?
Without at least some of the above problems solved, it is hard to have a theme (such as Luma) that will work for CE and EE without change. (You can think of EE is like a whole set of extensions you get as a mega-bundle, all tested to work together.)
GitHub issue 2640 is a good example. The Luma theme includes styles for Rma (an Enterprise Edition only module), even if only CE is used. This is because theme inheritance cannot be used – CMS blocks will not work with a child theme. So the most expedient short term solution was to merge some Enterprise Edition CSS into Community Edition. This is not being promoted as a “best practice” at this stage.
The good thing about mixins is they only take up space in downloaded CSS files if used. If not used by a module, they add no contribution to the final CSS file.
Themes in Magento 2 are a significant step forwards from Magento 1 with a lot of positive external feedback. However there are still some problems: a theme developer cannot use CMS blocks and theme inheritance together very easily. Also better education and refinement of the Magento UI Library may be required around the correct usage of Less where themes can apply most changes via Less variables (and thus be applied to all modules leveraging the Magento UI Library).
The concepts in this post can be confusing, but hopefully the above is clear.
Disclaimer: This post does not necessarily represent the opinions of my employer.