Magento loads first the javascript files contained in root/js folder and then those in skin_js. This provides a good enough structure so that you can load core javascript files first and then your own ones in skin_js.
But say you have multiple layouts files that each loads javascript files which depend on each other. For example you have a custom module that needs the jquery library, but its javascript files are loaded before that and undefined jQuery variable.
We create a simple module to be able to specify the order of css and javascript files. First register it. Create a file named Company_ReorderAssets.xml inside app/etc/modules and insert:
1
2
3
4
5
6
7
8
9
<?xml version="1.0"?>
<config>
<modules>
<Company_ReorderAssets>
<active>true</active>
<codePool>local</codePool>
</Company_ReorderAssets>
</modules>
</config>
Then create the module. Inside app/code/local/Company create the path ReorderAssets/etc/config.xml and insert:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0"?>
<config>
<modules>
<Company_ReorderAssets>
<version>1.0.0</version>
</Company_ReorderAssets>
</modules>
<global>
<blocks>
<class>Company_ReorderAssets_Block</class>
<page>
<rewrite>
<html_head>Company_ReorderAssets_Block_Page_Html_Head</html_head>
</rewrite>
</page>
</blocks>
</global>
</config>
Now we create the path for the class that we want to edit:ReorderAssets/Block/Page/Html/Head.php and insert:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
class Company_ReorderAssets_Block_Page_Html_Head extends Mage_Page_Block_Html_Head {
public function addItemFirst($type, $name, $params = null, $if = null, $cond = null) {
if ($type === 'skin_css' && empty($params)) {
$params = 'media="all"';
}
$firstElement = array();
$firstElement[$type . '/' . $name] = array(
'type' => $type,
'name' => $name,
'params' => $params,
'if' => $if,
'cond' => $cond,
);
$this->_data['items'] = array_merge($firstElement, $this->_data['items']);
return $this;
}
public function addItemAfter($after, $type, $name, $params = null, $if = null, $cond = null) {
if ($type === 'skin_css' && empty($params)) {
$params = 'media="all"';
}
$firstElement = array();
$firstElement[$type . '/' . $name] = array(
'type' => $type,
'name' => $name,
'params' => $params,
'if' => $if,
'cond' => $cond,
);
if (array_key_exists($after, $this->_data['items'])){
$pos = 1;
foreach ($this->_data['items'] as $key => $options){
if ($key == $after) :
break;
endif;
$pos +=1;
}
array_splice($this->_data['items'], $pos, 0, $firstElement);
}
return $this;
}
}
The function addItemFirst adds the first javascript or css file, but it will not add it again if it is already added. It is used the same as the addItem function. The function addItemAfter adds the needed css or js file after the first item. It’s file path should be either js/file.js for root js folder or file.js for skin_js folder.
Here it is how to use it in your layout.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0"?>
<layout version="0.1.0">
<default>
<reference name="head">
<action method="addItemFirst"><type>skin_js</type><script>js/jquery.js</script></action>
<action method="addItemAfter">
<after>skin_js/js/jquery.js</after>
<type>skin_js</type>
<script>newsletter_popup/newsletter_popup.js</script>
</action>
<action method="addItemAfter">
<after>skin_js/js/jquery.js</after>
<type>skin_js</type>
<script>newsletter_popup/cookies.js</script>
</action>
</reference>
</default>
</layout>
Now if I do a source code I get:
1
2
3
<script type="text/javascript" src="http://example.net/skin/frontend/company/theme/js/jquery.js"></script>
<script type="text/javascript" src="http://example.net/skin/frontend/company/theme/newsletter_popup/cookies.js"></script>
<script type="text/javascript" src="http://example.net/skin/frontend/company/theme/newsletter_popup/newsletter_popup.js"></script>
This xml loads first with addItemFirst the file js/jquery.js which is in skin_js. If it is already added in another xml, it will not load it again, but it is necessary to be stated here. Then with addItemAfter we add the javascript newsletter_popup/newsletter_popup.js after the skin_js/js/jquery.js. Calling the skin_js before the path is important.
If you were to include a root/js file we would use it like this:
1
2
3
4
5
<action method="addItemAfter">
<after>js/jquery.js</after>
<type>js</type>
<script>newsletter_popup/newsletter_popup.js</script>
</action>
Of course you must replace Company with the name of your company by convention.
Special thanks to Koncz Szabolcs.