WordPress page load optimization


||

packing_box.jpg I had to touch some pages to decrease load time for WordPress pages and collect some material to write down. Few articles will be follow to describe the received experience.

the material will be more interesting for programmers who understand code oof WordPress. But some of the issues can be done by accurate people.

The easiest way to lightning page loading in times is followed:

  1. reduce number of files to load
  2. concatenate scripts to one file
  3. concatenate styles to one files if possible
  4. compress loaded files
  5. caching everything except page content html

and make all of this in engine, without manual changing of files when you will make changing something small :)

Reduce number of files to load

First you can take a look into page source and try to find what is really necessary for the page. WordPress make adding features too easy and most of the plugin writers do not think about good conditions for add style or script.

If you take a look into conditions for add something by plugin, you can add same condition for style or script added by the plugin. By my experience it can reduce number of unused files a lot. For example for comment or related posts is_singular() conditional remove artifacts from index pages.

Another good way is graphics optimizing. If you take a look into WordPress admin styles you can find that button has backgrounds from the file
Button images
but button style is

#adminmenu #menu-posts div.wp-menu-image {
    background: transparent url("../images/menu-vs.png") no-repeat scroll -272px -33px;
}

#adminmenu #menu-posts:hover div.wp-menu-image,
#adminmenu #menu-posts.wp-has-current-submenu div.wp-menu-image {
    background: transparent url("../images/menu-vs.png") no-repeat scroll -272px -1px;
}

At least 11 buttons with active and passive images reference to single file.

Another good way to optimize graphics is data: URL. It is very useful in automate change linked icons to data fields in CSS and page content with amazing reduce the total amount of files. I will show the case in followed articles.

Concatenate scripts to one file

WordPress from version 2.8 can concatenate scripts and styles, but unfortunately it is active only for admin. To change it you need:

  • use internal WordPress class for show script instead of simple echo '<script ..>'. For script it is
    $wp_scripts = new WP_Scripts();

    where $wp_scripts is global variable.
    Also you can use enveloping with wp_enqueue_script()

  • enqueue scripts before scripts including in the wp-head()
    For plugin it is action before or in wp_head with priority up to 8, because wp_print_head_scripts use priority 9.

  • Change the WordPress engine core code , because only admin script concatenated by default

By steps in details:

Right script inculding

If you want to receive something like

<script type='text/javascript' src='/wp-content/themes/my-theme/script.js'></script>

you have to add into code something like

wp_enqueue_script('theme-script','/wp-content/themes/my-theme/script.js',array('jquery'),'1.1.5',true);
  1. 'theme-script' – unique handler for identification
  2. '/wp-content/themes/my-theme/script.js' – path from WordPress root. Usually better use constants or function to get path, but later you will find that this way is only one possible.
  3. array('jquery') – another WordPress feature – scripts dependence, from jQuery library in the case. And lib will be included before script by engine without any additional notification
  4. '1.1.5' – version of the script – used for cache and manage the scripts lists. Internal scrips WordPress used file date, but is up to you
  5. true – in this case place script in the footer. If missed or defined as false – script will be included in the header

I don’t think that the changing is so complicated.

Place for enqueue the script

Theme should add scripts somewhere in the header.php before wp_head();

Plugin should request script including before wp_print_head_scripts what is mean followed:

add_action('wp_head', 'my_head_handler', 7);

function my_head_handler() {
   wp_enqueue_script('plugin-script','/wp-content/plugins/my-plugin/script.js',array('jquery'),'1.1.5',true);
}

Please , make the attention for last parameter of add_action – it is priority. And 7 is universal for scripts and styles, because styles printing use 8 and script printing use 9.

After the changes you can find right and accurate scripts printing in the header or footer of your page.
but target is concatenate and gzip all of them.

Concatenation and packing on request

WordPress can do both from version 2.8, but by default it is enabled only for admin’s scripts. If you want to implement this fro all script then you have to put followed changed for script-loader.php ( from WordPress 2.9.2 ) and additional file scripts.php for describe script data. Other WordPress versions can has another line numbers or has another functions. And yes , it is hardcoding in the core WordPress code , please use it carefully. The modification is not dependence from any other changes and scipts will loaded as single links without the changes. In this case you can update version without crashing.

First in the file /wp-includes/script-loader.php

  1. // TODO: Wott - use GZIP
  2. define('ENFORCE_GZIP', true);

Enable gzip for scripts and styles

  1. // TODO: Wott add scripts to compact load
  2. require( ABSPATH . 'wp-content/scripts.php' );

And include additional file for custom scripts /wp-content/scripts.php

  1. // TODO: Wott - allow concat for all users
  2. if ( ( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) )
  3.     $concatenate_scripts = false;

And remove is_admin dependence.

Next new file /wp-content/scripts.php with content like

  1. <?php
  2.  
  3. $scripts->default_dirs[] = '/wp-content/themes/elegant-box/js/';
  4.  
  5. $scripts->add('theme-style-switcher','/wp-content/themes/elegant-box/js/styleswitcher.js',false,'1');
  6. $scripts->add_data( 'theme-style-switcher', 'group', 1 );
  7.  
  8. $scripts->add('theme-base','/wp-content/themes/elegant-box/js/base.js',false,'1');
  9. $scripts->add_data( 'theme-base', 'group', 1 );
  10.  
  11. $scripts->add('theme-menu','/wp-content/themes/elegant-box/js/menu.js',false,'1');
  12. $scripts->add_data( 'theme-menu', 'group', 1 );
  13.  
  14. $scripts->add('theme-comments','/wp-content/themes/elegant-box/js/comment.js',false,'1');
  15.  
  16. $scripts->add('highslide','/wp-includes/js/highslide/highslide-with-gallery.min.js',false,'4.1.8');
  17. $scripts->add_data( 'highslide', 'group', 1 );
  18.  
  19. ?>

In the 3rd line we add dir for custom theme scripts. If you are including another scripts not from /wp-admin/js/ or /wp-includes/js/, then you have to add the dirs additionally. Nested folders will be not required for add.

Next by $scripts->add the script repeat wp_enqueue_script calls, excluding last parameter. If you need include script in the footer then add $scripts->add_data with 'group' and '1'

And same for all script you want to concatenate.

NB: this place override data in wp_enqueue_script calls.

After all of the described changes you can find that scripts loaded by once ( or two if you have header and footer scripts together ) /wp-admin/load-scripts.php request, gzipped and less impact total page loading time.

in the followed articles you can find: styles concatenation, changing small graphics to data:URI and cache control …

feedback content * preview
Comments
  • @slookin

    Mostly no difference, but
    1. you still control sequence and conditions of styles and scripts – some layouts and scripts have dependencies. Of course this issue can be solved, but with more complex rules inside plugin.
    2. Reuse of native WP code instead of additional plugin. The style and script concatenation already works in admin pages and very small changes can enable this for all pages.
    3. It’s more funny :)

  • what about WP Minify plugin? it is cover most of your advices.
    for example it helps to reach “Page Speed Score: 95/100″ by google speed rank

  • I just found one additional issue:

    Someone protect WordPress by deny access to /wp-admin/ folder, but my technique require access to /wp-admin/load-scripts.php.

    I advice to remove full protection of /wp-admin/ with followed additional to root .htaccess:

    RewriteEngine On
    RewriteBase /

    RewriteRule ^wp-admin/load-scripts.php - [L]
    RewriteRule ^wp-admin/load-styles.php - [L]
                                           
    RewriteCond %{REMOTE_HOST} !^XXX.XXX.XXX.XXX$
    RewriteRule ^wp-admin - [L,F]

    RewriteCond %{REMOTE_HOST} !^XXX.XXX.XXX.XXX$
    RewriteRule ^wp-login.php - [L,F]

    Please insert your IP instead of XXX.XXX.XXX.XXX

    NB: you need remove protection in /wp-admin/.htaccess in this case.