Magento 2(M2) is vastly different in its structure than Magento 1.x. When you first crack the surface of this new platform, it can seem a little daunting. You might be asking yourself “Where do I start?”, at least I did. Once you dive into M2 you will see, not only how much more organized the file structure is, but also the improvement in ability to override content/layout XML and extend JS without having to load all its dependencies. Some other improvements include the addition of HTML5 tags built into the templates, the intro of CSS3, and the use of LESS over Sass (as well as a built-in LESS preprocessor). Notably, M2 has also switched from Prototype to a jQuery library. If you have ever worked with prototype before, this is a welcomed change!

With all that being said, there are not too many resources out there for us Frontend Dev’s. I have mostly relied on the Magento 2 development docs and trial and error. My goal here is to create a well explained process of theming in Magento 2. This will be a 3 part blog series to guide you through setting up your M2 install, creating a child theme, and customizing it (and I mean really customizing it).

Installing Magento 2

As you may be aware, there are a few different ways to install Magento 2. Please refer to the Magento installation guide first if this is your first M2 install. It is also very important to check whether your server meets the minimal Magento 2 requirements:

  • Apache: 2.2 or 2.4
  • PHP: 5.5.x or 5.6.x
  • MySQL: 5.6.x

 

I suggest using composer when installing Magento 2. Composer enables you to manage the Magento components and their dependencies. Here are some resources to walk you through your install:

Theme structure

There are number of differences and improvements to theme structure and the fallback system in Magento 2. The fallback system in M2 works in a similar way to Magento 1.x, but now has the added advantage of being able to create unlimited parent themes. In this tutorial, we will be creating a new theme based on M2’s ‘Blank’ theme.

M2 fallback system explained

In M2, the fallback system is defined by the theme.xml file. It tells your theme which parent to fallback on. The great thing in M2 is we can declare our own fallback system within our themes.

Magento 2 has a different folder naming convention for themes than Magento 1. In Magento 1, you would create your theme within app/design/frontend/<package>/<theme>. For Magento 2, you create your theme in app/design/frontend/<vendor>/<theme>. Lets take a closer look at the pieces of the new naming convention, and therefore how you should chose your folder names:

Vendor: This is the name of the individual or company developing the code for this theme.

Theme: This can be any name that you would like to call your theme.

app/design/frontend/
├── Mycompany/
│   │   ├──...default/
│   │   │   ├── ...
│   │   │   ├── ...

Above, indicates a new vendor folder with theme ‘default’.  This is based off M2’s ‘Blank’ theme. There can be multiple themes and store views under one vendor. I chose default as the base theme so when we create multiple store views the global assets for the stores will remain here. 

app/design/frontend/
├── Mycompany/
│   │   ├──...default/
│   │   │   ├── ...
│   │   │   ├── ...
├── Myothercompany/
│   │   ├──...store/
│   │   │   ├── ...

Above, indicates a new vendor folder, ‘Myothercompany’,  using ‘Mycompany’ as its parent theme. In this theme you can override global assets from ‘Mycompany/default’, otherwise they will fallback in hierarchy respectively. 

In Magento 1.x, the last place Magento would look in it’s fallback system is base/default. In M2, base/default is the module. Modules are now all encapsulated. This means, instead of having all your site wide assets, js, templates, blocks and controllers in different locations, they are now organized within the module. The location of the default versions of each module can be found in app/code/Magento. The folders in the image below represent the default modules in Magento 2.

app-code-magento

Now, let’s take a look at the structure of one of a default modules. In this case we are looking at the layered navigation module:

layered-nav-module-m2

Here, you see that the template and layout xml files now exist in view/frontend of the module. If you want to override/extend the modules’ templates, styling or JS, you will need to create an equivalent module folder in your theme that matches the path(s) of the file(s) you wish to override/extend. If we were extending the layered navigation module, you would create a folder named Magento_LayeredNavigation and place it in your theme folder eg. <vendor>/<theme>/Magento_LayeredNavigation.

Magento_LayeredNavigation is an example of a <Namespace_Module>. Magento being the namespace and the module being LayeredNavigation separated by an underscore. If you were extending the checkout module, it would be Magento_Checkout. The process of extending <Namespace_Module>(s) will be covered in detail later in this blog series.

*Note that you can only override the contents of the view/frontend portion of the module within your theme. If you need to override Controllers and Blocks, this is done in a different location in the file structure and will not be covered in this blog series.

Creating a New Magento theme

Creating theme.xml to declare fallback system

  • Navigate to app/design/frontend
  • Create a new vendor folder in app/design/frontend/ and name it ‘Mycompany’ eg.  app/design/frontend/Mycompany
  • Create a theme folder in within your new vendor folder named ‘default’ eg. app/design/frontend/MyCompany/default

 

This is what your theme structure should resemble:

app/design/frontend/
├── Mycompany/
│   │   ├──...default/
│   │   │   ├── ...
│   │   │   ├── ...

Next, create a theme.xml file in this directory. Copy it directly from app/design/frontend/Magento/blank/theme.xml. We are now going to declare our theme, ‘Mycompany’ and choose the appropriate parent. In this case, we are choosing /Magento/blank.

Your theme.xml should look like this:

<theme xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:noNamespaceSchemaLocation=”../../../../lib/internal/
Magento/Framework/Config/etc/theme.xsd”>
 <title>Mycompany Default</title>
 <parent>Magento/blank</parent>
</theme

and should be in this location app/design/frontend/Mycompany/default/theme.xml

Make your theme a Composer package (optional)

Magento default themes are distributed as Composer packages.

To distribute your theme as a package, add a composer.json file to your theme directory and register the package on a packaging server. A default public packaging server is https://packagist.org/.

composer.json provides theme dependency information.

In our case, copy the composer.json file to the theme directory app/design/frontend/Mycompany/default and edit the orange text as follow:

{
    "name": "magento/theme-frontend-default",
    "description": "N/A",
    "require": {
        "php": "~5.5.0|~5.6.0|~7.0.0",
        "magento/theme-frontend-blank": "100.0.*",
        "magento/framework": "100.0.*",
        "magento/magento-composer-installer": "*"
    },
    "type": "magento2-theme",
    "version": "100.0.1",
    "license": [
        "OSL-3.0",
        "AFL-3.0"
    ],
    "autoload": {
        "files": [
            "registration.php"
        ]
    },
    "extra": {
        "map": [
            [
                "*",
                "frontend/Mycompany/default"
            ]
        ]
    }
}

You can find details about the Composer integration in the Magento system here.

Registering our theme

The next step is to register our theme. In your theme directory add a registration.php file. I suggest copying the file from app/design/frontend/Magento/blank/registration.php and editing. Your file should look like this:

<?php
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::THEME,
    'frontend/Mycompany/default',
    __DIR__
);

Next, we will create _theme.less and folder structure where we will extend/override our theme LESS files. Create app\design\frontend\<Vendor>\<theme>\web\css\source\_theme.less. In this case our _theme.less will be in app\design\frontend\Mytheme\default\web\css\source\_theme.less

Installing and configuring Grunt

Magento has built-in Grunt tasks configured, but there are still several prerequisite steps you need to take to be able to use it. Make sure that you set your Magento application to developer in your .htaccess.

SetEnv MAGE_MODE developer

You’ll be running Magento in developer mode. In developer mode, Magento’s much more strict about PHP errors, will display raw exceptions, and make it easier to develop modules.

Next, install node.js to globally on your machine.

Install Grunt CLI tool globally. To do this, run the following in a command line:

npm install -g grunt-cli

Install (or refresh) the node.js project dependency, including Grunt, for your Magento instance. To do this, run the following in a command line:

cd <your_Magento_instance_directory>
npm install
npm update

Add your theme to Grunt configuration. To do this, in the dev/tools/grunt/configs/themes.js file, add your theme to module.exports as follows:

module.exports = {
    ...
    <theme>: {
        area: 'frontend',
        name: '<Vendor>/<theme>',
        locale: '<language>', 
        files: [
            '<path_to_file1>', //path to root source file
            '<path_to_file2>'
        ],
        dsl: 'less'
    ...
    },

(Optional) If you want to use Grunt for “watching” changes automatically, without reloading pages in a browser each time, install the LiveReload extension in your browser.

Next, we need to clean static files and caches. In command line run:

Create directories for static files

Next we will create directories to store the static files: styles, fonts, JavaScript and images. Each type should be stored in a separate sub-directory of web in your theme folder:

app/design/frontend/Mycompany/default/
├── web/
│ ├── css/
│ │ ├── source/ 
│ ├── fonts/
│ ├── images/
│ ├── js/

In the .../web/images  general theme related static files are stored. For example, a theme logo is stored in .../web/images. It is likely that your theme will also contain module-specific files, which are stored in the corresponding sub-directories, like .../<Namespace_Module>/web/css and similar.

Declaring theme logo

To declare a theme logo, add an extending default.xml to /Mycompany/de/Magento_Theme/layout/default.xml.

For example, if your logo file is my_logo.png sized 300x300px, you need to declare it as follows:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="logo">
            <arguments>
                <argument name="logo_file" xsi:type="string">images/my_logo.png</argument>
                <argument name="logo_img_width" xsi:type="number">300</argument> 
                <argument name="logo_img_height" xsi:type="number">300</argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Declaring the logo size is optional.

Your theme directory structure 

At this point your theme file structure looks as follows:

app/design/frontend/Mycompany/
├── default/
│   ├── etc/
│   │   ├── view.xml
│   ├── web/
│   │   ├── images/
│   │   │   ├── logo.svg
│   │   ├── css/
│   │   │   ├── source/
│   │   │   │   ├── _theme.less
│   │   ├── fonts/
│   │   ├── js/
│   ├── registration.php
│   ├── theme.xml
│   ├── composer.json

Apply your theme

Now we are ready to apply our theme to a store. Login to your magento admin and apply theme as follows:

In Admin, go to CONTENT > Design > Configuration. A Design Configuration page opens. It contains a grid with the available configuration scopes.

Design Configuration page

In the configuration record corresponding to your store view, click Edit.

On the Default Theme tab, in the Applied Theme drop-down, select your newly created theme.

Click Save.

Clear the cache.

To see your changes applied, reload the store front pages.

Now we have set up our theme and are ready to start customizing it!

What’s Next?

The next part of this blog series will cover extending, overriding and customizing our theme via <Namespace_Module>(s) and xml.