July 14 2016

Website Performance

Deferred parsing of Javascript – General

<script type="text/javascript">
  // Add a script element as a child of the body
  function downloadJSAtOnload() {
    var element = document.createElement("script");
    element.src = "deferredfunctions.js";
    document.body.appendChild(element);
  }
  // Check for browser support of event handling capability
  if (window.addEventListener)
    window.addEventListener("load", downloadJSAtOnload, false);
  else if (window.attachEvent)
    window.attachEvent("onload", downloadJSAtOnload);
  else
    window.onload = downloadJSAtOnload;
</script>

Deferred parsing of JavaScript in WordPress

// Defer Javascript parsing.  Add this to the theme's functions.php 
function defer_parsing_of_js ($url) {
    if (false === strpos($url, '.js'))
        return $url;
    if (strpos($url, 'jquery.js'))
        return $url;
    // return '$url async onload=myinit()';
    return '$url defer ';
}
add_filter('clean_url', 'defer_parsing_of_js', 11, 1);

Lazy CSS Loading with JavaScript

<script>
    var cb = function() { 
        var l = document.createElement('link'); 
        l.rel = 'stylesheet'; 
        l.href = 'yourCSSfile.css'; 
        var h = document.getElementsByTagName('head')[0];
        h.parentNode.insertBefore(l, h); 
    }; 
    var raf = requestAnimationFrame || 
              mozRequestAnimationFrame || 
              webkitRequestAnimationFrame || 
              msRequestAnimationFrame; 
    if (raf) 
        raf(cb); 
    else 
        window.addEventListener('load', cb); 
</script>

Modify .htaccess to Leverage Browser Caching

# ----------------------------------------------------------------------
# | Leverage Browser Caching |
# ----------------------------------------------------------------------
## EXPIRES CACHING ##
<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/jpg "access 1 year"
  ExpiresByType image/jpeg "access 1 year"
  ExpiresByType image/gif "access 1 year"
  ExpiresByType image/png "access 1 year"
  ExpiresByType text/css "access 1 month"
  ExpiresByType text/html "access 1 month"
  ExpiresByType application/pdf "access 1 month"
  ExpiresByType text/x-javascript "access 1 month"
  ExpiresByType application/x-shockwave-flash "access 1 month"
  ExpiresByType image/x-icon "access 1 year"
  ExpiresDefault "access 1 month"
</IfModule>
## EXPIRES CACHING ##
## CACHE CONTROL BY HTTP HEADERS ##
Header unset Pragma
<IfModule mod_headers.c>
  <FilesMatch "\\.(ico|jpe?g|png|gif|flv|svg|swf)$">
    Header set Cache-Control "max-age=2692000, public"
  </FilesMatch>
  <FilesMatch "\\.(css)$">
    Header set Cache-Control "max-age=2692000, public"
  </FilesMatch>
  <FilesMatch "\\.(js)$">
    Header set Cache-Control "max-age=216000, private"
  </FilesMatch>
  <FilesMatch "\\.(x?html?|php)$">
    Header set Cache-Control "max-age=600, private, must-revalidate"
  </FilesMatch>
  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  # Remove `ETags` as resources are sent with far-future expires headers
  Header unset ETag
  Header unset Last-Modified
</IfModule>
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# `FileETag None` doesn't work in all cases.
FileETag None
## CACHE CONTROL BY HTTP HEADERS ##

Modify .htaccess to enable Compression

# ----------------------------------------------------------------------
# | Compression |
# ----------------------------------------------------------------------
<IfModule mod_deflate.c>
 # Force compression for mangled `Accept-Encoding` request headers
 <IfModule mod_setenvif.c>
 <IfModule mod_headers.c>
 SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
 RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
 </IfModule>
 </IfModule>
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 # Compress all output labeled with one of the following media types.
 # (!) For Apache versions below version 2.3.7 you don't need to
 # enable `mod_filter` and can remove the `<IfModule mod_filter.c>`
 # and `</IfModule>` lines as `AddOutputFilterByType` is still in
 # the core directives.
 <IfModule mod_filter.c>
 AddOutputFilterByType DEFLATE "application/atom+xml" \
 "application/javascript" \
 "application/json" \
 "application/ld+json" \
 "application/manifest+json" \
 "application/rdf+xml" \
 "application/rss+xml" \
 "application/schema+json" \
 "application/vnd.geo+json" \
 "application/vnd.ms-fontobject" \
 "application/x-font-ttf" \
 "application/x-javascript" \
 "application/x-web-app-manifest+json" \
 "application/xhtml+xml" \
 "application/xml" \
 "font/eot" \
 "font/opentype" \
 "image/bmp" \
 "image/svg+xml" \
 "image/vnd.microsoft.icon" \
 "image/x-icon" \
 "text/cache-manifest" \
 "text/css" \
 "text/html" \
 "text/javascript" \
 "text/plain" \
 "text/vcard" \
 "text/vnd.rim.location.xloc" \
 "text/vtt" \
 "text/x-component" \
 "text/x-cross-domain-policy" \
 "text/xml"
 </IfModule>
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 # Map the following filename extensions to the specified
 # encoding type in order to make Apache serve the file types
 # with the appropriate `Content-Encoding` response header
 # (do note that this will NOT make Apache compress them!).
 #
 # If these files types would be served without an appropriate
 # `Content-Enable` response header, client applications (e.g.:
 # browsers) wouldn't know that they first need to uncompress
 # the response, and thus, wouldn't be able to understand the
 # content.
 <IfModule mod_mime.c>
 AddEncoding gzip svgz
 </IfModule>
</IfModule>

<FilesMatch "\\.(js|css|html|htm|php|xml)$">
 SetOutputFilter DEFLATE
</FilesMatch>

<IfModule mod_gzip.c>
 mod_gzip_on Yes
 mod_gzip_dechunk Yes
 mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
 mod_gzip_item_include handler ^cgi-script$
 mod_gzip_item_include mime ^text/.*
 mod_gzip_item_include mime ^application/x-javascript.*
 mod_gzip_item_exclude mime ^image/.*
 mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>

Prevent Image Hotlinking

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yourwebsite.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yourotherwebsite.com [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ http://i.imgur.com/MlQAH71.jpg [NC,R,L]

Allow Caching with HTTP Headers

// Allow cache in HTTP headers
function frontend_http_headers_with_cache() {
 if(!is_admin()) {
 header_remove("Cache-Control");
 header("Cache-Control: public, max-age=1200");
 }
}
add_action('send_headers', 'frontend_http_headers_with_cache', 10, 1);

MySQL Query Cache

# Check if query cache is available
show variables like 'have_query_cache';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| have_query_cache | YES   |
+------------------+-------+
# Check query cache variables
show variables like 'query%';
+------------------------------+---------+
| Variable_name                | Value   |
+------------------------------+---------+
| query_alloc_block_size       | 8192    |
| query_cache_limit            | 1048576 |
| query_cache_min_res_unit     | 4096    |
| query_cache_size             | 8388608 |
| query_cache_type             | ON      |
| query_cache_wlock_invalidate | OFF     |
| query_prealloc_size          | 8192    |
+------------------------------+---------+
# Enable query cache in my.cnf
query_cache_size = 268435456
query_cache_type = 1
query_cache_limit = 1048576

suPHP vs mod_php

suPHP – for each request the web server opens a new thread on behalf of that user

mod_php – every request is processed on web server behalf

Pros:
suPHP
– the web server can be … threaded safe, and it is separated from php
– can be isolated based on user/environment

mod_php
– you can use php_value and other php settings right from .htaccess
– it is way faster than suPHP

Cons:
suPHP
– you can’t use php_value and other php settings from .htaccess
– slower
– higher response time
– higher CPU load

mod_php
– PHP safe mode it is not quite safe
– higher memory consumption than suPHP
– can’t be isolated based on user/environment