Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
29.73% covered (danger)
29.73%
11 / 37
44.44% covered (danger)
44.44%
4 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
Critical_CSS
29.73% covered (danger)
29.73%
11 / 37
44.44% covered (danger)
44.44%
4 / 9
104.83
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 is_ready
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_change_output_action_names
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 is_available
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setup
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 register_data_sync
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 get_slug
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 display_critical_css
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
56
 update_total_problem_count
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace Automattic\Jetpack_Boost\Modules\Optimizations\Critical_CSS;
4
5use Automattic\Jetpack\Schema\Schema;
6use Automattic\Jetpack\WP_JS_Data_Sync\Data_Sync;
7use Automattic\Jetpack_Boost\Admin\Regenerate_Admin_Notice;
8use Automattic\Jetpack_Boost\Contracts\Changes_Output_After_Activation;
9use Automattic\Jetpack_Boost\Contracts\Feature;
10use Automattic\Jetpack_Boost\Contracts\Has_Data_Sync;
11use Automattic\Jetpack_Boost\Contracts\Needs_To_Be_Ready;
12use Automattic\Jetpack_Boost\Contracts\Optimization;
13use Automattic\Jetpack_Boost\Data_Sync\Critical_CSS_Meta_Entry;
14use Automattic\Jetpack_Boost\Lib\Critical_CSS\Admin_Bar_Compatibility;
15use Automattic\Jetpack_Boost\Lib\Critical_CSS\Critical_CSS_Invalidator;
16use Automattic\Jetpack_Boost\Lib\Critical_CSS\Critical_CSS_State;
17use Automattic\Jetpack_Boost\Lib\Critical_CSS\Critical_CSS_Storage;
18use Automattic\Jetpack_Boost\Lib\Critical_CSS\Data_Sync\Data_Sync_Schema;
19use Automattic\Jetpack_Boost\Lib\Critical_CSS\Data_Sync_Actions\Regenerate_CSS;
20use Automattic\Jetpack_Boost\Lib\Critical_CSS\Data_Sync_Actions\Set_Provider_CSS;
21use Automattic\Jetpack_Boost\Lib\Critical_CSS\Data_Sync_Actions\Set_Provider_Error_Dismissed;
22use Automattic\Jetpack_Boost\Lib\Critical_CSS\Data_Sync_Actions\Set_Provider_Errors;
23use Automattic\Jetpack_Boost\Lib\Critical_CSS\Display_Critical_CSS;
24use Automattic\Jetpack_Boost\Lib\Critical_CSS\Generator;
25use Automattic\Jetpack_Boost\Lib\Critical_CSS\Source_Providers\Source_Providers;
26use Automattic\Jetpack_Boost\Lib\Premium_Features;
27
28class Critical_CSS implements Feature, Changes_Output_After_Activation, Optimization, Has_Data_Sync, Needs_To_Be_Ready {
29
30    /**
31     * Critical CSS storage class instance.
32     *
33     * @var Critical_CSS_Storage
34     */
35    protected $storage;
36
37    /**
38     * Critical CSS Provider Paths.
39     *
40     * @var Source_Providers
41     */
42    protected $paths;
43
44    /**
45     * Prepare module. This is run irrespective of the module activation status.
46     */
47    public function __construct() {
48        $this->storage = new Critical_CSS_Storage();
49        $this->paths   = new Source_Providers();
50    }
51
52    /**
53     * Check if the module is ready and already serving critical CSS.
54     *
55     * @return bool
56     */
57    public function is_ready() {
58        return ( new Critical_CSS_State() )->is_generated();
59    }
60
61    /**
62     * Get the action names that will be triggered when the module is ready and serving critical CSS.
63     *
64     * @return string[]
65     */
66    public static function get_change_output_action_names() {
67        return array( 'jetpack_boost_critical_css_invalidated', 'jetpack_boost_critical_css_generated' );
68    }
69
70    public static function is_available() {
71        return true !== Premium_Features::has_feature( Premium_Features::CLOUD_CSS );
72    }
73
74    /**
75     * This is only run if Critical CSS module has been activated.
76     */
77    public function setup() {
78        add_action( 'wp', array( $this, 'display_critical_css' ) );
79        add_filter( 'jetpack_boost_total_problem_count', array( $this, 'update_total_problem_count' ) );
80
81        Generator::init();
82        Critical_CSS_Invalidator::init();
83        CSS_Proxy::init();
84
85        // Admin Notices
86        Regenerate_Admin_Notice::init();
87
88        return true;
89    }
90
91    public function register_data_sync( Data_Sync $instance ) {
92        $instance->register( 'critical_css_state', Data_Sync_Schema::critical_css_state() );
93        $instance->register( 'critical_css_meta', Data_Sync_Schema::critical_css_meta(), new Critical_CSS_Meta_Entry() );
94        $instance->register( 'critical_css_suggest_regenerate', Data_Sync_Schema::critical_css_suggest_regenerate() );
95        $instance->register_action( 'critical_css_state', 'request-regenerate', Schema::as_void(), new Regenerate_CSS() );
96        $instance->register_action( 'critical_css_state', 'set-provider-css', Data_Sync_Schema::critical_css_set_provider(), new Set_Provider_CSS() );
97        $instance->register_action( 'critical_css_state', 'set-provider-errors', Data_Sync_Schema::critical_css_set_provider_errors(), new Set_Provider_Errors() );
98        $instance->register_action( 'critical_css_state', 'set-provider-errors-dismissed', Data_Sync_Schema::critical_css_set_provider_errors_dismissed(), new Set_Provider_Error_Dismissed() );
99    }
100
101    public static function get_slug() {
102        return 'critical_css';
103    }
104
105    public function display_critical_css() {
106        // Don't look for Critical CSS in the dashboard.
107        if ( is_admin() ) {
108            return;
109        }
110        // Don't display Critical CSS when generating Critical CSS.
111        if ( Generator::is_generating_critical_css() ) {
112            return;
113        }
114
115        // Don't show Critical CSS in customizer previews.
116        if ( is_customize_preview() ) {
117            return;
118        }
119
120        // Get the Critical CSS to show.
121        $critical_css = $this->paths->get_current_request_css();
122        if ( ! $critical_css ) {
123            return;
124        }
125
126        if ( defined( 'WP_DEBUG' ) && WP_DEBUG === true ) {
127            $critical_css = "/* Critical CSS Key: {$this->paths->get_current_critical_css_key()} */\n" . $critical_css;
128        }
129
130        $display = new Display_Critical_CSS( $critical_css );
131        add_action( 'wp_head', array( $display, 'display_critical_css' ), 0 );
132        add_filter( 'style_loader_tag', array( $display, 'asynchronize_stylesheets' ), 10, 4 );
133        add_action( 'wp_footer', array( $display, 'onload_flip_stylesheets' ) );
134
135        // Ensure admin bar compatibility.
136        Admin_Bar_Compatibility::init();
137    }
138
139    public function update_total_problem_count( $count ) {
140        return ( new Critical_CSS_State() )->has_errors() ? ++$count : $count;
141    }
142}