Skip to content

Instantly share code, notes, and snippets.

@strsar
Last active October 1, 2020 14:34
Show Gist options
  • Save strsar/bc89920d5042fbec48402ff22e8c8e30 to your computer and use it in GitHub Desktop.
Save strsar/bc89920d5042fbec48402ff22e8c8e30 to your computer and use it in GitHub Desktop.
[WP] Wordpress - Clean and minify all markup
<?php defined('ABSPATH') or header('Location: /');
/**
* HTML document compression
*
* Clean and minify all markup
* Wrap `<!--wp-html-compression no compression-->` to skip over content
*/
class WP_HTML_Compression {
protected $compress_css = true; // Compress all inline styles
protected $compress_js = true; // May cause issues if inline js contains single line `//` comments
protected $remove_comments = true; // Remove all html comments
protected $tag_whitespace = false; // May cause spacing issues within content
protected $info_comment = false; // Add custom comment to bottom of document
protected $force_relative = false; // May break canonical tags (since they need to be absolute)
protected $html;
/**
* Construct
*/
public function __construct($html){
if(!empty($html)){
$this->parse_html($html);
}
}
/**
* Markup to string
*/
public function __toString(){
if(is_null($this->html)) {
return 'NULL';
}
return $this->html;
}
/**
* Add comment
*/
protected function bottom_comment($raw, $compressed){
return '';
}
/**
* Minify markup
*/
protected function minify_html($html){
$pattern = '/<(?<script>script).*?<\/script\s*>|<(?<style>style).*?<\/style\s*>|<!(?<comment>--).*?-->|<(?<tag>[\/\w.:-]*)(?:".*?"|\'.*?\'|[^\'">]+)*>|(?<text>((<[^!\/\w.:-])?[^<]*)+)|/si';
preg_match_all($pattern, $html, $matches, PREG_SET_ORDER);
$overriding = false;
$raw_tag = false;
$html = '';
foreach ($matches as $token){
$tag = (isset($token['tag'])) ? strtolower($token['tag']) : null;
$content = $token[0];
if(is_null($tag)){
if(!empty($token['script']) ){
if(!$overriding){
$strip = $this->compress_js;
}
}elseif( !empty($token['style']) ){
$strip = $this->compress_css;
}elseif($content == '<!--wp-html-compression no compression-->'){
$overriding = !$overriding;
// Don't print the comment
continue;
}elseif($this->remove_comments){
if(!$overriding && $raw_tag != 'textarea'){
// Remove any HTML comments, except MSIE conditional comments
$content = preg_replace('/<!--(?!\s*(?:\[if [^\]]+]|<!|>))(?:(?!-->).)*-->/s', '', $content);
}
}
}else{
if($tag == 'pre' || $tag == 'textarea'){
$raw_tag = $tag;
}elseif($tag == '/pre' || $tag == '/textarea'){
$raw_tag = false;
}else{
if($raw_tag || $overriding){
$strip = false;
}else{
$strip = true;
// Remove any empty attributes, except: action, alt, content, src or value
$content = preg_replace('/(\s+)(\w++(?<!\baction|\balt|\bcontent|\bsrc|\bvalue)="")/', '$1', $content);
// Remove any space before the end of self-closing XHTML tags, javaScript excluded
$content = str_replace(' />', '>', $content);
if($this->tag_whitespace) {
$html = str_replace('> <', '><', $html);
}
}
}
}
if($strip){
$content = $this->remove_white_space($content);
if($this->force_relative) {
$content = $this->relative_urls($content);
}
}
$html .= $content;
}
return $html;
}
/**
* Parse markup
*/
public function parse_html($html){
$this->html = $this->minify_html($html);
if($this->info_comment){
$this->html .= "\n" . $this->bottom_comment($html, $this->html);
}
}
/**
* Remove white space
*/
protected function remove_white_space($str){
$str = str_replace("\t", ' ', $str);
$str = str_replace("\n", '', $str);
$str = str_replace("\r", '', $str);
while(stristr($str, ' ')){
$str = str_replace(' ', ' ', $str);
}
return $str;
}
/**
* Make relative URLs
*/
protected function relative_urls($str){
$str = str_replace(home_url(), '', $str);
return $str;
}
}
// Start compression
function wp_html_compression_start(){
ob_start('wp_html_compression_finish');
}
// Finish compression
function wp_html_compression_finish($html){
return new WP_HTML_Compression($html);
}
// Run class
if(!is_admin() && !is_user_logged_in() && !is_feed()){
add_action('get_header', 'wp_html_compression_start');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment