Inline CSS on first load of a WordPress site

On a visitors first page load on your site, the CSS file will be inlined. This allows the web page to start rendering without waiting for a second HTTP request, improving the perceived performance of the page.

As external files are cached, the CSS file also loads asynchronously. On subsequent page loads, the CSS file can be loaded as it normally would it will be cached by the visitors browser and load immediately.

<?php

class PWCC_Theme_Assets {

  const CSS_VERSION = '20150526-04';
  const JS_VERSION = '20150526-01';
  const JS_GLOBAL = 'PWCC';

  private $loadCss = array();

  function __construct() {
    add_action( 'wp_enqueue_scripts', array( $this, 'action_enqueue_assets' ) );
    add_action( 'wp_print_styles', array( $this, 'action_inline_styles' ) );
  }

  function action_enqueue_assets() {
    global $wp_styles;

    $theme_path = get_stylesheet_directory();
    $theme_uri = get_stylesheet_directory_uri();

    $assets_path = $theme_path . "/assets";
    $assets_uri = $theme_uri . "/assets";

    // register the CSS file as is normally done in WordPress.
    wp_register_style(
      'pwcc-styles',
      $assets_uri . '/css/style.min.css',
      null,
      self::CSS_VERSION
    );

    if ( $this->css_cached( 'pwcc-styles' ) ) {
      // enqueue as normal (file is already cached)
      wp_enqueue_style( 'pwcc-styles' );
    }
    else {
      // prepare for script to be inlined (file is not cached)
      $this->loadCss[] = $wp_styles->registered['pwcc-styles'];
    }
  }

  function action_inline_styles() {
    global $wp_styles;

    $theme_path = get_stylesheet_directory();
    $theme_uri = get_stylesheet_directory_uri();

    $assets_path = $theme_path . "/assets";
    $assets_uri = $theme_uri . "/assets";

    if ( 0 === count( $this->loadCss ) ) {
      // there is no work to do.
      return;
    }

    // refer: https://github.com/filamentgroup/loadCSS
    echo "<!--\nloadCSS: load a CSS file asynchronously.\n";
    echo "[c]2014 @scottjehl, Filament Group, Inc.\n";
    echo "Licensed MIT -->\n";

    echo '<script>';
    echo self::JS_GLOBAL . '=window.' . self::JS_GLOBAL . '||{};';
    echo '!function(a){var b=a.document,c=a.' . self::JS_GLOBAL . ';c.loadCSS=function(a,c,d,e){"use strict";var f=b.createElement("link"),g=c||b.getElementsByTagName("script")[0],h=b.styleSheets;return f.rel="stylesheet",f.href=a,f.media="only x",e&&(f.onload=e),g.parentNode.insertBefore(f,g),f.onloadcssdefined=function(b){for(var c,d=0;d<h.length;d++)h[d].href&&h[d].href.indexOf(a)>-1&&(c=!0);c?b():setTimeout(function(){f.onloadcssdefined(b)})},f.onloadcssdefined(function(){f.media=d||"all"}),f}}(window);';
    echo '</script>' . "\n";

    // loop through each file to be inlined
    foreach ( $this->loadCss as $asset ) {
      $asset_file = str_replace( $assets_uri, $assets_path, $asset->src );
      echo '<style id="' . $asset->handle . '-css">';
      readfile( $asset_file );
      echo '</style>' . "\n";
      //load asynchronously too
      $this->set_css_cached( $asset );
    }

  }

  function css_cached( $asset_name ) {
    // Apply MD5 to asset name and version to ensure only valid
    // value for a cookie are applied.
    $name = "pwcc_csscached_" . md5( $asset_name );
    $value = md5( self::CSS_VERSION );

    if ( isset( $_COOKIE[$name] ) && ( $value == $_COOKIE[$name] ) ) {
      // cookie set, value correct, file is cached
      return true;
    }
    else {
      // file is not cached
      return false;
    }
  }

  function set_css_cached( $asset ) {
    $asset_name = $asset->handle;
    // Apply MD5 to asset name and version to ensure only valid
    // value for a cookie are applied.
    $name = "pwcc_csscached_" . md5( $asset_name );
    $value = md5( self::CSS_VERSION );

    // add the version cache-busting query string to the URL
    $src = add_query_arg( array( 'ver' => $asset->ver ), $asset->src );

    // filter the source as would happen automatically by WordPress
    // this ensures the URL altered by any CDN plugins.
    $src = apply_filters( 'style_loader_src', $src, $asset->handle );
    echo "<script>";
    // load the file
    echo self::JS_GLOBAL . ".loadCSS( '$src' );";
    // set the cookie to record the file is cached.
    echo "document.cookie = '$name=$value; path=/';";
    echo "</script>\n";
  }

}
new PWCC_Theme_Assets();

WordPress and front end web developer