During the development of my latest Magento shop I ran into the problem of not being able to include external javascript files as easily as you would for internal ones.
The problem:
Just as a quick recap, to include a javascript file in your shop header you just need to add a line to your page.xml file (app>design>frontend>default>yourthemename>layout):
<action method="addJs"><script>../skin/frontend/default/platinumenv/js/functions.js</script></action>
But if you change the path above by something starting with http or https, Magento will not recognize it as being external and try to append the base js url to it. For example a line like this:
<action method="addJs"><script>http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js</script></action>
will outpout something like that in the header:
<script type="text/javascript" src="http://www.myshop.com/js/http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
You can of course hard code the script tag but 1) it will have to be before or after the files included by the xml, which might create some conflicts and 2) it’s not fun at all!
My idea of a solution
After digging into some of the core files responsible for the output of the js I started to have a better idea of how to resolve the issue. The good thing about Magento is that when a core file does not behave the way you want, you can “easily” override.
The file we want to change here is Mage/Page/Block/Html/Head.php. This is where Magento handles inclusions in the header as well as file merging for js and css, among other stuff.
I am going to override this class to change one of its function: &_prepareStaticAndSkinElements(). Here is the new code:
<?php
/**
* Extjs
* Override core class to provide a way to include external javascript files
*/
class Foo_Page_Block_Html_Head extends Mage_Page_Block_Html_Head
{
/**
* Same as core file exept first foreach loop where we look for http or https in the
* url of the script
*/
protected function &_prepareStaticAndSkinElements($format, array $staticItems, array $skinItems, $mergeCallback = null)
{
$designPackage = Mage::getDesign();
$baseJsUrl = Mage::getBaseUrl('js');
$items = array();
if ($mergeCallback && !is_callable($mergeCallback)) {
$mergeCallback = null;
}
// get static files from the js folder, no need in lookups
foreach ($staticItems as $params => $rows) {
foreach ($rows as $name) {
//if http or htttps, do not add baseurl, do not try to merge
if(strstr($name, 'http://') || strstr($name, 'https://'))
$items[$params][] = $name;
else
$items[$params][] = $mergeCallback ? Mage::getBaseDir() . DS . 'js' . DS . $name : $baseJsUrl . $name;
}
}
// lookup each file basing on current theme configuration
foreach ($skinItems as $params => $rows) {
foreach ($rows as $name) {
$items[$params][] = $mergeCallback ? $designPackage->getFilename($name, array('_type' => 'skin'))
: $designPackage->getSkinUrl($name, array());
}
}
$html = '';
foreach ($items as $params => $rows) {
// attempt to merge
$mergedUrl = false;
if ($mergeCallback) {
$mergedUrl = call_user_func($mergeCallback, $rows);
}
// render elements
$params = trim($params);
$params = $params ? ' ' . $params : '';
if ($mergedUrl) {
$html .= sprintf($format, $mergedUrl, $params);
} else {
foreach ($rows as $src) {
$html .= sprintf($format, $src, $params);
}
}
}
return $html;
}
}
Very simple, if the path has http:// or https:// then do not include the baseurl
You then need to declare the new class in etc/local.xml. Add those lines between the existing <global> tags:
<blocks>
<page>
<rewrite>
<html_head>Foo_Page_Block_Html_Head</html_head>
</rewrite>
</page>
</blocks>
And that’s it. You can now enjoy adding external javascript files to your xml.





















Ace post! I like the presentation of the problem and solution. This may well come in useful.. ^_^
Hmm, I don’t have an etc/local.xml.
I have a layout/local.xml
Would that be it?
The etc/local.xml is where db details are stored so you definitelly have one. The full path to it is root/app/etc/local.xml.
I’ve never seen a layout/local.xml so can’t really say if it will do the same. Would be nice if it did though.
Can’t believe there is no easier way to do it.
Seems weird!
But I appreciate it anyway – Thx.
It’s really helpful for include external javascripts and speed up the magento site.
Regards,
Mahesh
Awesome! thanks a bunch man…
or you could save yourself the hassle and use setText in the head reference.
At the time of writing this solution was the only one I could find but if you say you can simply add a setText now them all the better