Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 61
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
Source_Providers
0.00% covered (danger)
0.00%
0 / 61
0.00% covered (danger)
0.00%
0 / 7
650
0.00% covered (danger)
0.00%
0 / 1
 get_providers
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_provider_for_key
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 get_current_request_css_keys
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
20
 get_current_request_css
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 get_current_critical_css_key
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_provider_sources
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
72
 make_absolute_urls
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace Automattic\Jetpack_Boost\Lib\Critical_CSS\Source_Providers;
4
5use Automattic\Jetpack_Boost\Lib\Critical_CSS\Critical_CSS_Storage;
6use Automattic\Jetpack_Boost\Lib\Critical_CSS\Source_Providers\Providers\Archive_Provider;
7use Automattic\Jetpack_Boost\Lib\Critical_CSS\Source_Providers\Providers\Cornerstone_Provider;
8use Automattic\Jetpack_Boost\Lib\Critical_CSS\Source_Providers\Providers\Post_ID_Provider;
9use Automattic\Jetpack_Boost\Lib\Critical_CSS\Source_Providers\Providers\Provider;
10use Automattic\Jetpack_Boost\Lib\Critical_CSS\Source_Providers\Providers\Singular_Post_Provider;
11use Automattic\Jetpack_Boost\Lib\Critical_CSS\Source_Providers\Providers\Taxonomy_Provider;
12use Automattic\Jetpack_Boost\Lib\Critical_CSS\Source_Providers\Providers\WP_Core_Provider;
13
14class Source_Providers {
15
16    /**
17     * Variable used to cache the CSS string during the page request.
18     * This is here because `get_critical_css` is called multiple
19     * times in `style_loader_tag` hook (on each CSS file).
20     *
21     * @var null|false|string
22     */
23    protected $request_cached_css;
24
25    /**
26     * Stores the Critical CSS key used for rendering the current page if any.
27     *
28     * @var null|string
29     */
30    protected $current_critical_css_key;
31
32    /**
33     * List of all the Critical CSS Types.
34     *
35     * The order is important because searching for critical CSS will stop as soon as a value is found.
36     * So finding Critical CSS by post ID is attempted before searching for a common Singular Post critical CSS.
37     *
38     * @var Provider[]
39     */
40    protected $providers = array(
41        Cornerstone_Provider::class,
42        Post_ID_Provider::class,
43        WP_Core_Provider::class,
44        Singular_Post_Provider::class,
45        Archive_Provider::class,
46        Taxonomy_Provider::class,
47    );
48
49    public function get_providers() {
50        return $this->providers;
51    }
52
53    /**
54     * Returns the Provider which controls a given key.
55     */
56    public function get_provider_for_key( $key ) {
57        foreach ( $this->providers as $provider ) {
58            if ( $provider::owns_key( $key ) ) {
59                return $provider;
60            }
61        }
62
63        return null;
64    }
65
66    /**
67     * Get all critical CSS storage keys that are available for the current request.
68     * Caches the result.
69     *
70     * @return array
71     */
72    public function get_current_request_css_keys() {
73        static $keys = null;
74        if ( null !== $keys ) {
75            return $keys;
76        }
77
78        $keys = array();
79
80        foreach ( $this->providers as $provider ) {
81            $provider_keys = $provider::get_current_storage_keys();
82            if ( empty( $provider_keys ) ) {
83                continue;
84            }
85            $keys = array_merge( $keys, $provider_keys );
86        }
87
88        return $keys;
89    }
90
91    /**
92     * Get critical CSS for the current request.
93     *
94     * @return string|false
95     */
96    public function get_current_request_css() {
97        if ( null !== $this->request_cached_css ) {
98            return $this->request_cached_css;
99        }
100
101        $storage = new Critical_CSS_Storage();
102        $data    = $storage->get_css( $this->get_current_request_css_keys() );
103        if ( false === $data ) {
104            return false;
105        }
106
107        $this->request_cached_css       = $data['css'];
108        $this->current_critical_css_key = $data['key'];
109
110        return $this->request_cached_css;
111    }
112
113    public function get_current_critical_css_key() {
114        return $this->current_critical_css_key;
115    }
116
117    /**
118     * Get providers sources.
119     *
120     * @return array
121     */
122    public function get_provider_sources( $context_posts = array() ) {
123        $sources                        = array();
124        $flat_core_and_cornerstone_urls = array();
125
126        $wp_core_provider_urls = WP_Core_Provider::get_critical_source_urls( $context_posts );
127        foreach ( $wp_core_provider_urls as $urls ) {
128            $flat_core_and_cornerstone_urls = array_merge( $flat_core_and_cornerstone_urls, $urls );
129        }
130        $cornerstone_provider_urls = Cornerstone_Provider::get_critical_source_urls( $context_posts );
131        foreach ( $cornerstone_provider_urls as $urls ) {
132            $flat_core_and_cornerstone_urls = array_merge( $flat_core_and_cornerstone_urls, $urls );
133        }
134        $flat_core_and_cornerstone_urls = array_values( array_unique( $flat_core_and_cornerstone_urls ) );
135
136        foreach ( $this->get_providers() as $provider ) {
137            $provider_name = $provider::get_provider_name();
138
139            // For each provider,
140            // Gather a list of URLs that are going to be used as Critical CSS source.
141            foreach ( $provider::get_critical_source_urls( $context_posts ) as $group => $urls ) {
142                if ( empty( $urls ) ) {
143                    continue;
144                }
145
146                // This removes core and cornerstone URLs from the list of URLs,
147                // so they don't belong to two separate groups.
148                if ( ! in_array( $provider, array( WP_Core_Provider::class, Cornerstone_Provider::class ), true ) ) {
149                    $urls = array_values( array_diff( $urls, $flat_core_and_cornerstone_urls ) );
150                }
151
152                if ( empty( $urls ) ) {
153                    continue;
154                }
155
156                $urls = $this->make_absolute_urls( $urls );
157
158                $key = $provider_name . '_' . $group;
159
160                // For each provider
161                // Track the state and errors in a state array.
162                $sources[] = array(
163                    'key'           => $key,
164                    'label'         => $provider::describe_key( $key ),
165                    /**
166                     * Filters the URLs used by Critical CSS for each provider.
167                     *
168                     * @param array $urls The list of URLs to be used to generate critical CSS
169                     * @param string $provider The provider name.
170                     * @since   1.0.0
171                     */
172                    'urls'          => apply_filters( 'jetpack_boost_critical_css_urls', $urls, $provider ),
173                    'success_ratio' => $provider::get_success_ratio(),
174                );
175            }
176        }
177
178        /**
179         * Filters the list of Critical CSS source providers.
180         *
181         * @param array $sources The list of Critical CSS source providers.
182         * @since 3.6.0
183         */
184        return apply_filters( 'jetpack_boost_critical_css_providers', $sources );
185    }
186
187    /**
188     * Make URLs absolute.
189     *
190     * @param array $urls The list of URLs to make absolute.
191     *
192     * @return array
193     */
194    private function make_absolute_urls( $urls ) {
195        $absolute_urls = array();
196        foreach ( $urls as $url ) {
197            if ( class_exists( '\WP_Http' ) && method_exists( '\WP_Http', 'make_absolute_url' ) ) {
198                $absolute_urls[] = \WP_Http::make_absolute_url( $url, home_url() );
199                continue;
200            }
201
202            if ( stripos( $url, home_url() ) === 0 ) {
203                $absolute_urls[] = $url;
204            } else {
205                $absolute_urls[] = home_url( $url );
206            }
207        }
208
209        return $absolute_urls;
210    }
211}