#1 - Moving wp_footer before </body>
W3 Total Cache plugin uses
wp_footer hook to output its script tags. Problem is that such a function can be placed anywhere in
footer.php depending on theme or even outside mentioned file. Main goal is to place
wp_footer()
right before
</body>
tag like below:
</div>
<?php wp_footer(); ?>
</body>
</html>
It's important to not have any additionals wrapper tags around
wp_footer
because many SEO tools won't interpret your scripts as placed in bottom of page. Sometimes it can be difficult to modify its position because it may negatively impact entire website appearance. In this case take a look at next method.
#2 – Using W3 Total Cache tag
W3 Total Cache is very comprehensive WordPress plugin and its authors created tiny tag called
<!-- W3TC-include-js-head -->
which you can place in any PHP file of your theme. Of course you will be interested in putting it in
footer.php file or equivalent where
</body>
exists. Like in previous method, place it before
</body>
tag:
<!-- W3TC-include-js-head -->
</body>
To make it work ensure you've enabled „Minify” option in W3TC general settings. Few people reported this method didn't work in some WordPress themes. If you are one of unlucky guys you should definitely give last chance to method #3.
#3 – PHP output filtering
It's a solution which you can use when:
- method #2 fails – simply it didn't work at all
- script files are still visible in places where shouldn't – it's a common case for WordPress plugins which incorrectly append their JS files. Shameful example can be Shareholic social plugin which inject code directly into page source.
Before you modify header and footer you must add following snippet to theme's
function.php file. First function has been found
in one of php.net discussions and is responsible for removing unwanted tags (with their content). Second and last one generate
<script>
tags generation.
/**
* Filter HTML code and leave allowed/disallowed tags only
*
* @param string $text Input HTML code.
* @param string $tags Filtered tags.
* @param bool $invert Define whether should leave or remove tags.
* @return string Filtered tags
*/
function theme_strip_tags_content($text, $tags = '', $invert = false) {
preg_match_all( '/<(.+?)[\s]*\/?[\s]*>/si', trim( $tags ), $tags );
$tags = array_unique( $tags[1] );
if ( is_array( $tags ) AND count( $tags ) > 0 ) {
if ( false == $invert ) {
return preg_replace( '@<(?!(?:'. implode( '|', $tags ) .')\b)(\w+)\b.*?>.*?</\1>@si', '', $text );
}
else {
return preg_replace( '@<('. implode( '|', $tags ) .')\b.*?>.*?</\1>@si', '', $text );
}
}
elseif ( false == $invert ) {
return preg_replace( '@<(\w+)\b.*?>.*?</\1>@si', '', $text );
}
return $text;
}
/**
* Generate script tags from given source code
*
* @param string $source HTML code.
* @return string Filtered HTML code with script tags only
*/
function theme_insert_js($source) {
$out = '';
$fragment = new DOMDocument();
$fragment->loadHTML( $source );
$xp = new DOMXPath( $fragment );
$result = $xp->query( '//script' );
$scripts = array();
$scripts_src = array();
foreach ( $result as $key => $el ) {
$src = $result->item( $key )->attributes->getNamedItem( 'src' )->value;
if ( ! empty( $src ) ) {
$scripts_src[] = $src;
} else {
$type = $result->item( $key )->attributes->getNamedItem( 'type' )->value;
if ( empty( $type ) ) {
$type = 'text/javascript';
}
$scripts[$type][] = $el->nodeValue;
}
}
//used by inline code and rich snippets type like application/ld+json
foreach ( $scripts as $key => $value ) {
$out .= '<script type="'.$key.'">';
foreach ( $value as $keyC => $valueC ) {
$out .= "\n".$valueC;
}
$out .= '</script>';
}
//external script
foreach ( $scripts_src as $value ) {
$out .= '<script src="'.$value.'"></script>';
}
return $out;
}
OK, you're ready. Let's assume you can still see scripts tag within
<head>
section. Hook responsible for content generated in this section is called
wp_head and should be located in
header.php file. Once you localize it, change:
<?php wp_head(); ?>
to this:
<?php
ob_start();
wp_head();
$themeHead = ob_get_contents();
ob_end_clean();
define( 'HEAD_CONTENT', $themeHead );
$allowedTags = '<style><link><meta><title>';
print theme_strip_tags_content( HEAD_CONTENT, $allowedTags );
?>
Now, everything what is not a style, link, meta or title tag will be removed from
<head>
section. The most important is to check before making changes what else your theme generate and add it to
$allowedTags
variable. You have got rid scripts from header file, now you must put it into right place. To do it you must open
footer.php and place following function before
</body>
:
<?php theme_insert_js( HEAD_CONTENT ); ?>
Last method is definitely the most time-consuming and dangerous but gives the best results. Please note that many plugins inject their JS code incorrectly so next you see such a behavior don't hesitate to write e-mail to author of plugin about not applying Codex rules regarding
correct JS registration in WordPress. If you are interested in removing useless CSS and JS from correctly registered plugins you should take a closer look at
Gonzales – WordPress plugin for improving frontend performance.