File "class-defer-css.php"
Full Path: /home/theinspectionboy/public_html/suffolk/includes-20250622113618/class-defer-css.php
File size: 7.22 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/**
* Class and methods to defer CSS and include critical CSS.
*
* @link https://ewww.io/swis/
* @package SWIS_Performance
*/
namespace SWIS;
use MatthiasMullie\Minify;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Enables plugin to filter CSS tags and defer them.
*/
final class Defer_CSS 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 CSS Defer.
*/
function __construct() {
if ( $this->get_option( 'critical_css' ) ) {
add_filter( 'wp_head', array( $this, 'inline_critical_css' ), 1 );
add_filter( 'swis_filter_page_output', array( $this, 'inline_critical_js' ) );
}
if ( ! $this->get_option( 'defer_css' ) ) {
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 CSS defer by page.
*
* @param bool Whether to skip parsing the page.
* @param string $uri The URL of the page.
*/
if ( apply_filters( 'swis_skip_css_defer_by_page', false, $uri ) ) {
return;
}
// Overrides for user exclusions.
add_filter( 'swis_skip_css_defer', array( $this, 'skip_css_defer' ), 10, 2 );
if ( ! defined( 'SWIS_KEEP_DASHICONS' ) || ! SWIS_KEEP_DASHICONS ) {
// Make sure dashicons are not loaded on front-end for visitors.
add_action( 'wp_enqueue_scripts', array( $this, 'dequeue_dashicons' ), 11 );
}
// Get all the script/css urls and rewrite them (if enabled).
add_filter( 'style_loader_tag', array( $this, 'defer_css' ), 20 );
add_filter( 'swis_elements_link_tag', array( $this, 'defer_css' ) );
$this->validate_user_exclusions();
}
/**
* Is there a place for this (or maybe also for emoji)?
*/
function dequeue_dashicons() {
if ( ! is_user_logged_in() ) {
wp_deregister_style( 'dashicons' );
}
}
/**
* Validate the user-defined exclusions.
*/
function validate_user_exclusions() {
$user_exclusions = $this->get_option( 'defer_css_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;
}
}
}
}
/**
* Exclude CSS from being processed based on user specified list.
*
* @param boolean $skip Whether SWIS should skip processing.
* @param string $tag The CSS link tag HTML.
* @return boolean True to skip the resource, unchanged otherwise.
*/
function skip_css_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 CSS link tag to be deferred.
*
* @param string $tag HTML for the CSS resource.
* @return string The deferred version of the resource, if it was allowed.
*/
function defer_css( $tag ) {
$this->debug_message( '<b>' . __METHOD__ . '()</b>' );
if ( ! $this->is_frontend() ) {
return $tag;
}
if ( strpos( $tag, 'admin-bar.min.css' ) ) {
return $tag;
}
if ( false !== strpos( $tag, 'async' ) ) {
return $tag;
}
if ( false !== strpos( $tag, 'defer' ) ) {
return $tag;
}
if ( false !== strpos( $tag, 'asset-clean' ) ) {
return $tag;
}
if ( apply_filters( 'swis_skip_css_defer', false, $tag ) ) {
return $tag;
}
if ( false === strpos( $tag, 'preload' ) && false === strpos( $tag, 'data-swis' ) ) {
$this->debug_message( trim( $tag ) );
$async_tag = str_replace( " media='all'", " media='print' data-swis='loading' onload='this.media=\"all\";this.dataset.swis=\"loaded\"'", $tag );
if ( $tag === $async_tag ) {
$async_tag = str_replace( " media=''", " media='print' data-swis='loading' onload='this.media=\"all\";this.dataset.swis=\"loaded\"'", $tag );
}
// Run it through for preloading if possible.
$async_tag = $this->preload_css( $async_tag, $tag );
// If we got a new tag, let's go!
if ( $tag !== $async_tag ) {
$this->debug_message( trim( $async_tag ) );
return $async_tag . '<noscript>' . trim( $tag ) . "</noscript>\n";
}
}
return $tag;
}
/**
* Modify an async link/CSS tag for preloading.
*
* @param string $async_tag The async version of a <link...> tag.
* @param string $tag The original version of a <link...> tag.
* @return string The tag with a preloader added, if applicable.
*/
function preload_css( $async_tag, $tag ) {
if ( false !== strpos( $tag, "rel='stylesheet'" ) ) {
$allowed_to_preload = array(
'avada-styles/', // Avada dynamic CSS.
'bb-plugin/cache/', // Beaver Builder dynamic CSS.
'bb-plugin/css/', // Beaver Builder plugin CSS.
'brizy/public/', // Brizy dynamic CSS.
'brizy-pro/public/', // Brizy Pro dynamic CSS.
'dist/block-library/', // Gutenberg (stock WP) CSS.
'build/block-library/', // Gutenberg (plugin) CSS.
'elementor/assets/css', // Elementor plugin stock CSS.
'elementor/css', // Elementor dynamic CSS.
'elementor-pro/assets/css', // Elementor Pro stock CSS.
'fusion-builder/', // Avada Builder stock CSS.
'fusion-core/', // Avada Core stock CSS.
'fusion-styles/', // Avada dynamic CSS.
'generateblocks/style', // GenerateBlocks dynamic CSS.
'component-framework/oxygen', // Oxygen plugin CSS.
'/oxygen/css/', // Oxygen dynamic CSS.
'siteorigin-panels/css/', // SiteOrigin plugin CSS.
'td-composer/assets', // TagDiv Composer (builder from Newspaper Theme).
'wp-content/themes/', // Theme CSS.
);
$allowed_to_preload = apply_filters( 'swis_defer_css_preload_list', $allowed_to_preload );
foreach ( $allowed_to_preload as $allowed ) {
if ( empty( $allowed ) ) {
continue;
}
if ( false !== strpos( $tag, $allowed ) ) {
$async_tag = str_replace( array( " rel='stylesheet'", " id='" ), array( " rel='preload' as='style'", " data-id='" ), $tag ) . $async_tag;
}
}
}
return $async_tag;
}
/**
* Insert cricital CSS rules in to the header to prevent FOUC.
*/
function inline_critical_css() {
$minifier = new Minify\CSS( $this->get_option( 'critical_css' ) );
echo "<style id='swis-critical-css'>\n" . wp_kses( $minifier->minify(), 'strip' ) . "\n</style>\n";
}
/**
* Insert the JS to remove the Critical CSS section once all the CSS has loaded.
*
* @param string $buffer The HTML content of the page.
* @return string The altered HTML.
*/
function inline_critical_js( $buffer ) {
$script_name = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? 'critical-css-remove.js' : 'critical-css-remove.min.js';
$inline_script = file_get_contents( SWIS_PLUGIN_PATH . 'assets/' . $script_name );
return preg_replace( '#</body>#i', '<script>' . $inline_script . '</script></body>', $buffer, 1 );
}
}