Skip to content

Instantly share code, notes, and snippets.

@kish2011
Forked from Shelob9/README.MD
Created January 3, 2017 00:32
Show Gist options
  • Save kish2011/b36c83f1d5367e09404508681be11c72 to your computer and use it in GitHub Desktop.
Save kish2011/b36c83f1d5367e09404508681be11c72 to your computer and use it in GitHub Desktop.

Combine, Minify and Inline CSS In WordPress, in the correct order

Installation

Use copypasta to add to a sub-dir of mu-plugins or use Composer:

  "require": {
    "shelob9/css-inliner" : "*"
  }

and

  "repositories": [
    {
      "type": "vcs",
      "url": "https://gist.github.com/Shelob9/4abd39c57e31c1a37d689118236be729.git"
    }
  ]

Example Usage:

In your main mu-plugin or whatever

  add_action( 'init', function(){
    if( ! is_admin() && ! wp_doing_ajax() ){
      include  WP_CONTENT_DIR  . '/mu-plugins/css-inliner/init.php';

      add_filter( 'josh_css_minifier_styles', function(){
        return [
          'tm_clicktotweet',
          'edd-styles',
          'edd_acp_frontend_css',
          'edd-sl-styles',
          'edd-recurring',
        ];

      });
    }
  });
{
"name": "shelob9/css-inliner",
"license": "GPL v2+",
"type": "wordpress-muplugin",
"repositories": [
{
"type": "composer",
"url": "http://wpackagist.org"
}
],
"require": {
"composer/installers" : "~1.0"
}
}
<?php
class Josh_CSS_Inliner {
protected $styles;
protected $prepared;
public function __construct( array $styles = array() )
{
$this->styles = $styles;
if( ! empty( $this->styles ) ){
$this->set_prepared();
if( ! empty( $this->prepared ) ){
add_action( 'wp_head', [ $this, 'wp_head' ] );
}
}
}
public function wp_head()
{
printf( "<style id='%s-inline-css' class='cfdc-inlined' type='text/css'>\n%s\n</style>\n", esc_attr( $this->cache_key() ), $this->prepared );
}
protected function cache_key() : string
{
return md5( implode( ',', array_values( $this->styles ) ) );
}
protected function set_prepared()
{
$key = $this->cache_key();
if( ! empty( $_prepared = get_transient( $key ) ) ){
$this->prepared = $_prepared;
}else{
$this->prepared = $this->process();
set_transient( $key, $this->prepared, WEEK_IN_SECONDS );
}
}
protected function process() : string
{
global $wp_styles;
foreach ( $this->styles as $style ){
$key = array_search( $style, $wp_styles->queue );
if( false !== $key ){
$ordered[ $key ] = str_replace( WP_CONTENT_URL, untrailingslashit( WP_CONTENT_DIR ), $wp_styles->registered[ $style ]->src );
unset( $wp_styles->queue[ $key ] );
unset( $wp_styles->registered[ $style ] );
}
}
ksort( $ordered );
ob_start();
foreach ( $ordered as $path ){
if( file_exists( $path ) ){
include $path;
}
}
$concat = ob_get_clean();
if( ! empty( $concat ) ){
return josh_minify_css($concat);
}else{
return '';
}
}
}
<?php
//https://gist.githubusercontent.com/tovic/d7b310dea3b33e4732c0/raw/a2aec8653a893c42f4cf22662e775814c2d91f0a/php-html-css-js-minifier.php
// Helper function(s) ...
define('X', "\x1A"); // a placeholder character
$SS = '"(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'';
$CC = '\/\*[\s\S]*?\*\/';
$CH = '<\!--[\s\S]*?-->';
function josh__minify_x($input) {
return str_replace(array("\n", "\t", ' '), array(X . '\n', X . '\t', X . '\s'), $input);
}
function josh__minify_v($input) {
return str_replace(array(X . '\n', X . '\t', X . '\s'), array("\n", "\t", ' '), $input);
}
/**
* =======================================================
* CSS MINIFIER
* =======================================================
* -- CODE: ----------------------------------------------
*
* echo josh_minify_css(file_get_contents('test.css'));
*
* -------------------------------------------------------
*/
function josh__minifiy_css($input) {
// Keep important white-space(s) in `calc()`
if(stripos($input, 'calc(') !== false) {
$input = preg_replace_callback('#\b(calc\()\s*(.*?)\s*\)#i', function($m) {
return $m[1] . preg_replace('#\s+#', X . '\s', $m[2]) . ')';
}, $input);
}
// Minify ...
return preg_replace(
array(
// Fix case for `#foo [bar="baz"]` and `#foo :first-child` [^1]
'#(?<![,\{\}])\s+(\[|:\w)#',
// Fix case for `[bar="baz"] .foo` and `@media (foo: bar) and (baz: qux)` [^2]
'#\]\s+#', '#\b\s+\(#', '#\)\s+\b#',
// Minify HEX color code ... [^3]
'#\#([\da-f])\1([\da-f])\2([\da-f])\3\b#i',
// Remove white-space(s) around punctuation(s) [^4]
'#\s*([~!@*\(\)+=\{\}\[\]:;,>\/])\s*#',
// Replace zero unit(s) with `0` [^5]
'#\b(?:0\.)?0([a-z]+\b|%)#i',
// Replace `0.6` with `.6` [^6]
'#\b0+\.(\d+)#',
// Replace `:0 0`, `:0 0 0` and `:0 0 0 0` with `:0` [^7]
'#:(0\s+){0,3}0(?=[!,;\)\}]|$)#',
// Replace `background(?:-position)?:(0|none)` with `background$1:0 0` [^8]
'#\b(background(?:-position)?):(0|none)\b#i',
// Replace `(border(?:-radius)?|outline):none` with `$1:0` [^9]
'#\b(border(?:-radius)?|outline):none\b#i',
// Remove empty selector(s) [^10]
'#(^|[\{\}])(?:[^\{\}]+)\{\}#',
// Remove the last semi-colon and replace multiple semi-colon(s) with a semi-colon [^11]
'#;+([;\}])#',
// Replace multiple white-space(s) with a space [^12]
'#\s+#'
),
array(
// [^1]
X . '\s$1',
// [^2]
']' . X . '\s', X . '\s(', ')' . X . '\s',
// [^3]
'#$1$2$3',
// [^4]
'$1',
// [^5]
'0',
// [^6]
'.$1',
// [^7]
':0',
// [^8]
'$1:0 0',
// [^9]
'$1:0',
// [^10]
'$1',
// [^11]
'$1',
// [^12]
' '
),
$input);
}
function josh_minify_css($input) {
if( ! $input = trim($input)) return $input;
global $SS, $CC;
// Keep important white-space(s) between comment(s)
$input = preg_replace('#(' . $CC . ')\s+(' . $CC . ')#', '$1' . X . '\s$2', $input);
// Create chunk(s) of string(s), comment(s) and text
$input = preg_split('#(' . $SS . '|' . $CC . ')#', $input, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
$output = "";
foreach($input as $v) {
if(trim($v) === "") continue;
if(
($v[0] === '"' && substr($v, -1) === '"') ||
($v[0] === "'" && substr($v, -1) === "'") ||
(strpos($v, '/*') === 0 && substr($v, -2) === '*/')
) {
// Remove if not detected as important comment ...
if($v[0] === '/' && strpos($v, '/*!') !== 0) continue;
$output .= $v; // String or comment ...
} else {
$output .= josh__minifiy_css($v);
}
}
// Remove quote(s) where possible ...
$output = preg_replace(
array(
// '#(' . $CC . ')|(?<!\bcontent\:|[\s\(])([\'"])([a-z_][-\w]*?)\2#i',
'#(' . $CC . ')|\b(url\()([\'"])([^\s]+?)\3(\))#i'
),
array(
// '$1$3',
'$1$2$4$5'
),
$output);
return josh__minify_v($output);
}
<?php
add_action( 'wp_print_styles', function() {
$styles_to_inline = apply_filters( 'josh_css_minifier_styles', [ ] );
if ( empty( $styles_to_inline ) ) {
return;
}
include_once __DIR__ . '/functions.php';
include_once __DIR__ . '/css-inliner.php';
new Josh_CSS_Inliner( $styles_to_inline );
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment