سؤال

Does anyone know how to have all of Magento's JS script tags e.g. <script type="text/javascript" src="http://sitename.com/js/prototype/prototype.js"></script> render out before the closing </body>?

I've tried this once before, but I was given an error which I think was along the lines of the addJS method not being available where I used it, possibly in reference footer.

هل كانت مفيدة؟

المحلول

It depends on your request. For instance, lastly, I had been removed all Prototype scripts from the Homepage of the Magento store which I didn't face any problem. But as I said, it depends on your theme, extensions etc.

To moving the script :

Find the following line in page.xml of your theme

<block type="core/text_list" name="before_body_end" as="before_body_end" translate="label">

And insert the following just before :

<block type="page/html_head" name="jsfooter" as="jsfooter" template="page/html/jsfooter.phtml">
   <action method="addJs"><script>your_script.js</script></action>
</block>

For Magento 1.9 use this:

<block type="page/html_head" name="jsfooter" as="jsfooter" template="page/html/jsfooter.phtml">
       <action method="addItem"><type>skin_js</type><name>js/yourskinfile.js</name><params/></action>
    </block>

Create the template file in app/design/frontend/[package]/[theme]/template/page/html/jsfooter.phtml and put the following

<?php echo $this->getCssJsHtml() ?>

Add below in your template just before closing </body> tag.

<?php echo $this->getChildHtml('jsfooter') ?>

نصائح أخرى

There are two problems with moving the tag. The greatest problem is that for some reason Magento injects a lot of JS that is dependent on prototype directly into the <body/> tag. Moving the scripts to the end of the document (though good for load times), will break a lot of the pages in Magento.

The other problem is actually doing it. There doesn't seem to be <move /> tag, or similar functionality. What I have done for custom scripts that I have created is adding scripts like this. It is more redundant, but it works:

<block type="page/html_head" name="foot.scripts" template="page/template/foot-scripts.phtml">
    <action method="addJs"><script>jmax/global-min.js</script></action>
</block>

In Magento 1.x this is a fool's errand. There are simply too many inline scripts littered throughout the template files in Magento that will break if you relocated the core JS files from the <head>. Potentially in Magento 2, this situation will change but it's straddling Prototype and jQuery as Magento migrates away from Prototype.

For other scripts, you should place them before the </body> element. I've found it helpful to ignore Magento's <action method="addJS|addItem"> XML and simply create a new template file for each script, which includes a plain HTML script reference like:

<script src="<?php echo $this->getSkinUrl('js/hobbiton.js'); ?>"></script>

Then you can embed this template file anywhere (and still use before/after to control the order) like so:

<block type="core/template name="jquery.hobbiton" after="-" template="custom/jquery/hobbiton.phtml" />

Moving external JavaScript to the bottom is not enough in most cases. If you use any templates with inline JavaScript, like in the default themes, you will need to delay the execution of these until all dependencies (prototype.js, varien.js, ...) are loaded.

An approach is to extract all inline <script> elements from rendered blocks using an observer for http_response_send_before and move them to the end right after the external scripts. While you are at it, you can move all script elements, not only inline. This saves you the hassle of moving them via the layout model, which was clearly not intended by Magento.

Tom Robertshaw created an extension that does exactly this, with a single observer that changes the response HTML using regular expressions: https://github.com/bobbyshaw/magento-footer-js

He uses the core_block_abstract_to_html_after event but only takes action if the current block is the root block. This means, the observer is called more often, but it should leverage block caching to some degree.

I highly recommend the mediarox pagespeed module to help you optimise your javascript (and css) and improve google pagespeed insight ranking.

It works by parsing html output by Magento and then performing a cut and paste action on the code to move javascript to the bottom of the html code. The process is fast but is best used in conjunction with a full page cache to cache the html changes.

More information on how this module works and can help you to improve pagespeed rank here:

http://blog.gaiterjones.com/magento-google-pagespeed-jscsshtmlminify-optimisation/

For Magento v1.6+ (need to test in older versions);

1 - create an template file in page/html/footer/extras.phtml with this content:

<?php echo $this->getCssJsHtml() ?>

2 - Add this html node to your layout xml:

<reference name="before_body_end">
<block type="page/html_head" name="extra_js" as="extraJs" after="-" template="page/html/footer/extras.phtml">
    <action method="addItem"><type>skin_js</type><name>js/jquery.min.js</name></action>
</block>

3 - That is it!

Due to an issue with this other script (in product/list.phtml) <script type="text/javascript"> decorateList('category-list', 'none-recursive') </script> I had to move some JS at the end of my page.

I wasn't able to make what's indicated above work so I find another way to achieve :

I override the Mage/page/Block/Html/Footer.php controller by recreating it with the same path in app/local folder.

Here is the full path to be created if not exists :

app/local/Mage/page/Block/Html/Footer.php

In this file, I add functions from Head.php which can be found in the same folder of Magento's core (i.e. Mage/page/Block/Html/Head.php).

Functions you need to make it works are (obviously the full function, here I just indicate the name to remain concise):

public function addItem($type, $name, $params=null, $if=null, $cond=null)
{...}

public function addJs($name, $params = "")
{...}

public function getCssJsHtml()
{...}

protected function &_prepareStaticAndSkinElements($format, array $staticItems, array $skinItems, $mergeCallback = null)
{...}

protected function _separateOtherHtmlHeadElements(&$lines, $itemIf, $itemType, $itemParams, $itemName, $itemThe)
{...}

protected function _prepareOtherHtmlHeadElements($items)
{...}

Then I add to my custom (the one in my theme) page/html/footer.phtml the call for this :

<?php echo $this->getCssJsHtml() ?>

At the end, I can now add JS in my footer by calling it in any layout by

<action method="addJs"><script>yourscript.js</script></action>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى magento.stackexchange
scroll top