If you’re trying to develop for Joomla and need to know how the Web Asset Manager works, this guide is for you.
The Web Asset Manager is a newer system for organizing file dependencies and loading web assets in Joomla. In a nutshell, we define all of our extension’s scripts and styles in a Json file called “joomla.asset.json” and then call the WebAssetManager’s functions with simple PHP to load the styles and scripts defined within the Json file.
Using the WebAssetManager instead of just manually loading scripts and styles via a script/link element is important. It will help keep your files organized and ensure that the same dependencies are not loaded multiple times.
For example, if an extension asks for a stylesheet or script the template already loaded, we won’t be attempting to load the same file multiple times and waste space in the html document (provided the dependency is named properly).
The Basics
Assets refer to the JavaScript and CSS files a Joomla extension needs to operate. Bootstrap, FontAwesome, your template’s stylesheet, custom scripts, etc. are all examples of assets we should load with Joomla’s WebAssetManager.
The asset definitions are stored in a Json file called joomla.asset.json which should be placed in the root folder of a template or the corresponding media folder of an extension.
For example, if you are using it in a template, you would place the file at:
site_root/templates/your_template_name/joomla.asset.json
If you were creating a content plugin, you’d place it at:
site_root/media/plg_content_yourplugin/joomla.asset.json
Structure of joomla.asset.json
To allow your template or extensions to use a specified asset on the website, we must first add it to the .json file, register the asset file with the WebAssetManager, and finally use the WebAssetManager to call the asset by the name we assigned.
Let’s begin by examining the joomla.asset.json file for a template.
Add/Use Asset for Template
I am using my template, j4starter, for this example.
With templates, you should create joomla.asset.json (if you don’t already have it) in the template’s root directory.
For my template j4starter, this is at:
site_root/templates/j4starter/joomla.asset.json
This file should also be defined under the files section of templateDetails.xml. You should read up on template development if you’re not familiar.
Now let’s examine the structure of the joomla.asset.json file.
If you’re not familiar with json files, they’re basically a structured way to define and share objects or information. Kind of like xml files. Json files may follow a specific schema, defined by the application developer (Joomla/OSM in this case). The schema tells us how to structure the information in the json file (the names, data types, and values we must provide).
Thankfully, defining assets in joomla.asset.json is fairly easy. Just open up your favorite code editor and start defining files according to the schema. Let’s see what the template’s json file looks like.
Note that I’ve removed a few of the assets not needed to fully explain this concept.
Sample joomla.asset.json file:
{
"$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
"name": "j4starter",
"version": "4.0.0",
"description": "This file contains assets used by j4starter",
"license": "GPL-2.0-or-later",
"assets": [
{
"name": "template.j4starter.mainstyles",
"description": "The default css style to use.",
"type": "style",
"uri": "template.min.css",
"dependencies": [
"fontawesome"
]
},
{
"name": "template.j4starter.user",
"description": "The User.css file",
"type": "style",
"uri": "user.css"
},
{
"name": "template.j4starter.scripts",
"description": "the javascript for this template.",
"type": "script",
"uri": "template.js",
"attributes" : {
"defer": true
},
"dependencies": [
"core"
]
},
{
"name": "template.active",
"description": "allows extensions to use it as a dependency to the active template.",
"type": "script",
"uri": "",
"dependencies": [
"template.j4starter.scripts"
]
},
{
"name": "fontawesome",
"type": "style",
"uri": "system/joomla-fontawesome.min.css"
}
]
}
Code language: JSON / JSON with Comments (json)
The syntax is to enclose each section with curly brackets {}. The first few lines define the schema, the name of the template, the version, description, and license.
The name, version, description, and assets are necessary. The license field is optional.
You should use the same name as your template for the name, the template alias/slug (same name you used as the template folder name with no spaces).
The assets section is an array of additional objects. Each object in this array (separated by a comma) defines an individual asset.
Each asset needs a minimum of a name and a type. You’ll want a uri too, to define the location of the asset you want to be loaded.
Here is a description of each field and its importance:
- “name”: the internal name of this asset
- may have periods, all lower case, should not have spaces
- “type”: the file type
- should usually be “script” if a js file or “style” if a css file
- the type “preset” is also an option, which may contain a list of assets
- “uri”: the file location and name
- This is usually relative to the media folder
- You can also use full external or absolute links (to a CDN, for example)
- If you don’t specify a folder, it will load from the respective css or js folder under
- media/templates/site/your_active_template/css
- media/template/site/your_active_template/js
- “dependencies”:
- This is an array containing other asset names this asset depends on
- For example, the first asset “mainstyles” has “fontawesome” as a dependency, this means it will load the uri defined in “mainstyles” along with the uri defined at the bottom under “fontawesome”
- You may list as many or as few dependencies as you would like
- If multiple assets have the same dependency, the dependency will only be loaded once
- “attributes”:
- Additional attributes to add to the link when loading the asset on the page, such as the defer option
Example: Adding Style & Script to Template
Suppose you want to add “mystyle.css” and “myscript.js” to every page on your website, by modifying the template’s joomla.asset.json file and the template’s index.php. Let’s see what that would look like.
First, where do you put mystyle.css and myscript.js?
The correct answer is under the respective directory in the template media folder.
- mystyle.css would be placed at site_root/media/templates/site/templatename/css/mystyle.css
- myscript.js would be placed at site_root/media/templates/site/templatename/js/myscript.js
Next, you would open joomla.asset.json and add these assets to the assets array. Remember to separate each asset in the array with a comma.
I have decided to name my assets “mystyle” and “myscript” for demonstration.
This is what the new assets look like when added to the json file:
{
"name": "mystyle",
"type": "style",
"uri": "mystyle.css"
},
{
"name": "myscript",
"type": "script",
"uri": "myscript.js"
}
Code language: JSON / JSON with Comments (json)
Now the assets are in the file, but I still have done nothing with them.
We have two options to load these assets onto the page.
Loading with PHP
First, we can open index.php for our template and tell the WebAssetManager to load the script and style.
If you’re using j4starter, we already loaded Joomla’s WebAssetManager near the top of index.php
$wa = $this->getWebAssetManager();
Code language: PHP (php)
The variable $wa represents the WebAssetManager. So now we can use the asset manager’s functions in our code.
The useScript(name) function loads a script, and the useStyle(name) function loads a style from the json file.
Since I unoriginally named my assets “myscript” and “mystyle” – these are the arguments I’ll pass to the functions.
$wa->useScript('myscript');
$wa->useStyle('mystyle');
Code language: PHP (php)
You can put that code anywhere you want within the PHP document. However, it’s probably best to place it near the top, after you load $wa, or wherever the other scripts/styles are being loaded.
Test it out by refreshing the website and see if it loaded the files properly using dev tools. If you’re in Chrome or Edge, open dev tools and go to the “Sources” tab. I find this is the quickest way to see what gets loaded.
Loading With Dependencies
The next option is to load the assets as dependencies of other assets. This still ultimately means using PHP, but if you’re using an existing template, chances are that a script and style asset were already loaded from joomla.asset.json. This means we can add mystyle and myscript as dependencies of the items which were already loaded.
In the case of j4starter, I already load scripts and styles using the following PHP:
$wa->useStyle('template.j4starter.mainstyles');
$wa->useScript('template.j4starter.scripts');
Code language: PHP (php)
So I can make “mystyle” a dependency of “template.j4starter.mainstyles” and “myscript” a dependency of “template.j4starter.scripts” by defining this in the json file.
Now, I’ve removed $wa->useScript('myscript');
and $wa->useStyle('mystyle');
from my template’s index.php file.
Open joomla.asset.json again, and add the dependencies to scripts and mainstyles (or whatever existing script/style names you have there).
Note that scripts must only have scripts as dependencies and styles can only have style dependencies. You cannot mix them.
joomla.asset.json
{
"name": "template.j4starter.mainstyles",
"description": "The default css style to use.",
"type": "style",
"uri": "template.min.css",
"dependencies": [
"fontawesome",
"mystyle"
]
},
{
"name": "template.j4starter.scripts",
"description": "the javascript for this template.",
"type": "script",
"uri": "template.js",
"attributes" : {
"defer": true
},
"dependencies": [
"core",
"myscript"
]
},
Code language: JSON / JSON with Comments (json)
I’ve added the dependencies to the scripts and styles I already loaded from index.php. Now, it will load “mystyle.css” and “myscript.js” just as it did before – but as dependencies of these other assets rather than individually from the php using useStyle and useScript.
If you’re curious what the “core” dependency is from the scripts, this loads the file media/system/js/core.min.js
The core.js file contains assorted functions fundamental to Joomla’s standard operations. It helps with bootstrap functions, forms, editors, and more. The core asset itself is declared in a separate joomla.asset.json file located under media/system/joomla.asset.json. You should probably just leave the core stuff alone.
Other Ways To Load URIs
There are actually a few ways you can provide a URI to Joomla with joomla.asset.json. I briefly mentioned this earlier, but it bears repeating.
For templates, you can just provide the filename itself, and it will load the resource from the respective js or css folder under media/templates/site/template…
All other resources are loaded relative to the media folder itself, or as an absolute link.
From Media Folder
I’m going to change the “mystyle” asset I created earlier. This time, I’ll provide the URI relative to the site root.
{
"name": "mystyle",
"type": "style",
"uri": "media/templates/site/j4starter/css/mystyle.css"
},
Code language: JSON / JSON with Comments (json)
If I reload the site, that works.
The schema says it loads files relative to the media folder, while omitting the “css” or “js” part. So by that logic, you would expect this to work too, but it does not…
"uri": "templates/site/j4starter/mystyle.css",
Code language: JSON / JSON with Comments (json)
For reference, the fontawesome dependency looks like this:
"uri": "system/joomla-fontawesome.min.css"
Code language: JSON / JSON with Comments (json)
That file is actually at: media/system/css/joomla-fontawesome.min.css
So templates appear to be an exception to this convention, since it automatically loads the files from the template’s js or css folder just by specifying the filename itself. If you want to load a template asset with the full url, you must provide the full directory relative to the site root, not the media folder.
Finally, you can load files with their full web address, such as a css or js file from a CDN.
In this example, I load bootstrap5 from a CDN.
{
"name": "bootstrap5",
"type": "style",
"uri": "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
}
Code language: JSON / JSON with Comments (json)
Loading Assets from Extensions
There are a few differences if you want to use a joomla.asset.json file to load assets with a non-template extension. Some functions and requirements are slightly different.
First, Joomla expects joomla.asset.json to be in the template’s root folder by default. This is different for extensions. First, Joomla does not know if you’re even using additional assets, so it doesn’t look for joomla.asset.json – you must tell it where to find it.
The convention is to place the asset file for your extension at media/extensiontype_shortname/joomla.asset.json
For example, I used the alias “contentplugdemo” for my content plugin demo. So this is the same name I’ll use internally. For this plugin, I would place the asset json file at media/plg_content_contentplugdemo/joomla.asset.json
If you were doing this for a component, it’d go under media/com_mycomponent, for a module under media/mod_mymodule and so on.
You’re supposed to use the “css” and “js” folder under the respective extension’s media folder to store the assets. Do not use alternative folder names.
Example: Loading Asset From Content Plugin
I’m going to attempt to load “pluginstyle.css” from “media/plg_content_contentplugdemo/css” using the WebAssetManager and a joomla.asset.json file saved under “media/plg_content_contentplugdemo”
I’ll begin by creating the directories as necessary, and placing my CSS file in the media/plg…/css folder.
Next, I’ll create a new joomla.asset.json file, give it a name and a description, and add my CSS asset to it.
joomla.asset.json:
{
"$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
"name": "plg_content_contentplugdemo",
"version": "4.0.0",
"description": "assets used by my demo plugin",
"license": "GPL-2.0-or-later",
"assets": [
{
"name": "plg.content.contentplugdemo.styles",
"description": "a test css file",
"type": "style",
"uri": "plg_content_contentplugdemo/pluginstyle.css"
}
]
}
Code language: JSON / JSON with Comments (json)
This time, the uri is relative to the media folder, excluding the “css” folder. "uri": "plg_content_contentplugdemo/pluginstyle.css"
will in fact load the file at site_root/media/plg_content_contentplugdemo/css/pluginstyle.css
Now I have to load the style from my plugin’s main php file located under site_root/plugins/content/contentplugdemo
I’ll add this code near the top of the file.
$doc = Factory::getApplication()->getDocument();
$wa = $doc->getWebAssetManager();
$wa->getRegistry()->addExtensionRegistryFile('plg_content_contentplugdemo');
Code language: PHP (php)
I used the same getWebAssetManager function I used before with the template. But this time, I had to get it from the document instead of from $this template as I did earlier. I also had to get the document to get the web asset manager from it.
Finally, on the third line, I added the joomla.asset.json file to the registry by telling Joomla where it was located. This function knows to look for the folder under the media directory, so it will load the registry from the specified folder (media/plg_content_contentplugdemo).
Now that we’ve loaded the web asset manager and told it where the directory is within the media folder, we can load styles and scripts just as we did earlier. Use the asset name and the $wa use… functions to load them.
$wa->useStyle("plg.content.contentplugdemo.styles");
Code language: PHP (php)
Now, provided my plugin is enabled and I’m on a content page, I can check and see that “pluginstyles.css” has been loaded properly.
This same logic applies to any other type of extension you want to use the WebAssetManager with. Of course, you must use the useScript and “js” directory instead of useStyle and “css” directory if you’re loading JS.
Conflicting Dependencies and Errors
No Asset in Registry Error
One common error you may encounter when working with assets is basically an asset not found error, which will crash the front end.
0 - There is no "stylename" asset of a "style" type in the registry.
This error likely means you have a typo in the asset name (either in the json file, or the php file you referred to it from with useStyle/useScript).
It could also show up if you accidentally mixed up a script with a style. For example, giving a CSS file the asset type of “script” instead of “style” in joomla.asset.json.
Finally, if you named everything properly and used the right types/functions, you could encounter this issue if Joomla couldn’t find joomla.asset.json to begin with. This means you either never registered the file using the $wa->getRegistry()->addExtensionRegistryFile(...)
function, your joomla.asset.json file has a typo in the filename itself, or you misplaced the file.
Style/Script Isn’t Loading
If you named everything correctly, but the asset itself cannot be found, you will not get the previous error. Instead, Joomla will simply skip trying to load the asset.
So if an expected asset won’t load, you must review a few things. First, make sure the URI is correct in the Json file. If the relative URI conventions I discussed earlier are confusing, try just using the full URI relative to the site root.
If all else fails, you can always load the script or style using traditional script/link elements in the php/html files. It completely defeats the purpose of everything I just reviewed, but it will work in a pinch.
Conflicts
What happens if two assets have the same name? Which one gets loaded?
To test this, I created two assets with the same name – one in the template’s joomla.asset.json file and the other in the content plugin’s file. They both have the same name, but each asset point to different stylesheets. I then called useStyle from the template’s file using the shared name. So which gets loaded?
Depending on the page, either of the two files might be loaded. If I was on a content page, the css file from the content plugin’s asset file was loaded. When I was on a page that wasn’t part of com_content, the other css file was loaded. I believe this has to do with the order in which Joomla prepares different parts of the page. I think Joomla loads content plugins (onContentPrepare) before the template. Since I set the asset up at this point, it used the asset from the plugin rather than the template.
Of course, you can avoid this confusion by not repeating an asset name across multiple extensions. Remember, every asset can use other assets as dependencies. So if you need to make sure something gets loaded with something else, you can load it in as a dependency.
If you have a single asset which you need to make available to multiple extensions, such as a custom CSS or JS framework, it may make sense to package the shared assets in a system plugin and then install that with the respective extensions depending on it. This gives you the flexibility of only having to update the plugin in the event that something with the framework changes or a bug is encountered, rather than having to update every single extension you build which relies upon it.
Register and Use…
Besides the useStyle and useScript functions, the WebAssetManager has the functions “registerAndUseScript” and “registerAndUseStyle”.
These functions allow you to register and use a style, script, or preset, without needing to touch joomla.asset.json.
For these functions, the first argument is the name you wish to give to the asset, and the second is its uri.
For example, to load “anotherstyle.css” from my template’s css folder in the media directory, I can use this code:
$wa->registerAndUseStyle('my.asset', 'anothertest.css');
Code language: PHP (php)
Of course, you still have to get the WebAssetManager using the methods discussed earlier.
Here’s a full example loading a script from a plugin’s media folder…
$doc = Factory::getApplication()->getDocument();
$wa = $doc->getWebAssetManager();
$wa->registerAndUseScript('superspecial.scripts','plg_content_aplugin/myscript.js');
Code language: PHP (php)