5

I'm trying to unset all javascript declarations in the document head.

By this I mean inline javascript that is added by 3rd party extensions using ->addScriptDeclaration(), and not javascript files that are added using ->addScript().

If I dump

$doc = JFactory::getDocument();
var_dump($doc->_scripts);

then all Javascript files added by the Joomla core and 3rd party extensions are shown.

If I dump

$doc = JFactory::getDocument();
var_dump($doc->_script['text/javascript']);

Then only the core javascript is shown, eg:

string(79) "jQuery(window).on('load',  function() {
            new JCaption('img.caption');
        });"

Anything added by 3rd party extensions is not included and still gets outputted to the head.

Is it possible to intercept 3rd party script in the template or is it added at a later date and can only be done by a plugin at a certain event?

  • Why would you want to remove script declarations added by extensions. They are added for a reason (to add functionality to the extensions), thus if you remove them, you are removing some of the extensions functionality – Lodder Oct 21 '14 at 9:17
  • @lodder I didn't say I want to remove them. I want to unset them and move them out of the head of the document to the bottom of the page. However, the script in the code above only adds script added by the Joomla core and not extensions, hence my question. – Robert Went Oct 21 '14 at 11:39
5

This answer is very long and has many methods, best is at the bottom

unset($doc->_scripts[JUri::base(true)'/path/to/file.js'])

is mostly how to do it, some scripts might add the full url and some might not.

So here is a better way to go about it if you want everything removed.

$doc->_scripts = array();
//if you need to re include libraries
JHtml::_('jquery.framework');
JHtml::_('behavior.framework');

//if the array trick does not work you could do
for($i=0;$i<count($doc->_scripts);$i++){
   //in here you could stop it from removing specific files by looking for specific file names
   $get_file = explode('/',$doc->_scripts[$i]);
   $get_file = end($get_file);

   //many more ways to do this, chains of if statements can get messy
   switch($get_file){
      case 'jquery.js':
      case 'boostrap.js';
         break;
      default:
         unset($doc->_scripts[$i]);
         break;
   }
}

EDIT:

For script declaration it combines most scripts into one rather then seperate them, also the template is not the last place to execute before the page is rendered, so more could still be added to the script array. I am not 100% on this but I believe modules are rendered after the template and then inserted, components load based on the menu item so they load before. Also plugins can add more scripts afterwords.

So the only way to guarantee that you can adjust the scripts to your needs fully would be through a plugin. There is a system event called onBeforeCompileHead that can do that.

http://docs.joomla.org/Plugin/Events/System#onBeforeCompileHead

You would have to create a plugin but they are the easiest of all extensions to make, here is a good reference.

http://docs.joomla.org/J3.x:Creating_a_Plugin_for_Joomla

In Summary, depending on where it is added it may not be possible in the template, plugins could be the only way.

UPDATE Like I said it cannot be done with just templates, but I found a way to get around that with a simple system plugin that can be used to allow it on any site. This is something that would be useful in the core and I might try to do a pull request to get it added, though anyone is welcome to. However its unlikely to be added "next release"

class PlgSystemHooks extends JPlugin
{
    public function onAfterDispatch(){
        $app = JFactory::getApplication();
        $template = $app->getTemplate();

        if ($app->isSite())
        {
            if (file_exists(JPATH_THEMES.DIRECTORY_SEPARATOR.$template.DIRECTORY_SEPARATOR.'functions.php'))
            {
                $dispatcher = JDispatcher::getInstance();
                require_once JPATH_THEMES.DIRECTORY_SEPARATOR.$template.DIRECTORY_SEPARATOR.'functions.php';
            }
        }
    }
}

This is sort of inspired by wordpress but I was blown away when, by looking at source code I discovered it was basically completely supported in core, just the final step of defining a file in the template was missed. Such a useful functionality!

Here is how to use it.

First create a functions.php file in your template.

Next use something like this in that file.

$dispatcher->register('onBeforeCompileHead',function(){
   //your code to remove the unneeded scripts.
});

Note: I did this from memory, so it might not be 100% correct, looking into the JDispatcher class might be a good idea if it does not work. This can be very useful in many projects that need some simple plugin functionality specifically for that site, but making a custom plugin is way more work then it needs to be.

  • Thanks for the answer, but I don't have an issue unsetting script files. It is specifically script declarations (inline javascript) added to the head by 3rd party extensions using the addScriptDeclaration syntax. – Robert Went Oct 20 '14 at 21:43
  • The way you worded it is a little misleading then. I will adjust my answer to help though. – Jordan Ramstad Oct 21 '14 at 13:51
  • Ok, if you could let me know what is misleading I will try and alter the question. The addScriptDeclaration() in the title is used to add inline javascript rather than files. – Robert Went Oct 21 '14 at 13:55
  • Its not that its wrong, its that when I first read it I did not fully grasp what was needed. Anyway added to the answer for script declarations. – Jordan Ramstad Oct 21 '14 at 14:09
  • Thanks, I've updated the question. Unfortunately this doesn't work. When dumping the scripts array, the 3rd party code isn't in the array so it's not possible to unset the code that hasn't been added yet. I've just been through all the methods and it's starting to look like it's just not possible from within the template. – Robert Went Oct 21 '14 at 14:15
3

The other way to do it, and the method that I prefer, is to simply create an override for the extension and comment out the call for the script there.

I do this all the time, for almost every extension I use, removing both script and css calls. The only possible gotcha is that if the extension developer did not put the calls in the view file, then you can't create a template override and you'd have to hack the extension instead.

  • +1 for good practice. This is currently what I'm doing but want to future-proof it a bit incase extensions are added in the future. I thought all script would be contained in _script[] but it seems like the template gets rendered before the head is put together. – Robert Went Oct 21 '14 at 11:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.