Magento 2 Theme Setup¶
Prerequisites and Assumptions¶
- Magento 2.1 installation. See our tutorial here
- Basing from Luma theme
Relevant Technologies¶
Relevant Magento 2 Concepts¶
Creating Themes¶
When starting a new theme it is important to decide what your starting point should be. There are four options for extending themes:
Luma¶
Unless you intend to make massive changes you should always extend from the Luma theme. The Luma theme has a much better starting user experience over the Blank theme.
It is also important to note that Magento's automated acceptance tests are written with the Luma theme in mind. The tests are less likely to pass for themes that do not extend Luma meaning that the tests will need overriding to support them.
Blank¶
Extending from Blank is useful when you intend to create a completely new theme which is very different from Luma. Themes that completely change the layout or set out to make drastic changes should use Blank as a starting point.
Venia¶
This is the new PWA studio driven theme provided by Magento. At the time of writing it is still not marked as ready for production use. It is not advisable to use this theme unless you know what you are doing and are at least adept with Javascript and newer frontend technologies.
Third party themes¶
There are many third party themes available for Magento 2, many are rebuilt versions from Magento 1. Not all themes are made equal and you should be cautious when selecting a third party theme. Be sure to test the theme thoroughly in development mode so that any errors with the theme files are caught as early as possible.
Again, as with Blank, unless the theme developer has written test overrides the tests will need updating and will likely need a considerable amount of work to get passing.
New Theming Concepts in Magento 2¶
Module-specific theme files¶
In Magento 2 there is no longer a "base" package or "default" theme. Now, modules contain their own files within their view/(area)/(layout|template|web)
folders.
Here are a few examples:
Themes¶
Themes are a new standalone concept in Magento 2. These themes exist to create their own template, layout, CSS files as a self contained package.
Themes can also specify their own overrides to modules' theme files, rather than relying purely on file path matching.
Static content¶
Static resources such as CSS, images and JS files are no longer served from the theme folder itself.
Instead they're published to the pub
folder using either symlinks or copies.
Creating the theme structure¶
Folders¶
The first step is to create a new namespaced folder path in app/design/frontend
.
This would look like app/design/frontend/(Vendor_Name)/(ThemeName)
Magento 2 theme skeleton folders¶
- app/design/frontend/(Vendor_Name)/(ThemeName)
- (Module_Name)/ sets the theme's templates and layout for each module, such as Magento_Catalog
- Magento_Theme/ for module-agnostic templates and layout
- layout/ for layout XML files
- template/ for PHTML template files
- media/ contains a preview file
- web/ contains static content for delivering to the browser
- css/
- source/ - less files
- images/
- js/
- registration.php registers the theme
- theme.xml contains data about the theme such as the name and parent theme
Configuration¶
registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::THEME,
'frontend/EdmondsCommerce/ThemeTutorial',
__DIR__
);
theme.xml
This file specifies information about the theme, as used in Magento's admin
<theme xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/theme.xsd">
<title>Edmonds Commerce Theme Tutorial</title>
<parent>Magento/luma</parent>
<media>
<preview_image>media/preview.jpg</preview_image>
</media>
</theme>
Applying your theme¶
To apply a theme to your store, navigate to the Magento Admin's Design Configuration page:
- Log into the Magento Admin
- Click Content, and then under Design click Configuration
- Choose your website/store/store view level, and click Edit
- Set your Applied Theme
Theme Files¶
Folders¶
- A module's template files are contained in its
view/(area)/templates
folder - A theme's template files are contained in its
Magento_Theme/templates
folder
PHTML Templates Overview¶
Standard Magento templates are written as PHTML files. This involves a mixture of PHP and HTML, all with a focus on presenting the view-level content. This means business logic should be contained in the Block class and called using its public methods (more on accessing block methods below)
PHTML files look like
<a href="<?php echo $url ?>">
<?php echo $text ?>
</a>
if
, foreach
, while
etc control structures:
<?php foreach($array as $item): ?>
<span><?php echo $item ?>
<?php endforeach; ?>
<?php if($test === 'test'): ?>
<span><?php echo $test ?>
<?php endif; ?>
Accessing block methods¶
As part of the rendering process, Magento makes available a $block
variable which represents an object instatiation of the Block class. As with any other PHP object, you can call its public methods from within the template.
Note
This is a change from Magento 1, where the template was included within the class.
This meant that the template had access to the block class's protected and private methods using $this
Rendering child blocks¶
Inserting child blocks is pretty much the same as Magento 1:
1 |
|
Translations and Escaping¶
Translations can be implemented using the __()
method. Note that this is not a method call on an object:
1 |
|
Magento\Framework\View\ElementAbstractBlock
provides public stripTags()
and escapeHtml()
methods. These strip a string of HTML entities and tags respectively.
1 2 |
|
Further Reading¶
Layout¶
In Magento 2, layout XML works a little differently.
The most obvious difference is that each layout handle is its own XML file, so your theme's layout folder might look like this:
- Magento_Theme/
- layout/
- catalog_product_view.xml
- cms_index_index.xml
- default.xml //applies to all pages
XML Instructions¶
Layout XML in Magento 2 separates its instructions into four groups:
<head>
<body>
<html>
<update>
All but the last one correspond to the HTML elements that contain them. <update>
is simply a way to include another handle's instructions into the current file.
Magento 2 has a few instructions in Layout XML. Some will be familiar from Magento 1, others are new.
Head Layout Instructions¶
Title
Sets the page's title, as used in the window title bar and tab
<title>Page Title</title>
css
, script
, link
Adds CSS and Javascript resources to the page. The <link>
tag allows for both IE-conditional comments, and to
defer loading the script until the page has loaded
<css src="Namespace_Module::css/style.css" />
<script src="Namespace_Module::js/script.js" />
<link src="Namespace_Module::js/script.css" ie_condition="IE 9" defer="defer" />
meta
- Normal meta tags for the page, with key/value pairs
1 |
|
Body Layout Instructions¶
Full documentation on body layout instructions
Containers¶
Containers are a new concept in Magento 2. Containers are intended to represent a part of a page, rather than a block of content. They're not backed by a PHP Class, and can only create an HTML element.
Attributes can be assigned to the containers, and they can be sorted within their parents.
Examples of standard containers are the header, footer, left, right and content areas.
<container name="container.name" htmlTag="div" htmlClass="class" after="-">
<!-- Blocks and other containers injected here -->
</container>
Blocks¶
Blocks are used to add content to the page, and are backed by a PHP Block class. More on Blocks
<block class="Namespaced\Path\To\Block\Class" name="top.container.welcome"></block>
Move¶
<move>
instruction allows for a block to be moved from one block or container to another.
<move element="old.name" as="new.name" destination="destination.block.name" before="-" />
ReferenceContainer/ReferenceBlock¶
This allows for more content to be added into a block or container
<referenceContainer name="footer">
<!-- Inject more content in to the container -->
</referenceContainer>
<referenceBlock name="header">
<!-- Inject more content in to the block -->
</referenceBlock>
Block Types¶
There are many types of predefined Block in Magento 2, all contained within Magento\Framework\View\Element
namespace.
Magento\Framework\View\Element\Text
is used for displaying simple text on the page. Good for debugging your layout XMLMagento\Framework\View\Element\Text\ListText
is extended from Text, this is used to contain a sorted list of other blocks. Blocks added as children to this are automatically renderedMagento\Framework\View\Element\Messages
are their own block type in Magento 2. These represent the "success", "error" etc bannersMagento\Framework\View\Element\RedirectRedirect
perform a client-side redirect, if ever that's desirableTemplate
for loading a block with an included template. The template is set with thetemplate
attribute, e.g:template="Module_Name::path/to/template.phtml"
Block methods¶
Parameters can be called on Blocks' constructors, as well as their class methods.
To set constructor parameter values, argument
s can be added:
<arguments>
<argument name="logo_img_width" xsi:type="number">220</argument>
<argument name="logo_img_height" xsi:type="number">70</argument>
</arguments>
And class methods by specifying an action
:
<action method="methodName">
<argument name="methodArgumentName" xsi:type="text">value</argument>
<argument name="methodArgumentArray" xsi:type="array">
<item name="array_key" xsi:type="number">1337<item>
</argument>
</action>
Static content (CSS/Images/JS)¶
These files are stored in the theme's web
sub-folder, under their own css
, js
and images
sub-folders.
In Developer mode these files are read through symlinks created inside the pub folder. In production though they're published to the pub
folder using the bin/magento setup:static-content:deploy
command.
Images and CSS¶
A theme's images and CSS files are stored in the web/images
and web/css
folders respectively.
LESS¶
Magento 2 natively supports using CSS preprocessors, and uses Less CSS for its own Luna theme.
Storing Less files¶
Less files are contained within a modules web/css/source/ folder, with a naming convention that base files are
named as file.less
and files to be imported are named with an underscore prefix as _file.less
.
Importing other less files¶
Because normal Less @import
directives use paths relative to the include path, they're not aware of Magento's fallback system.
For this reason, other .less files should be included with //@magento_import file.less
- yes, with the //
comment.
This means the Less compiler will ignore it, allowing Magento to handle the fallback in its round of compilation.
Referencing images¶
Image URLs are relative to the web/css
folder, so image paths should be url('../images/path/to/image.jpg')
Compiling your Less¶
There are two ways to compile your less files:
- Using
grunt
commands:grunt exec
sets up symlinks from the files in pub/static to your module/theme's filesgrunt less
compiles your less to CSS, and then sets up the symlinks to thosegrunt watch
runs a file watcher to track changes to the less files, and compiles the CSS on the flygrunt clean
clears the symlinksgrunt refresh
clears then regenerates the symlinks, equivilant toclean
thenexec
- Some commands allow you to specify the theme e.g.
grunt less:theme
- Using
bin/magento setup:static-content:deploy
- Used in production
- Converts the
LESS
files toCSS
for the theme - Handles theme fallback and locales
Variables¶
Magento provides a set of helpful variables for use in the Less files:
@screen__*
variables for use in@media
queries@icon-*
` variables for a limited set of icons- Navigation variables to customise the category menus
Further Reading¶
JavaScript¶
Magento recommends including Javascript as part of templates rather than through layout XML to ensure they run as part of the body.
It makes use of RequireJS to pull in dependencies. These are run with the script tag with a Magento-specific type:
<script type="text/x-magento-init"></script>
Pulling in a Javascript assets¶
To pull in the module Magento_Configurable's js/configurable.js
file (which will exist in the pub
folder):
<script type="text/x-magento-init">
require(["Magento_ConfigurableProduct/js/configurable"], function(Configurable){
// your function body here
});
</script>
web
folder:
<script type="text/x-magento-init">
require(["js/customFile.js"], function(){
// your function body here
});
</script>
lib
folder are accessed by name:
<script type="text/x-magento-init">
require(["jquery"], function($){
// your function body here
});
</script>
jQuery Widgets¶
Not to be confused with UI Components, these extend from jQuery UI components and are useful widgets to use on the frontend. They include accordions, calendars, menus and tabs.
They can be initialised similar to the following in your template file:
<script>
require([
'jquery',
'tabs'], function ($) {
$("#footer-accordion").accordion();
});
</script>
Further Reading¶
Overriding modules' view files¶
In Magento 1, overriding other modules' assets was as simple as matching the file path in your own theme. In Magento 2, things are pretty similar, except you specify which module you want to override.
- In your theme (
app/design/frontend/(namespace)/(theme)
), create a folder matching theNameSpace_Module
you're overriding - Create a sub-folder for the type of file you're overriding:
templates
,layout
orweb
- Match the original module's file path, and add your content there
An example would look like:
- app/design/frontend/(namespace)/(theme)/
- Magento_Catalog/
- layout/
- catalog_product_view.xml
- templates/
- product/
- list.phtml
- view.phtml
Common Snippets¶
Templates¶
URL Generation¶
<a href="<?php echo $block->getUrl('path/to/page') ?>">Link</a>
Layout¶
New container¶
<container name="new_container" htmlClass="container_css_class" htmlTag="div">
<!-- blocks or containers here -->
</container>
New blank template¶
<block class="Magento\Framework\View\Element\Template"
template="Magento_Theme::path/to/template.phtml"
name="block_name" />
Removing sidebar items¶
<referenceBlock name="catalog.compare.sidebar" remove="true"/>
<referenceBlock name="view.addto.compare" remove="true" />
<referenceBlock name="category.product.addto.compare" remove="true" />
Removing My Account links¶
<referenceBlock name="customer-account-navigation-wish-list-link" remove="true"/>
<referenceBlock name="customer-account-navigation-billing-agreements-link" remove="true"/>
<referenceBlock name="customer-account-navigation-downloadable-products-link" remove="true"/>
<referenceBlock name="customer-account-navigation-newsletter-subscriptions-link" remove="true"/>
<referenceBlock name="customer-account-navigation-my-credit-cards-link" remove="true"/>
Admin Configuration¶
A few aspects of the theme can be user-configured through the Admin. This is found in Content > Design > Configuration > (store) > Edit
- Logo image and dimensions (now includes SVG)
- Title prefix and suffix as displayed in the tab/title bar
- Meta keywords/description as the default if the page doesn't specify its own
- Favicon image
- Welcome Text which is displayed for logged out users
- Miscellaneous HTML, scripts and CSS inserted before the closing
</body>
and</html>
tags
Image placeholders are configurable at Stores > Configuration > Catalog > Product Image Placeholders
Deployment¶
When deploying to the server, you should change from Developer mode to Production mode.
With this change in place, resources are served directly from the pub
folder rather than through symlinks or the static.php file.
To this end you need to ensure your resources are published.
This is accomplished using the bin/magento setup:static-content:deploy
command.
This will loop through the themes and modules to deploy their static files to the pub
folder.
Remember to set a locale if an Admin user uses a non-default locale, or else they'll have no CSS in their Admin:
bin/magento setup:static-content:deploy en_GB