$_value ) { global ${$_option}; ${$_option} = $_value; } $this->run(); } public function run() { global $ao_css_defer; global $ao_ccss_deferjquery; global $ao_ccss_key; // add all filters to do CCSS if key present. if ( $ao_css_defer && isset( $ao_ccss_key ) && ! empty( $ao_ccss_key ) ) { // Set AO behavior: disable minification to avoid double minifying and caching. add_filter( 'autoptimize_filter_css_critcss_minify', '__return_false' ); add_filter( 'autoptimize_filter_css_defer_inline', array( $this, 'ao_ccss_frontend' ), 10, 1 ); // Add the action to enqueue jobs for CriticalCSS cron. add_action( 'autoptimize_action_css_hash', array( 'autoptimizeCriticalCSSEnqueue', 'ao_ccss_enqueue' ), 10, 1 ); // conditionally add the filter to defer jquery and others. if ( $ao_ccss_deferjquery ) { add_filter( 'autoptimize_html_after_minify', array( $this, 'ao_ccss_defer_jquery' ), 11, 1 ); } // Order paths by length, as longest ones have greater priority in the rules. if ( ! empty( $ao_ccss_rules['paths'] ) ) { $keys = array_map( 'strlen', array_keys( $ao_ccss_rules['paths'] ) ); array_multisort( $keys, SORT_DESC, $ao_ccss_rules['paths'] ); } // Add an array with default WordPress's conditional tags // NOTE: these tags are sorted. global $ao_ccss_types; $ao_ccss_types = $this->get_ao_ccss_core_types(); // Extend conditional tags on plugin initalization. add_action( apply_filters( 'autoptimize_filter_ccss_extend_types_hook', 'init' ), array( $this, 'ao_ccss_extend_types' ) ); } } public function ao_ccss_frontend( $inlined ) { // Apply CriticalCSS to frontend pages // Attach types and settings arrays. global $ao_ccss_types; global $ao_ccss_rules; global $ao_ccss_additional; global $ao_ccss_loggedin; global $ao_ccss_debug; global $ao_ccss_keyst; $no_ccss = ''; // Only if keystatus is OK and option to add CCSS for logged on users is on or user is not logged in. if ( ( $ao_ccss_keyst && 2 == $ao_ccss_keyst ) && ( $ao_ccss_loggedin || ! is_user_logged_in() ) ) { // Check for a valid CriticalCSS based on path to return its contents. $req_path = strtok( $_SERVER['REQUEST_URI'], '?' ); if ( ! empty( $ao_ccss_rules['paths'] ) ) { foreach ( $ao_ccss_rules['paths'] as $path => $rule ) { // explicit match OR partial match if MANUAL rule. if ( $req_path == $path || urldecode( $req_path ) == $path || ( false == $rule['hash'] && false != $rule['file'] && strpos( $req_path, str_replace( site_url(), '', $path ) ) !== false ) ) { if ( file_exists( AO_CCSS_DIR . $rule['file'] ) ) { $_ccss_contents = file_get_contents( AO_CCSS_DIR . $rule['file'] ); if ( 'none' != $_ccss_contents ) { if ( $ao_ccss_debug ) { $_ccss_contents = '/* PATH: ' . $path . ' hash: ' . $rule['hash'] . ' file: ' . $rule['file'] . ' */ ' . $_ccss_contents; } return apply_filters( 'autoptimize_filter_ccss_core_ccss', $_ccss_contents . $ao_ccss_additional ); } else { $no_ccss = 'none'; } } } } } // Check for a valid CriticalCSS based on conditional tags to return its contents. if ( ! empty( $ao_ccss_rules['types'] ) && 'none' !== $no_ccss ) { // order types-rules by the order of the original $ao_ccss_types array so as not to depend on the order in which rules were added. $ao_ccss_rules['types'] = array_replace( array_intersect_key( array_flip( $ao_ccss_types ), $ao_ccss_rules['types'] ), $ao_ccss_rules['types'] ); $is_front_page = is_front_page(); foreach ( $ao_ccss_rules['types'] as $type => $rule ) { if ( in_array( $type, $ao_ccss_types ) && file_exists( AO_CCSS_DIR . $rule['file'] ) ) { $_ccss_contents = file_get_contents( AO_CCSS_DIR . $rule['file'] ); if ( $is_front_page && 'is_front_page' == $type ) { if ( 'none' != $_ccss_contents ) { if ( $ao_ccss_debug ) { $_ccss_contents = '/* TYPES: ' . $type . ' hash: ' . $rule['hash'] . ' file: ' . $rule['file'] . ' */ ' . $_ccss_contents; } return apply_filters( 'autoptimize_filter_ccss_core_ccss', $_ccss_contents . $ao_ccss_additional ); } else { $no_ccss = 'none'; } } elseif ( strpos( $type, 'custom_post_' ) === 0 && ! $is_front_page ) { if ( get_post_type( get_the_ID() ) === substr( $type, 12 ) ) { if ( 'none' != $_ccss_contents ) { if ( $ao_ccss_debug ) { $_ccss_contents = '/* TYPES: ' . $type . ' hash: ' . $rule['hash'] . ' file: ' . $rule['file'] . ' */ ' . $_ccss_contents; } return apply_filters( 'autoptimize_filter_ccss_core_ccss', $_ccss_contents . $ao_ccss_additional ); } else { $no_ccss = 'none'; } } } elseif ( 0 === strpos( $type, 'template_' ) && ! $is_front_page ) { if ( is_page_template( substr( $type, 9 ) ) ) { if ( 'none' != $_ccss_contents ) { if ( $ao_ccss_debug ) { $_ccss_contents = '/* TYPES: ' . $type . ' hash: ' . $rule['hash'] . ' file: ' . $rule['file'] . ' */ ' . $_ccss_contents; } return apply_filters( 'autoptimize_filter_ccss_core_ccss', $_ccss_contents . $ao_ccss_additional ); } else { $no_ccss = 'none'; } } } elseif ( ! $is_front_page ) { // all "normal" conditional tags, core + woo + buddypress + edd + bbpress // but we have to remove the prefix for the non-core ones for them to function. $type = str_replace( array( 'woo_', 'bp_', 'bbp_', 'edd_' ), '', $type ); if ( function_exists( $type ) && call_user_func( $type ) ) { if ( 'none' != $_ccss_contents ) { if ( $ao_ccss_debug ) { $_ccss_contents = '/* TYPES: ' . $type . ' hash: ' . $rule['hash'] . ' file: ' . $rule['file'] . ' */ ' . $_ccss_contents; } return apply_filters( 'autoptimize_filter_ccss_core_ccss', $_ccss_contents . $ao_ccss_additional ); } else { $no_ccss = 'none'; } } } } } } } // Finally, inline the default CriticalCSS if any or else the entire CSS for the page // This also applies to logged in users if the option to add CCSS for logged in users has been disabled. if ( ! empty( $inlined ) && 'none' !== $no_ccss ) { return apply_filters( 'autoptimize_filter_ccss_core_ccss', $inlined . $ao_ccss_additional ); } else { add_filter( 'autoptimize_filter_css_inline', '__return_true' ); return; } } public function ao_ccss_defer_jquery( $in ) { // try to defer all JS (main goal being jquery.js as AO by default does not aggregate that). if ( ( ! is_user_logged_in() || $ao_ccss_loggedin ) && preg_match_all( '#(.*)#Usmi', $in, $matches, PREG_SET_ORDER ) ) { foreach ( $matches as $match ) { if ( ( ! preg_match( '//', $match[0] ) || preg_match( '/type\s*=\s*[\'"]?(?:text|application)\/(?:javascript|ecmascript)[\'"]?/i', $match[0] ) ) && '' !== $match[1] && ( false !== strpos( $match[1], 'jQuery' ) || false !== strpos( $match[1], '$' ) ) ) { // inline js that requires jquery, wrap deferring JS around it to defer it. $new_match = 'var aoDeferInlineJQuery=function(){' . $match[1] . '}; if (document.readyState === "loading") {document.addEventListener("DOMContentLoaded", aoDeferInlineJQuery);} else {aoDeferInlineJQuery();}'; $in = str_replace( $match[1], $new_match, $in ); } elseif ( '' === $match[1] && false !== strpos( $match[0], 'src=' ) && false === strpos( $match[0], 'defer' ) ) { // linked non-aggregated JS, defer it. $new_match = str_replace( '