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.

As promised, today we’re going to show you how to add javascript and CSS files to your Magento module without needing to worry about how their paths are rendered or how Magento serves them. While you may find this article useful on its own, we’re going to assume you’ve worked through the previoustwo.

Before we get to the main course, we’re going to provide an engineering critique of Magento 2’s XML based layout rendering language. This language is similar to the XML based language in Magento 1, but has some differences that might trip up an experienced Magento 1 developer.

The next few sections are optional, and not recommended unless you’re interested in the implementation details of Magento 2. You can skip ahead to the Adding CSS and Javascript to a Page section if all you’re interested in is getting your javascript and CSS files included on a page.

Magento 2’s Domain Specific Language for Rendering HTML

With Magento 2, the core team has added a number of features to their XML based layout language. They’ve also changed some of the language’s semantics. For example, in Magento 1, each node under the root node of a layout update XML file was always a layout handle. For example, in the Magento 1 Layout Update XML Node below, the handle is catalog_category_view.

Without getting too deeply into it, handles control which layout nodes are applied to a page during which request. Magento 2 still has handles, but they no longer appear in layout files. Instead, the handle is the file name. For example, the main catalog_category_view layout handle XML file is at

In all the examples, the file name is the handle name. While the mechanism has changed, handles still serve the same purpose in Magento 2. On every Magento 2 HTML page render, certain handles “fire”, similar to events. The handles that fire control which layout files are loaded (in Magento 1 they controlled which XML nodes were read from all the files), and then Magento processes the combined XML tree to know which blocks it should add to a page.

We covered this change briefly in our Introduction to Magento 2 — No More MVC article. However, we glossed over a number of substantial changes to Magento’s layout language that we’ll need to touch briefly on before we continue.

The <block/> tag from Magento 1 remains relatively unchanged. It means Create a block object. The main difference is the type attribute has been replaced with a class attribute. Since Magento did away with class aliases (core/template, namespace_module/my_block, etc.) it made sense to do away with the type attribute, and more accurately label it as class.

The first small change above is the referenceBlock node. Magento 1 had the concept of a block reference. However, the node was named <reference/>. In Magento 1, the above might look like

The referenceBlock node makes things more explicit, and is another welcome change. This might seem superficial, until you realize that Magento 2’s layout language controls more than blocks. The layout language also controls something called containers, and has a corresponding referenceContainer block. You can see an example of the referenceContainer block here

In Magento 2, a container is a special sort of block that only contains other blocks. Containers are conceptually similar to the text/list blocks in Magento 1, although their implementation is very different.

The concept of containers is a good one, but it’s here that the implementation starts to get a little wobbly. Magento’s layout language is a little loosey–goosey with the difference between a container and a block. For example, the above XML?

<referenceContainer name="root">

This could also be written as

<referenceBlock name="root">

That is — even though root is a container, referenceBlock will still return a reference to it, and allow you to add blocks to it. For a change meant to make things more explicit and clear, it’s a little strange that the layout language would let something like that happen.

We used referenceBlock in our introduction tutorial because we weren’t ready to discuss containers and other changes to the layout system. While this was useful for a transitional tutorial, generally speaking this is the sort of looseness that can make a domain specific language seem extra confusing.

Without getting too deeply into the details, you can tell if a “block” is a container or a regular block by how the original programmer created it. If you see a <block/> tag

<block name="foo" />

then the named block (“foo” above) is a regular block. If you see a <container/> tag

<container name="foo"/>

then the named entity is a container. If you’re curious, Magento’s core code adds the content container in the following file

Context Sensitive Nodes

In Magento 1, the layout language was a system designed to render arbitrary HTML via a nested collection of block objects. The layout system itself didn’t care which part of an HTML document it was rendering. It just rendered blocks. Specific blocks, like page/html_head, could introduce that context, but it happened at the block level. The layout system itself was unaware that it was rendering the <head/> portion of a document.

In Magento 2, the core team attempted to change this, and add that context in at the language level. They added two new top level tags named <body> and <head> to the vocabulary of the language. While it was an interesting experiment, the implementation feels half done, and further complicates an already complicated layout system. Consider the following

Here you can see an example of a core module layout handle XML file that uses the new head and body sections. The first bit of confusion this introduces is top level tags under the root tag now mean different things. In some files, these top level tags will be context tags like <head/> and <body/> above. In other files, the top level tags will be actual commands/directives (referenceBlock, container, etc) for the layout engine

If you enjoy implementing domain specific languages, this may seem like a minor thing. However, the intent of a domain specific language is to simplify and constrain the options for developers and programmers unfamiliar with the entire system. The lack of consistency here will make these files harder for designers and front end developers to understand.

The next bit of confusion is in what that context change means. Nodes placed inside the <body/> tag

behave very similar to plain old layout XML nodes. You’re still getting references to existing blocks and containers, and adding new blocks to them for rendering. The only difference is the <attribute/> tag you see above. With this you can change the ID element of the underlying <body/> tag.

Here, you’ve completely lost the ability to modify the layout with commands like referenceBlock, etc. Instead, you have a narrow set of tags (<attribute/>, <css/>, <link/>, <meta/>, <remove/>, <script/>, <title/>) for doing things specifically in the <head/> of a document.

The other bit of cognitive dissonance a Magento 1 developer will feel here is the <head/> section of the HTML page is no longer rendered like a normal block. If you take a look at the root phtml template you can see a Magento HTML page is no longer a series of nested blocks.

In Magento 2, an HTML page is a phtml template populated by simple variables. These simple variables are populated by different means in the render method of the Magento\Framework\View\Result\Page object. Magento creates the <body/> tag of the page by echoing out the $layoutContent variable. Magento gets the string for $layoutContent by doing the traditional kickoff of rendering a series of nested blocks.

How Magento populates of contents of these variable is beyond the scope of this article. The main change you’ll want to be aware of is that <head/> is no longer simply controlled by standard layout blocks.

Summary of Magento 2 Layout Changes

Magento 1’s layout system, while cryptic, was ultimately understandable by a single developer. Its why I wrote No Frills Magento Layout — the system wasn’t well documented, but once explained developers could understand and reason about it from top to bottom. It had a complex looking surface, but a simple elegant implementation.

As you can see from the above critique, Magento 2 has taken an already cryptic system, and added layers of complexity on top of it. These top levels of complexity are equally complex under the hood. Without getting into the details of it, Magento takes the layout handle XML files for a single request, merges them into a a single document, processes that document to transform it into a Magento 1 style page layout document, and then processes that document is way that similar, but not identical, to Magento 1.

Unlike Magento 1’s layout system, which an average developer could ultimately translate in their head into PHP code and reason about, the new rendering is too complex for most human beings to keep in their head at once. The new system is less understandable to the average developer. Perhaps this was necessary to implement the RequireJS and Less CSS systems the core team wanted to, but from the outside looking in it seems like a classic case of what people complain about when they complain about architect driven development.

Adding CSS and Javascript to a Page

Layout system critiqued, let’s get back to the practical business of adding a front end file to our Magento module. Before we begin, per pervious articles in this series, the following assumes

After running the above, you should be able to load the pulsestorm_javascriptcssexample frontname in your system.

http://magento.example.com/pulsestorm_javascriptcssexample

With the above completed, let’s get started!

The Layout Head Section

One of the new features Magento 2 introduces is context aware layout update XML files. By context aware we mean that end-programmer-users can add commands/directives to their layout XML files that only effect a particular section of the document. In plain english — layout update XML files now have a <head/> section where you can add head specific information about a file.

and reload the page, you’ll see that Magento has loaded them correctly into the system.

Adding Files Via PHP

In addition to using Magento 2’s layout XML system to automatically add front end asset URLs to your project, you can also create these URLs via PHP using a Magento\Framework\View\Asset\Repository object. We’ll show you how to do this below, as well as how to add arbitrary HTML to the <head/> of a Magento HTML page.

Starting with the later item, add the following node to our layout handle XML file

Creates a new Pulsestorm\JavascriptCssExample\Block\Head block named pulsestorm_javascriptcssexample_block_head that uses the head.phtml template.

Adds that new block to the head.additional block using the reference from #1

The head.additional block is a special block. Any block added to head.additional will automatically be output into the <head/> area of a Magento page. If you read our critique above, this is another bit of confusion added by the <head/> context. Even though our ultimate goal is to add something to <head/>, we need to operate inside the layout handle XML file’s <body/> tag.

Regardless, once we’ve got the layout XML in place, we’ll want to create our new Head block class

With the above in place, clear your Magento cache and reload your page. You should see the <!-- Hello There --> comment in your page’s <head/> node.

With a new template rendered in <head/>, we’re ready to render an asset URL using the asset repository.

The Asset Repository

The Magento\Framework\View\Asset\Repository object will allow us to create asset objects. Asset objects can convert a file identifier like foo/test.js or Pulsestorm_JavascriptCssExample::test.js into a full URL.

Like any object in Magento 2, when we want an instance of an object we don’t directly instantiate it — we inject it in another object’s constructor. Change your Head.php file so it matches the following

What we’ve done above is use Magento 2’s automatic constructor dependency injection to create a \Magento\Framework\View\Asset\Repository object, and assign it to the assetRepository property of our block object. The other parameters in __construct and the call to parent::__construct are there for compatibility with the base template block class. Also, notice we made assetRepository a public property. This means we’ll be able to access it in our phtml template.

With the above in place, clear your cache, delete the files in var/generate/* (because you changed an automatic constructor dependency injection constructor), and reload the page. If you view the raw HTML source, you should see a new <script/> tag rendered with a full asset URL.

What we’ve done above is use the createAsset method of the asset repository object to create an asset object. Then, we use the getUrl method of the asset object to fetch the HTTP url of the asset. All we need to know is the file identifier — Magento handles the grunt work of pulling together the correct URL path parameters.

Incorrect dependency in class

Update: Readers have reported that, in more modern versions of Magento 2, they end up getting the following error

If you’re using a version of Magento that doesn’t set an asset repository object on blocks, try $asset_repository = $this->_assetRepo; instead.

The reason this error occurs is the dependency injection compiler checks to make sure objects don’t have “double injections”. The Magento\Framework\View\Asset\Repository class is already injected in a base template class, and therefore our injection of it is redundant.

We regret the error.

Wrap Up

Today, after a long winded critique of Magento 2’s layout language, we demonstrated how to use that language to add front end CSS and Javascript assets to a Magento page. We also investigated directly using the underlying PHP asset repository that makes this possible.

In the past few articles, we’ve been entirely focused on getting “raw” front end asset files into our system. Next time we’ll start investigating how Magento has integrated with the new higher level front end abstractions like RequireJS and Less CSS.