File "class-defer-js.php"
Full Path: /home/theinspectionboy/public_html/suffolk/includes/class-defer-js.php
File size: 5.12 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/**
* Class and methods to defer JS.
*
* @link https://ewww.io/swis/
* @package SWIS_Performance
*/
namespace SWIS;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Enables plugin to filter JS tags and defer them.
*/
final class Defer_JS extends Page_Parser {
/**
* A list of user-defined exclusions, populated by validate_user_exclusions().
*
* @access protected
* @var array $user_exclusions
*/
protected $user_exclusions = array();
/**
* Register actions and filters for JS Defer.
*/
function __construct() {
if ( ! $this->get_option( 'defer_js' ) ) {
return;
}
parent::__construct();
$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
$uri = add_query_arg( null, null );
$this->debug_message( "request uri is $uri" );
/**
* Allow pre-empting JS defer by page.
*
* @param bool Whether to skip parsing the page.
* @param string $uri The URL of the page.
*/
if ( apply_filters( 'swis_skip_js_defer_by_page', false, $uri ) ) {
return;
}
// Start an output buffer before any output starts.
add_filter( $this->prefix . 'filter_page_output', array( $this, 'filter_page_output' ) );
// Overrides for user exclusions.
add_filter( 'swis_skip_js_defer', array( $this, 'skip_js_defer' ), 10, 2 );
// Get all the script urls and rewrite them (if enabled).
add_filter( 'script_loader_tag', array( $this, 'defer_scripts' ), 20 );
add_filter( 'swis_elements_script_tag', array( $this, 'defer_scripts' ) );
$this->validate_user_exclusions();
}
/**
* Validate the user-defined exclusions.
*/
function validate_user_exclusions() {
$user_exclusions = $this->get_option( 'defer_js_exclude' );
if ( ! empty( $user_exclusions ) ) {
if ( is_string( $user_exclusions ) ) {
$user_exclusions = array( $user_exclusions );
}
if ( is_array( $user_exclusions ) ) {
foreach ( $user_exclusions as $exclusion ) {
if ( ! is_string( $exclusion ) ) {
continue;
}
$this->user_exclusions[] = $exclusion;
}
}
}
$this->user_exclusions[] = '/js/dist/i18n.';
$this->user_exclusions[] = '/js/dist/hooks.';
$this->user_exclusions[] = '/js/tinymce/';
$this->user_exclusions[] = '/js/dist/vendor/lodash.';
$this->user_exclusions[] = '/js/domaincheck';
$this->user_exclusions[] = 'facetwp/assets/js/dist/front';
}
/**
* Parse page content looking for jQuery script tag to rewrite.
*
* @param string $content The HTML content to parse.
* @return string The filtered HTML content.
*/
function filter_page_output( $content ) {
$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
if ( $this->is_json( $content ) ) {
return $content;
}
if ( $this->get_option( 'defer_jquery_safe' ) && false === strpos( $content, 'jQuery' ) ) {
preg_match( "#<script\s+(?:type='text/javascript'\s+)?src='[^']+?/jquery(\.min)?\.js[^']*?'[^>]*?>#is", $content, $jquery_tags );
if ( ! empty( $jquery_tags[0] ) && false === strpos( $jquery_tags[0], 'defer' ) && false === strpos( $jquery_tags[0], 'async' ) ) {
$deferred_jquery = str_replace( '>', ' defer>', $jquery_tags[0] );
if ( $deferred_jquery && $deferred_jquery !== $jquery_tags[0] ) {
$content = str_replace( $jquery_tags[0], $deferred_jquery, $content );
}
}
}
return $content;
}
/**
* Exclude JS from being processed based on user specified list.
*
* @param boolean $skip Whether SWIS should skip processing.
* @param string $tag The script tag HTML.
* @return boolean True to skip the resource, unchanged otherwise.
*/
function skip_js_defer( $skip, $tag ) {
if ( $this->user_exclusions ) {
foreach ( $this->user_exclusions as $exclusion ) {
if ( false !== strpos( $tag, $exclusion ) ) {
$this->debug_message( __METHOD__ . "(); user excluded $tag via $exclusion" );
return true;
}
}
}
return $skip;
}
/**
* Rewrites a script tag to be deferred.
*
* @param string $tag URL to the script.
* @return string The deferred version of the resource, if it was allowed.
*/
function defer_scripts( $tag ) {
$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
if ( ! $this->is_frontend() ) {
return $tag;
}
if ( false !== strpos( $tag, 'async' ) ) {
return $tag;
}
if ( false !== strpos( $tag, 'defer' ) ) {
return $tag;
}
if ( false !== strpos( $tag, 'jquery.js' ) ) {
return $tag;
}
if ( false !== strpos( $tag, 'jquery.min.js' ) ) {
return $tag;
}
if ( false !== strpos( $tag, 'asset-clean' ) ) {
return $tag;
}
if ( apply_filters( 'swis_skip_js_defer', false, $tag ) ) {
return $tag;
}
if ( false !== strpos( $tag, 'lazysizes.min.js' ) ) {
return str_replace( '></script', ' async></script', $tag );
}
$this->debug_message( trim( $tag ) );
// If we don't have the ending script tag, usually from \SWIS\Element_Filter.
if ( false === strpos( $tag, '</script>' ) ) {
$deferred_tag = str_replace( '>', ' defer>', $tag );
} else {
$deferred_tag = str_replace( '></script', ' defer></script', $tag );
}
if ( $deferred_tag && $deferred_tag !== $tag ) {
$this->debug_message( trim( $deferred_tag ) );
return $deferred_tag;
}
$this->debug_message( 'unchanged' );
return $tag;
}
}