Stripping Joomla 3

So Joomla 3 has been around for a while now and seems stable enough that you can use it for production sites without having to check up on it everyday to see if anything new has broken. And with a new site comes a new template. As always, I wanted it to be fast loading, so I set out to investigate what it is that joomla is inserting into my site.

So I thought a good place to start would be with a blank template. Now when I say blank, I mean literally nothing in there. This is the content of the index.php file:

<?php
// No direct access.
defined('_JEXEC') or die;
?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $this->language; ?>">
 <head>
 <jdoc:include type="head" />
 </head>
 <body>
<jdoc:include type="component" />
 <jdoc:include type="modules" name="debug" />
 </body>
</html>

So basically the tag for Joomla to output the head, the content and a module position for the debug information. Loading up the site, this is the content of the documents head:

<head>
<base href="http://localhost/joomla3/" />http://localhost/joomla3/" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="generator" content="Joomla! - Open Source Content Management" />
<title>Home</title>
<link href="http://localhost/joomla3/index.php"http://localhost/joomla3/index.php" rel="canonical" />
<link href="/joomla3/index.php?format=feed&amp;type=rss" rel="alternate" type="application/rss+xml" title="RSS 2.0" />
<link href="/joomla3/index.php?format=feed&amp;type=atom" rel="alternate" type="application/atom+xml" title="Atom 1.0" />
<link href="/joomla3/templates/test/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />
<script src="/joomla3/media/system/js/mootools-core.js" type="text/javascript"></script>
<script src="/joomla3/media/system/js/core.js" type="text/javascript"></script>
<script src="/joomla3/media/system/js/caption.js" type="text/javascript"></script>
<script type="text/javascript">
window.addEvent('load', function() {
new JCaption('img.caption');
});
</script>
</head>

This can get a lot worse if extensions start requesting the bootstrap framework using JHtml::_('bootstrap.framework'); as this results in these additional lines being loaded:

<script src="/joomla3/media/jui/js/jquery.min.js" type="text/javascript"></script>
<script src="/joomla3/media/jui/js/jquery-noconflict.js" type="text/javascript"></script>
<script src="/joomla3/media/jui/js/bootstrap.min.js" type="text/javascript"></script>

So with that one line inserted in the template we now have 2 locally loaded javascript libraries, bootstrap javascript, core javascript and some inline javascript which we aren't even using. 

So how do we stop all of this from happening? Well I began with the template overrides, copying all the views for com_content into the templates html folder and then going through each one and removing any instances of the following:

JHtml::_('behavior.caption');
JHtml::_('bootstrap.tooltip');
JHtml::_('behavior.tooltip');
JHtml::_('behavior.framework');

This stops the extra scripts from being loaded, but we still have mootools caption and the core js loading. We can remove those by unsetting them in the templates index file:

$app = JFactory::getApplication();
$doc = JFactory::getDocument();
$this->language = $doc->language;
$this->direction = $doc->direction;
unset($doc->_scripts[JURI::root(true) . '/media/system/js/mootools-core.js']);
unset($doc->_scripts[JURI::root(true) . '/media/system/js/mootools-more.js']);
unset($doc->_scripts[JURI::root(true) . '/media/system/js/core.js']);
unset($doc->_scripts[JURI::root(true) . '/media/system/js/caption.js']);
unset($doc->_scripts[JURI::root(true) . '/media/jui/js/jquery.min.js']);
unset($doc->_scripts[JURI::root(true) . '/media/jui/js/jquery-noconflict.js']);
unset($doc->_scripts[JURI::root(true) . '/media/jui/js/bootstrap.min.js']);

That takes care of the core files that either load, or can be requested by components. The problem now is that we still have the inline caption script which will also now throw an error because mootools isn't defined. Now we don't want to remove the whole lot as we would also loose any js added by modules are components so we need to use php to check if javascript is set and if it is, to remove the caption code from the string:

if (isset($this->_script['text/javascript']))
{
 $this->_script['text/javascript'] = preg_replace('%window\.addEvent\(\'load\',\s*function\(\)\s*{\s*new\s*JCaption\(\'img.caption\'\);\s*}\);\s*%', '', $this->_script['text/javascript']);
 if (empty($this->_script['text/javascript']))
 unset($this->_script['text/javascript']);
}

So now, if I check the content of the head again, we get this:

<head>
<base href="http://localhost/joomla3/" />http://localhost/joomla3/" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="author" content="Super User" />
<meta name="generator" content="Joomla! - Open Source Content Management" />
<title>Home</title>
<link href="http://localhost/joomla3/index.php"http://localhost/joomla3/index.php" rel="canonical" />
<link href="/joomla3/templates/test/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />
</head>

Just the generator tag to remove and the work is done:

$this->setGenerator(NULL);

Bear in mind that we are unsetting the scripts at the top of the templates index file, so anything which calls the framework behaviour after that will still load up the libraries.