PluginProbe
Autoptimize / trunk
Autoptimize vtrunk
3.1.16 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 All 108 releases
← All changes | classes/autoptimizeExtra.php +270 -547 2.4.1 → trunk View file →
@@ -16,8 +16,15 @@
16 16 */
17 17 protected $options = array();
18 18
19 19 /**
20 + * Singleton instance.
21 + *
22 + * @var self|null
23 + */
24 + protected static $instance = null;
25 +
26 + /**
20 27 * Creates an instance and calls run().
21 28 *
22 29 * @param array $options Optional. Allows overriding options without having to specify them via admin options page.
23 30 */
@@ -23,39 +30,60 @@
23 30 */
24 31 public function __construct( $options = array() )
25 32 {
26 33 if ( empty( $options ) ) {
27 - $options = $this->fetch_options();
34 + $options = self::fetch_options();
28 35 }
29 36
30 37 $this->options = $options;
31 38 }
32 39
40 + /**
41 + * Helper for getting a singleton instance. While being an
42 + * anti-pattern generally, it comes in handy for now from a
43 + * readability/maintainability perspective, until we get some
44 + * proper dependency injection going.
45 + *
46 + * @return self
47 + */
48 + public static function instance()
49 + {
50 + if ( null === self::$instance ) {
51 + self::$instance = new self();
52 + }
53 +
54 + return self::$instance;
55 + }
56 +
33 57 public function run()
34 58 {
35 59 if ( is_admin() ) {
36 - add_action( 'admin_menu', array( $this, 'admin_menu' ) );
60 + if ( is_multisite() && is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network() ) {
61 + add_action( 'network_admin_menu', array( $this, 'admin_menu' ) );
62 + } else {
63 + add_action( 'admin_menu', array( $this, 'admin_menu' ) );
64 + }
37 65 add_filter( 'autoptimize_filter_settingsscreen_tabs', array( $this, 'add_extra_tab' ) );
38 66 } else {
39 - $this->run_on_frontend();
67 + add_action( 'wp', array( $this, 'run_on_frontend' ) );
40 68 }
41 69 }
42 70
43 - protected function fetch_options()
71 + public function set_options( array $options )
44 72 {
45 - $value = get_option( 'autoptimize_extra_settings' );
73 + $this->options = $options;
74 +
75 + return $this;
76 + }
77 +
78 + public static function fetch_options()
79 + {
80 + $value = autoptimizeOptionWrapper::get_option( 'autoptimize_extra_settings' );
46 81 if ( empty( $value ) ) {
47 82 // Fallback to returning defaults when no stored option exists yet.
48 83 $value = autoptimizeConfig::get_ao_extra_default_options();
49 84 }
50 85
51 - // get service availability.
52 - $value['availabilities'] = get_option( 'autoptimize_service_availablity' );
53 -
54 - if ( empty( $value['availabilities'] ) ) {
55 - $value['availabilities'] = autoptimizeUtils::check_service_availability( true );
56 - }
57 -
58 86 return $value;
59 87 }
60 88
61 89 public function disable_emojis()
@@ -72,9 +100,9 @@
72 100 // Removes TinyMCE emojis.
73 101 add_filter( 'tiny_mce_plugins', array( $this, 'filter_disable_emojis_tinymce' ) );
74 102
75 103 // Removes emoji dns-preftech.
76 - add_filter( 'wp_resource_hints', array( $this, 'filter_remove_emoji_dns_prefetch' ), 10, 2 );
104 + add_filter( 'emoji_svg_url', '__return_false' );
77 105 }
78 106
79 107 public function filter_disable_emojis_tinymce( $plugins )
80 108 {
@@ -84,11 +112,16 @@
84 112 return array();
85 113 }
86 114 }
87 115
88 - public function filter_remove_qs( $src ) {
89 - if ( strpos( $src, '?ver=' ) ) {
90 - $src = remove_query_arg( 'ver', $src );
116 + public function filter_remove_qs( $src )
117 + {
118 + if ( ! empty( $src ) ) {
119 + if ( strpos( $src, '?ver=' ) ) {
120 + $src = remove_query_arg( 'ver', $src );
121 + } elseif ( strpos( $src, '?v=' ) ) {
122 + $src = remove_query_arg( 'v', $src );
123 + }
91 124 }
92 125
93 126 return $src;
94 127 }
@@ -99,9 +132,9 @@
99 132 if ( ! empty( $in ) ) {
100 133 $exclusions = array_fill_keys( array_filter( array_map( 'trim', explode( ',', $in ) ) ), '' );
101 134 }
102 135
103 - $settings = $this->options['autoptimize_extra_text_field_3'];
136 + $settings = wp_strip_all_tags( $this->options['autoptimize_extra_text_field_3'] );
104 137 $async = array_fill_keys( array_filter( array_map( 'trim', explode( ',', $settings ) ) ), '' );
105 138 $attr = apply_filters( 'autoptimize_filter_extra_async', 'async' );
106 139 foreach ( $async as $k => $v ) {
107 140 $async[ $k ] = $attr;
@@ -112,10 +145,18 @@
112 145
113 146 return $merged;
114 147 }
115 148
116 - protected function run_on_frontend()
149 + public function run_on_frontend()
117 150 {
151 + // only run the Extra optimizations on frontend if general conditions
152 + // for optimizations are met, this to ensure e.g. removing querystrings
153 + // is not done when optimizing for logged in users is off, breaking
154 + // some pagebuilders (Divi & Elementor).
155 + if ( false === autoptimizeMain::should_buffer() ) {
156 + return;
157 + }
158 +
118 159 $options = $this->options;
119 160
120 161 // Disable emojis if specified.
121 162 if ( ! empty( $options['autoptimize_extra_checkbox_field_1'] ) ) {
@@ -127,17 +168,10 @@
127 168 add_filter( 'script_loader_src', array( $this, 'filter_remove_qs' ), 15, 1 );
128 169 add_filter( 'style_loader_src', array( $this, 'filter_remove_qs' ), 15, 1 );
129 170 }
130 171
131 - // Making sure is_plugin_active() exists when we need it.
132 - if ( ! function_exists( 'is_plugin_active' ) ) {
133 - require_once ABSPATH . 'wp-admin/includes/plugin.php';
134 - }
135 172 // Avoiding conflicts of interest when async-javascript plugin is active!
136 - $async_js_plugin_active = false;
137 - if ( function_exists( 'is_plugin_active' ) && is_plugin_active( 'async-javascript/async-javascript.php' ) ) {
138 - $async_js_plugin_active = true;
139 - }
173 + $async_js_plugin_active = autoptimizeUtils::is_plugin_active( 'async-javascript/async-javascript.php' );
140 174 if ( ! empty( $options['autoptimize_extra_text_field_3'] ) && ! $async_js_plugin_active ) {
141 175 add_filter( 'autoptimize_filter_js_exclude', array( $this, 'extra_async_js' ), 10, 1 );
142 176 }
143 177
@@ -145,8 +179,17 @@
145 179 if ( ! empty( $options['autoptimize_extra_radio_field_4'] ) && ( '1' !== $options['autoptimize_extra_radio_field_4'] ) ) {
146 180 add_filter( 'wp_resource_hints', array( $this, 'filter_remove_gfonts_dnsprefetch' ), 10, 2 );
147 181 add_filter( 'autoptimize_html_after_minify', array( $this, 'filter_optimize_google_fonts' ), 10, 1 );
148 182 add_filter( 'autoptimize_extra_filter_tobepreconn', array( $this, 'filter_preconnect_google_fonts' ), 10, 1 );
183 +
184 + if ( '2' === $options['autoptimize_extra_radio_field_4'] ) {
185 + // remove Google Fonts, adding filters to also remove Google Fonts from 3rd party themes/ plugins.
186 + // inspired by https://wordpress.org/plugins/disable-remove-google-fonts/.
187 + remove_action( 'wp_footer', 'et_builder_print_font' ); // Divi.
188 + remove_action( 'wp_footer', array( 'RevSliderFront', 'load_google_fonts' ) ); // Revslider.
189 + add_filter( 'elementor/frontend/print_google_fonts', '__return_false' ); // Elementor.
190 + add_filter( 'fl_builder_google_fonts_pre_enqueue', '__return_empty_array' ); // Beaver Builder.
191 + }
149 192 }
150 193
151 194 // Preconnect!
152 195 if ( ! empty( $options['autoptimize_extra_text_field_2'] ) || has_filter( 'autoptimize_extra_filter_tobepreconn' ) ) {
@@ -152,29 +195,17 @@
152 195 if ( ! empty( $options['autoptimize_extra_text_field_2'] ) || has_filter( 'autoptimize_extra_filter_tobepreconn' ) ) {
153 196 add_filter( 'wp_resource_hints', array( $this, 'filter_preconnect' ), 10, 2 );
154 197 }
155 198
156 - // Optimize Images!
157 - if ( ! empty( $options['autoptimize_extra_checkbox_field_5'] ) && 'down' !== $options['availabilities']['extra_imgopt']['status'] && ( 'launch' !== $options['availabilities']['extra_imgopt']['status'] || $this->imgopt_launch_ok() ) ) {
158 - if ( apply_filters( 'autoptimize_filter_extra_imgopt_do', true ) ) {
159 - add_filter( 'autoptimize_html_after_minify', array( $this, 'filter_optimize_images' ), 10, 1 );
160 - $_imgopt_active = true;
161 - }
162 - if ( apply_filters( 'autoptimize_filter_extra_imgopt_do_css', true ) ) {
163 - add_filter( 'autoptimize_filter_base_replace_cdn', array( $this, 'filter_optimize_css_images' ), 10, 1 );
164 - $_imgopt_active = true;
165 - }
166 - if ( $_imgopt_active ) {
167 - add_filter( 'autoptimize_extra_filter_tobepreconn', array( $this, 'filter_preconnect_imgopt_url' ), 10, 1 );
168 - }
199 + // Preload!
200 + if ( ! empty( $options['autoptimize_extra_text_field_7'] ) || has_filter( 'autoptimize_filter_extra_tobepreloaded' ) || ! empty( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) {
201 + add_filter( 'autoptimize_html_after_minify', array( $this, 'filter_preload' ), 10, 2 );
169 202 }
170 - }
171 203
172 - public function filter_remove_emoji_dns_prefetch( $urls, $relation_type )
173 - {
174 - $emoji_svg_url = apply_filters( 'emoji_svg_url', 'https://s.w.org/images/core/emoji/' );
175 -
176 - return $this->filter_remove_dns_prefetch( $urls, $relation_type, $emoji_svg_url );
204 + // Remove global styles.
205 + if ( ! empty( $options['autoptimize_extra_checkbox_field_8'] ) ) {
206 + $this->disable_global_styles();
207 + }
177 208 }
178 209
179 210 public function filter_remove_gfonts_dnsprefetch( $urls, $relation_type )
180 211 {
@@ -182,12 +213,23 @@
182 213 }
183 214
184 215 public function filter_remove_dns_prefetch( $urls, $relation_type, $url_to_remove )
185 216 {
186 - if ( 'dns-prefetch' === $relation_type ) {
217 + $url_to_remove = (string) $url_to_remove;
218 +
219 + if ( ! empty( $url_to_remove ) && 'dns-prefetch' === $relation_type ) {
187 220 $cnt = 0;
188 221 foreach ( $urls as $url ) {
189 - if ( false !== strpos( $url, $url_to_remove ) ) {
222 + // $url can be an array, in which case we need to fetch the value of the href key.
223 + if ( is_array( $url ) ) {
224 + if ( isset( $url['href'] ) ) {
225 + $url = $url['href'];
226 + } else {
227 + continue;
228 + }
229 + }
230 +
231 + if ( is_string( $url ) && false !== strpos( $url, $url_to_remove ) ) {
190 232 unset( $urls[ $cnt ] );
191 233 }
192 234 $cnt++;
193 235 }
@@ -212,8 +254,14 @@
212 254 foreach ( $matches[2] as $font ) {
213 255 if ( ! preg_match( '/rel=["\']dns-prefetch["\']/', $matches[0][ $i ] ) ) {
214 256 // Get fonts name.
215 257 $font = str_replace( array( '%7C', '%7c' ), '|', $font );
258 + if ( strpos( $font, 'fonts.googleapis.com/css2' ) !== false ) {
259 + // (Somewhat) change Google Fonts APIv2 syntax back to v1.
260 + // todo: support for 100..900
261 + $font = rawurldecode( $font );
262 + $font = str_replace( array( 'css2?', 'ital,wght@', 'wght@', 'ital@', '0,', '1,', ':1', ';', '&family=' ), array( 'css?', '', '', '', '', 'italic', ':italic', ',', '%7C' ), $font );
263 + }
216 264 $font = explode( 'family=', $font );
217 265 $font = ( isset( $font[1] ) ) ? explode( '&', $font[1] ) : array();
218 266 // Add font to $fonts[$i] but make sure not to pollute with an empty family!
219 267 $_thisfont = array_values( array_filter( explode( '|', reset( $font ) ) ) );
@@ -221,8 +269,9 @@
221 269 $fonts_collection[ $i ]['fonts'] = $_thisfont;
222 270 // And add subset if any!
223 271 $subset = ( is_array( $font ) ) ? end( $font ) : '';
224 272 if ( false !== strpos( $subset, 'subset=' ) ) {
273 + $subset = str_replace( array( '%2C', '%2c' ), ',', $subset );
225 274 $subset = explode( 'subset=', $subset );
226 275 $fonts_collection[ $i ]['subsets'] = explode( ',', $subset[1] );
227 276 }
228 277 }
@@ -244,25 +293,30 @@
244 293 $subset_string = '';
245 294 foreach ( $fonts_collection as $font ) {
246 295 $fonts_string .= '|' . trim( implode( '|', $font['fonts'] ), '|' );
247 296 if ( ! empty( $font['subsets'] ) ) {
248 - $subset_string .= implode( ',', $font['subsets'] );
297 + $subset_string .= ',' . trim( implode( ',', $font['subsets'] ), ',' );
249 298 }
250 299 }
251 300
252 301 if ( ! empty( $subset_string ) ) {
253 - $fonts_string = $fonts_string . '&subset=' . $subset_string;
302 + $subset_string = str_replace( ',', '%2C', ltrim( $subset_string, ',' ) );
303 + $fonts_string = $fonts_string . '&subset=' . $subset_string;
254 304 }
255 305
256 - $fonts_string = str_replace( '|', '%7C', ltrim( $fonts_string, '|' ) );
306 + $fonts_string = apply_filters( 'autoptimize_filter_extra_gfont_fontstring', str_replace( '|', '%7C', ltrim( $fonts_string, '|' ) ) );
307 + // only add display parameter if there is none in $fonts_string (by virtue of the filter).
308 + if ( strpos( $fonts_string, 'display=' ) === false ) {
309 + $fonts_string .= apply_filters( 'autoptimize_filter_extra_gfont_display', '&display=swap' );
310 + }
257 311
258 312 if ( ! empty( $fonts_string ) ) {
259 313 if ( '5' === $options['autoptimize_extra_radio_field_4'] ) {
260 - $rel_string = 'rel="preload" as="style" onload="' . autoptimizeConfig::get_ao_css_preload_onload() . '"';
314 + $rel_string = 'rel="stylesheet" media="print" onload="' . autoptimizeConfig::get_ao_css_preload_onload() . '"';
261 315 } else {
262 316 $rel_string = 'rel="stylesheet"';
263 317 }
264 - $fonts_markup = '<link ' . $rel_string . ' id="ao_optimized_gfonts" href="https://fonts.googleapis.com/css?family=' . $fonts_string . '" />';
318 + $fonts_markup = '<link ' . $rel_string . ' id="ao_optimized_gfonts" href="https://fonts.googleapis.com/css?family=' . $fonts_string . '">';
265 319 }
266 320 } elseif ( '4' === $options['autoptimize_extra_radio_field_4'] ) {
267 321 // Aggregate & load async (webfont.js impl.)!
268 322 $fonts_array = array();
@@ -276,43 +330,53 @@
276 330 }
277 331 $fonts_array = array_merge( $fonts_array, $_fonts['fonts'] );
278 332 }
279 333
280 - $fonts_markup = '<script data-cfasync="false" id="ao_optimized_gfonts" type="text/javascript">WebFontConfig={google:{families:[\'';
281 - foreach ( $fonts_array as $fnt ) {
282 - $fonts_markup .= $fnt . "','";
334 + $fonts_array = array_map( 'urldecode', $fonts_array );
335 + $fonts_array = array_map(
336 + function( $_f ) {
337 + return trim( $_f, ',' );
338 + },
339 + $fonts_array
340 + );
341 +
342 + // type attrib on <script not added by default.
343 + $type_js = '';
344 + if ( apply_filters( 'autoptimize_filter_cssjs_addtype', false ) ) {
345 + $type_js = 'type="text/javascript" ';
283 346 }
284 - $fonts_markup = trim( trim( $fonts_markup, "'" ), ',' );
285 - $fonts_markup .= '] },classes:false, events:false, timeout:1500};(function() {var wf = document.createElement(\'script\');wf.src=\'https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js\';wf.type=\'text/javascript\';wf.async=\'true\';var s=document.getElementsByTagName(\'script\')[0];s.parentNode.insertBefore(wf, s);})();</script>';
347 +
348 + $fonts_markup = '<script ' . $type_js . 'data-cfasync="false" id="ao_optimized_gfonts_config">WebFontConfig={google:{families:' . wp_json_encode( $fonts_array, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_QUOT ) . ' },classes:false, events:false, timeout:1500};</script>';
349 + $fonts_library_markup = '<script ' . $type_js . 'data-cfasync="false" id="ao_optimized_gfonts_webfontloader">(function() {var wf = document.createElement(\'script\');wf.src=\'https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js\';wf.type=\'text/javascript\';wf.async=\'true\';var s=document.getElementsByTagName(\'script\')[0];s.parentNode.insertBefore(wf, s);})();</script>';
350 + $in = substr_replace( $in, $fonts_library_markup . '</head>', strpos( $in, '</head>' ), strlen( '</head>' ) );
286 351 }
287 352
288 353 // Replace back in markup.
289 - $out = substr_replace( $in, $fonts_markup . '<link', strpos( $in, '<link' ), strlen( '<link' ) );
354 + $inject_point = apply_filters( 'autoptimize_filter_extra_gfont_injectpoint', '<link' );
355 + $out = substr_replace( $in, $fonts_markup . $inject_point, strpos( $in, $inject_point ), strlen( $inject_point ) );
290 356 unset( $fonts_collection );
291 357
292 - // and insert preload polyfill if "link preload" and if the polyfill isn't there yet (courtesy of inline&defer).
293 - $preload_polyfill = autoptimizeConfig::get_ao_css_preload_polyfill();
294 - if ( '5' === $options['autoptimize_extra_radio_field_4'] && strpos( $out, $preload_polyfill ) === false ) {
295 - $out = str_replace( '</body>', $preload_polyfill . '</body>', $out );
296 - }
297 358 return $out;
298 359 }
299 360
300 361 public function filter_preconnect( $hints, $relation_type )
301 362 {
302 - $options = $this->options;
363 + $options = $this->options;
364 + $preconns = array();
303 365
304 366 // Get settings and store in array.
305 - $preconns = array_filter( array_map( 'trim', explode( ',', $options['autoptimize_extra_text_field_2'] ) ) );
367 + if ( array_key_exists( 'autoptimize_extra_text_field_2', $options ) ) {
368 + $preconns = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( $options['autoptimize_extra_text_field_2'] ) ) ) );
369 + }
306 370 $preconns = apply_filters( 'autoptimize_extra_filter_tobepreconn', $preconns );
307 371
308 372 // Walk array, extract domain and add to new array with crossorigin attribute.
309 373 foreach ( $preconns as $preconn ) {
374 + $domain = '';
310 375 $parsed = parse_url( $preconn );
311 -
312 - if ( is_array( $parsed ) && empty( $parsed['scheme'] ) ) {
376 + if ( is_array( $parsed ) && ! empty( $parsed['host'] ) && empty( $parsed['scheme'] ) ) {
313 377 $domain = '//' . $parsed['host'];
314 - } elseif ( is_array( $parsed ) ) {
378 + } elseif ( is_array( $parsed ) && ! empty( $parsed['host'] ) ) {
315 379 $domain = $parsed['scheme'] . '://' . $parsed['host'];
316 380 }
317 381
318 382 if ( ! empty( $domain ) ) {
@@ -350,383 +414,122 @@
350 414
351 415 return $in;
352 416 }
353 417
354 - public function filter_optimize_images( $in )
355 - {
356 - /*
357 - * potential future functional improvements:
358 - *
359 - * picture element.
360 - * filter for critical CSS.
361 - */
418 + public function filter_preload( $in ) {
419 + // make array from comma separated list.
420 + $options = $this->options;
421 + $preloads = array();
422 + if ( array_key_exists( 'autoptimize_extra_text_field_7', $options ) ) {
423 + $preloads = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( $options['autoptimize_extra_text_field_7'] ) ) ) );
424 + }
362 425
363 - $imgopt_base_url = $this->get_imgopt_base_url();
364 - $to_replace = array();
365 -
366 - // extract img tags.
367 - if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
368 - foreach ( $matches[0] as $tag ) {
369 - $orig_tag = $tag;
370 - $imgopt_w = '';
371 - $imgopt_h = '';
372 -
373 - // first do (data-)srcsets.
374 - if ( preg_match_all( '#srcset=("|\')(.*)("|\')#Usmi', $tag, $allsrcsets, PREG_SET_ORDER ) ) {
375 - foreach ( $allsrcsets as $srcset ) {
376 - $srcset = $srcset[2];
377 - $srcsets = explode( ',', $srcset );
378 - foreach ( $srcsets as $indiv_srcset ) {
379 - $indiv_srcset_parts = explode( ' ', trim( $indiv_srcset ) );
380 - if ( $indiv_srcset_parts[1] && rtrim( $indiv_srcset_parts[1], 'w' ) !== $indiv_srcset_parts[1] ) {
381 - $imgopt_w = rtrim( $indiv_srcset_parts[1], 'w' );
382 - }
383 - if ( $this->can_optimize_image( $indiv_srcset_parts[0] ) ) {
384 - $imgopt_url = $this->build_imgopt_url( $indiv_srcset_parts[0], $imgopt_w, '' );
385 - $tag = str_replace( $indiv_srcset_parts[0], $imgopt_url, $tag );
386 - $to_replace[ $orig_tag ] = $tag;
387 - }
388 - }
389 - }
390 - }
391 -
392 - // proceed with img src.
393 - // first reset and then get width and height and add to $imgopt_size.
394 - $imgopt_w = '';
395 - $imgopt_h = '';
396 - if ( preg_match( '#width=("|\')(.*)("|\')#Usmi', $tag, $width ) ) {
397 - $imgopt_w = $width[2];
398 - }
399 - if ( preg_match( '#height=("|\')(.*)("|\')#Usmi', $tag, $height ) ) {
400 - $imgopt_h = $height[2];
401 - }
402 -
403 - // then start replacing images src.
404 - if ( preg_match_all( '#src=(?:"|\')(?!data)(.*)(?:"|\')#Usmi', $tag, $urls, PREG_SET_ORDER ) ) {
405 - foreach ( $urls as $url ) {
406 - $full_src_orig = $url[0];
407 - $url = $url[1];
408 - if ( $this->can_optimize_image( $url ) ) {
409 - $imgopt_url = $this->build_imgopt_url( $url, $imgopt_w, $imgopt_h );
410 - $full_imgopt_src = str_replace( $url, $imgopt_url, $full_src_orig );
411 - $tag = str_replace( $full_src_orig, $full_imgopt_src, $tag );
412 - $to_replace[ $orig_tag ] = $tag;
413 - }
414 - }
415 - }
426 + if ( false === autoptimizeImages::imgopt_active() && false === autoptimizeImages::should_lazyload_wrapper() ) {
427 + // only do this here if imgopt/ lazyload are not active?
428 + $metabox_preloads = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) );
429 + if ( ! empty( $metabox_preloads ) ) {
430 + $preloads = array_merge( $preloads, $metabox_preloads );
416 431 }
417 432 }
418 - $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $in );
419 433
420 - // img thumbnails in e.g. woocommerce.
421 - if ( strpos( $out, 'data-thumb' ) !== false && apply_filters( 'autoptimize_filter_extra_imgopt_datathumbs', true ) ) {
422 - $out = preg_replace_callback(
423 - '/\<div(?:[^>]?)\sdata-thumb\=(?:\"|\')(.+?)(?:\"|\')(?:[^>]*)?\>/s',
424 - array( $this, 'replace_data_thumbs' ),
425 - $out
426 - );
427 - }
434 + $preloads = apply_filters( 'autoptimize_filter_extra_tobepreloaded', $preloads );
428 435
429 - return $out;
430 - }
431 -
432 - public function filter_optimize_css_images( $in )
433 - {
434 - $imgopt_base_url = $this->get_imgopt_base_url();
435 - $in = $this->normalize_img_urls( $in );
436 -
437 - if ( $this->can_optimize_image( $in ) ) {
438 - return $this->build_imgopt_url( $in, '', '' );
439 - } else {
436 + // immediately return if nothing to be preloaded.
437 + if ( empty( $preloads ) ) {
440 438 return $in;
441 439 }
442 - }
443 440
444 - private function get_imgopt_base_url()
445 - {
446 - static $imgopt_base_url = null;
441 + // iterate through array and add preload link to tmp string.
442 + $preload_output = '';
443 + foreach ( $preloads as $preload ) {
444 + if ( filter_var( $preload, FILTER_VALIDATE_URL ) !== $preload ) {
445 + continue;
446 + }
447 + $preload = esc_url_raw( $preload );
448 + $crossorigin = '';
449 + $preload_as = '';
450 + $mime_type = '';
451 + $_preload = strtok( $preload, '?' );
447 452
448 - if ( is_null( $imgopt_base_url ) ) {
449 - $imgopt_host = $this->get_imgopt_host();
450 - $quality = $this->get_img_quality_string();
451 - $ret_val = apply_filters( 'autoptimize_filter_extra_imgopt_wait', 'ret_img' ); // values: ret_wait, ret_img, ret_json, ret_blank.
452 - $imgopt_base_url = $imgopt_host . 'client/' . $quality . ',' . $ret_val;
453 - $imgopt_base_url = apply_filters( 'autoptimize_filter_extra_imgopt_base_url', $imgopt_base_url );
454 - }
455 -
456 - return $imgopt_base_url;
457 - }
458 -
459 - private function can_optimize_image( $url )
460 - {
461 - static $cdn_url = null;
462 - static $nopti_images = null;
463 -
464 - if ( is_null( $cdn_url ) ) {
465 - $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', get_option( 'autoptimize_cdn_url', '' ) );
466 - }
467 -
468 - if ( is_null( $nopti_images ) ) {
469 - $nopti_images = apply_filters( 'autoptimize_filter_extra_imgopt_noptimize', '' );
470 - }
471 -
472 - $imgopt_base_url = $this->get_imgopt_base_url();
473 - $site_host = AUTOPTIMIZE_SITE_DOMAIN;
474 - $url_parsed = parse_url( $url );
475 -
476 - if ( $url_parsed['host'] !== $site_host && empty( $cdn_url ) ) {
477 - return false;
478 - } elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && $url_parsed['host'] !== $site_host ) {
479 - return false;
480 - } elseif ( strpos( $url, '.php' ) !== false ) {
481 - return false;
482 - } elseif ( str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) {
483 - // fixme: better check against end of string.
484 - return false;
485 - } elseif ( ! empty( $nopti_images ) ) {
486 - $nopti_images_array = array_filter( array_map( 'trim', explode( ',', $nopti_images ) ) );
487 - foreach ( $nopti_images_array as $nopti_image ) {
488 - if ( strpos( $url, $nopti_image ) !== false ) {
489 - return false;
453 + if ( autoptimizeUtils::str_ends_in( $_preload, '.css' ) ) {
454 + $preload_as = 'style';
455 + } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.js' ) ) {
456 + $preload_as = 'script';
457 + } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.woff' ) || autoptimizeUtils::str_ends_in( $_preload, '.woff2' ) || autoptimizeUtils::str_ends_in( $_preload, '.ttf' ) || autoptimizeUtils::str_ends_in( $_preload, '.eot' ) || autoptimizeUtils::str_ends_in( $_preload, '.otf' ) ) {
458 + $preload_as = 'font';
459 + $crossorigin = ' crossorigin';
460 + $mime_type = ' type="font/' . pathinfo( $_preload, PATHINFO_EXTENSION ) . '"';
461 + if ( ' type="font/eot"' === $mime_type ) {
462 + $mime_type = 'application/vnd.ms-fontobject';
490 463 }
491 - }
492 - }
493 - return true;
494 - }
495 -
496 - private function build_imgopt_url( $orig_url, $width = 0, $height = 0 )
497 - {
498 - $filtered_url = apply_filters( 'autoptimize_filter_extra_imgopt_build_url', $orig_url, $width, $height );
499 -
500 - if ( $filtered_url !== $orig_url ) {
501 - return $filtered_url;
502 - }
503 -
504 - $orig_url = $this->normalize_img_urls( $orig_url );
505 - $imgopt_base_url = $this->get_imgopt_base_url();
506 - $imgopt_size = '';
507 -
508 - if ( $width && 0 !== $width ) {
509 - $imgopt_size = ',w_' . $width;
510 - }
511 -
512 - if ( $height && 0 !== $height ) {
513 - $imgopt_size .= ',h_' . $height;
514 - }
515 -
516 - $url = $imgopt_base_url . $imgopt_size . '/' . $orig_url;
517 -
518 - return $url;
519 - }
520 -
521 - public function replace_data_thumbs( $matches )
522 - {
523 - if ( $this->can_optimize_image( $matches[1] ) ) {
524 - return str_replace( $matches[1], $this->build_imgopt_url( $matches[1], 150, 150 ), $matches[0] );
525 - } else {
526 - return $matches[0];
527 - }
528 - }
529 -
530 - public function filter_preconnect_imgopt_url( $in )
531 - {
532 - $imgopt_url_array = parse_url( $this->get_imgopt_base_url() );
533 - $in[] = $imgopt_url_array['scheme'] . '://' . $imgopt_url_array['host'];
534 -
535 - return $in;
536 - }
537 -
538 - private function normalize_img_urls( $in )
539 - {
540 - $parsed_site_url = parse_url( site_url() );
541 -
542 - if ( strpos( $in, 'http' ) !== 0 && strpos( $in, '//' ) === 0 ) {
543 - $in = $parsed_site_url['scheme'] . ':' . $in;
544 - } elseif ( strpos( $in, '/' ) === 0 ) {
545 - $in = $parsed_site_url['scheme'] . '://' . $parsed_site_url['host'] . $in;
546 - }
547 -
548 - return apply_filters( 'autoptimize_filter_extra_imgopt_normalized_url', $in );
549 - }
550 -
551 - private function get_img_quality_array()
552 - {
553 - static $img_quality_array = null;
554 -
555 - if ( is_null( $img_quality_array ) ) {
556 - $img_quality_array = array(
557 - '1' => 'lossy',
558 - '2' => 'glossy',
559 - '3' => 'lossless',
560 - );
561 - $img_quality_array = apply_filters( 'autoptimize_filter_extra_imgopt_quality_array', $img_quality_array );
562 - }
563 -
564 - return $img_quality_array;
565 - }
566 -
567 - private function get_img_quality_setting()
568 - {
569 - static $_img_q = null;
570 -
571 - if ( is_null( $_img_q ) ) {
572 - $_setting = $this->options['autoptimize_extra_select_field_6'];
573 -
574 - if ( ! $_setting || empty( $_setting ) || ( '1' !== $_setting && '3' !== $_setting ) ) {
575 - // default image opt. value is 2 ("glossy").
576 - $_img_q = '2';
464 + } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.jpeg' ) || autoptimizeUtils::str_ends_in( $_preload, '.jpg' ) || autoptimizeUtils::str_ends_in( $_preload, '.webp' ) || autoptimizeUtils::str_ends_in( $_preload, '.png' ) || autoptimizeUtils::str_ends_in( $_preload, '.gif' ) || autoptimizeUtils::str_ends_in( $_preload, '.svg' ) ) {
465 + $preload_as = 'image';
577 466 } else {
578 - $_img_q = $_setting;
467 + $preload_as = 'other';
579 468 }
580 - }
581 469
582 - return $_img_q;
583 - }
584 -
585 - private function get_img_quality_string()
586 - {
587 - static $_img_q_string = null;
588 -
589 - if ( is_null( $_img_q_string ) ) {
590 - $_quality_array = $this->get_img_quality_array();
591 - $_setting = $this->get_img_quality_setting();
592 - $_img_q_string = apply_filters( 'autoptimize_filter_extra_imgopt_quality', 'q_' . $_quality_array[ $_setting ] );
470 + $preload_output .= '<link rel="preload" fetchpriority="high" href="' . $preload . '" as="' . $preload_as . '"' . $mime_type . $crossorigin . '>';
593 471 }
472 + $preload_output = apply_filters( 'autoptimize_filter_extra_preload_output', $preload_output );
594 473
595 - return $_img_q_string;
474 + return $this->inject_preloads( $preload_output, $in );
596 475 }
597 476
598 - public static function get_img_provider_stats()
599 - {
600 - // wrapper around query_img_provider_stats() so we can get to $this->options from cronjob() in autoptimizeCacheChecker.
601 - $self = new self();
602 - return $self->query_img_provider_stats();
603 - }
477 + public static function inject_preloads( $preloads, $html ) {
478 + // add string to head (before first link node by default).
479 + $preload_inject = apply_filters( 'autoptimize_filter_extra_preload_inject', '<link' );
480 + $position = autoptimizeUtils::strpos( $html, $preload_inject );
604 481
605 - public function query_img_provider_stats()
606 - {
607 - if ( ! empty( $this->options['autoptimize_extra_checkbox_field_5'] ) ) {
608 - $_img_provider_stat_url = '';
609 - $_img_provider_endpoint = $this->get_imgopt_host() . 'read-domain/';
610 - $_site_host = AUTOPTIMIZE_SITE_DOMAIN;
611 -
612 - // make sure parse_url result makes sense, keeping $_img_provider_stat_url empty if not.
613 - if ( $_site_host && ! empty( $_site_host ) ) {
614 - $_img_provider_stat_url = $_img_provider_endpoint . $_site_host;
615 - }
616 -
617 - $_img_provider_stat_url = apply_filters( 'autoptimize_filter_extra_imgopt_stat_url', $_img_provider_stat_url );
618 -
619 - // only do the remote call if $_img_provider_stat_url is not empty to make sure no parse_url weirdness results in useless calls.
620 - if ( ! empty( $_img_provider_stat_url ) ) {
621 - $_img_stat_resp = wp_remote_get( $_img_provider_stat_url );
622 - if ( ! is_wp_error( $_img_stat_resp ) ) {
623 - if ( '200' == wp_remote_retrieve_response_code( $_img_stat_resp ) ) {
624 - $_img_provider_stat = json_decode( wp_remote_retrieve_body( $_img_stat_resp ), true );
625 - update_option( 'autoptimize_imgopt_provider_stat', $_img_provider_stat );
626 - }
627 - }
628 - }
629 - }
482 + return autoptimizeUtils::substr_replace( $html, $preloads . $preload_inject, $position, strlen( $preload_inject ) );
630 483 }
631 484
632 - public function imgopt_launch_ok()
485 + public function disable_global_styles()
633 486 {
634 - static $launch_status = null;
487 + remove_action( 'wp_enqueue_scripts', 'wp_enqueue_global_styles' );
488 + remove_action( 'wp_footer', 'wp_enqueue_global_styles', 1 );
489 + remove_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' );
635 490
636 - if ( is_null( $launch_status ) ) {
637 - $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
638 - $magic_number = intval( substr( md5( parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ), 0, 3 ), 16 );
639 - $has_launched = get_option( 'autoptimize_imgopt_launched', '' );
640 - if ( $has_launched || ( array_key_exists( 'launch-threshold', $avail_imgopt ) && $magic_number < $avail_imgopt['launch-threshold'] ) ) {
641 - $launch_status = true;
642 - if ( ! $has_launched ) {
643 - update_option( 'autoptimize_imgopt_launched', 'on' );
491 + if ( true === apply_filters( 'autoptimize_filter_extra_global_styles_and_block_css', true ) ) {
492 + add_action(
493 + 'wp_enqueue_scripts',
494 + function() {
495 + wp_dequeue_style( 'wp-block-library' );
496 + wp_dequeue_style( 'wp-block-library-theme' );
644 497 }
645 - } else {
646 - $launch_status = false;
647 - }
498 + );
648 499 }
649 500
650 - return $launch_status;
651 - }
652 -
653 - public static function imgopt_launch_ok_wrapper()
654 - {
655 - // needed for "plug" notice in autoptimizeMain.php.
656 - $self = new self();
657 - return $self->imgopt_launch_ok();
658 - }
659 -
660 - public function get_imgopt_host()
661 - {
662 - static $imgopt_host = null;
663 -
664 - if ( is_null( $imgopt_host ) ) {
665 - $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
666 - if ( ! empty( $avail_imgopt ) && array_key_exists( 'hosts', $avail_imgopt ) && is_array( $avail_imgopt['hosts'] ) ) {
667 - $imgopt_host = array_rand( array_flip( $avail_imgopt['hosts'] ) );
668 - } else {
669 - $imgopt_host = 'https://cdn.shortpixel.ai/';
670 - }
671 - }
672 -
673 - return $imgopt_host;
674 - }
675 -
676 - public static function get_imgopt_host_wrapper()
677 - {
678 - // needed for CI tests.
679 - $self = new self();
680 - return $self->get_imgopt_host();
681 - }
682 -
683 - public function get_imgopt_status_notice() {
684 - $_extra_options = $this->options;
685 - if ( ! empty( $_extra_options ) && is_array( $_extra_options ) && array_key_exists( 'autoptimize_extra_checkbox_field_5', $_extra_options ) && ! empty( $_extra_options['autoptimize_extra_checkbox_field_5'] ) ) {
686 - $_imgopt_notice = '';
687 - $_stat = get_option( 'autoptimize_imgopt_provider_stat', '' );
688 - $_site_host = AUTOPTIMIZE_SITE_DOMAIN;
689 - $_imgopt_upsell = 'https://shortpixel.com/aospai/af/GWRGFLW109483/' . $_site_host;
690 -
691 - if ( is_array( $_stat ) ) {
692 - if ( 1 == $_stat['Status'] ) {
693 - // translators: "add more credits" will appear in a "a href".
694 - $_imgopt_notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota is almost used, make sure you %1$sadd more credits%2$s to avoid slowing down your website.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' );
695 - } elseif ( -1 == $_stat['Status'] ) {
696 - // translators: "add more credits" will appear in a "a href".
697 - $_imgopt_notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota was used, %1$sadd more credits%2$s to keep fast serving optimized images on your site.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' );
698 - } else {
699 - $_imgopt_upsell = 'https://shortpixel.com/g/af/GWRGFLW109483';
700 - // translators: "log in to check your account" will appear in a "a href".
701 - $_imgopt_notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota are in good shape, %1$slog in to check your account%2$s.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' );
501 + if ( true === apply_filters( 'autoptimize_filter_extra_remove_woocommerce_block_css', true ) ) {
502 + add_action(
503 + 'wp_enqueue_scripts',
504 + function() {
505 + wp_dequeue_style( 'wc-blocks-style' );
702 506 }
703 - $_imgopt_notice = apply_filters( 'autoptimize_filter_imgopt_notice', $_imgopt_notice );
704 -
705 - return array(
706 - 'status' => $_stat['Status'],
707 - 'notice' => $_imgopt_notice,
708 - );
709 - }
507 + );
710 508 }
711 - return false;
712 509 }
713 510
714 - public static function get_imgopt_status_notice_wrapper() {
715 - // needed for notice being shown in autoptimizeCacheChecker.php.
716 - $self = new self();
717 - return $self->get_imgopt_status_notice();
718 - }
719 -
720 511 public function admin_menu()
721 512 {
722 - add_submenu_page( null, 'autoptimize_extra', 'autoptimize_extra', 'manage_options', 'autoptimize_extra', array( $this, 'options_page' ) );
513 + // no acces if multisite and not network admin and no site config allowed.
514 + if ( autoptimizeConfig::should_show_menu_tabs() ) {
515 + add_submenu_page(
516 + '',
517 + 'autoptimize_extra',
518 + 'autoptimize_extra',
519 + 'manage_options',
520 + 'autoptimize_extra',
521 + array( $this, 'options_page' )
522 + );
523 + }
723 524 register_setting( 'autoptimize_extra_settings', 'autoptimize_extra_settings' );
724 525 }
725 526
726 527 public function add_extra_tab( $in )
727 528 {
728 - $in = array_merge( $in, array( 'autoptimize_extra' => __( 'Extra', 'autoptimize' ) ) );
529 + if ( autoptimizeConfig::should_show_menu_tabs() ) {
530 + $in = array_merge( $in, array( 'autoptimize_extra' => esc_html__( 'Extra', 'autoptimize' ) ) );
531 + }
729 532
730 533 return $in;
731 534 }
732 535
@@ -731,209 +534,129 @@
731 534 }
732 535
733 536 public function options_page()
734 537 {
538 + // phpcs:disable Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace
539 +
735 540 // Working with actual option values from the database here.
736 541 // That way any saves are still processed as expected, but we can still
737 542 // override behavior by using `new autoptimizeExtra($custom_options)` and not have that custom
738 543 // behavior being persisted in the DB even if save is done here.
739 - $options = $this->fetch_options();
740 - $gfonts = $options['autoptimize_extra_radio_field_4'];
741 - $sp_url_suffix = '/af/GWRGFLW109483/' . AUTOPTIMIZE_SITE_DOMAIN;
742 - ?>
544 + $options = $this->fetch_options();
545 + $gfonts = $options['autoptimize_extra_radio_field_4'];
546 + ?>
743 547 <style>
744 548 #ao_settings_form {background: white;border: 1px solid #ccc;padding: 1px 15px;margin: 15px 10px 10px 0;}
745 549 #ao_settings_form .form-table th {font-weight: normal;}
746 550 #autoptimize_extra_descr{font-size: 120%;}
747 551 </style>
552 + <script>document.title = "Autoptimize: <?php esc_html_e( 'Extra', 'autoptimize' ); ?> " + document.title;</script>
748 553 <div class="wrap">
749 - <h1><?php _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
750 - <?php echo autoptimizeConfig::ao_admin_tabs(); ?>
751 - <?php
752 - if ( 'on' !== get_option( 'autoptimize_js' ) && 'on' !== get_option( 'autoptimize_css' ) && 'on' !== get_option( 'autoptimize_html' ) ) {
753 - ?>
754 - <div class="notice-warning notice"><p>
755 - <?php
756 - _e( 'Most of below Extra optimizations require at least one of HTML, JS or CSS autoptimizations being active.', 'autoptimize' );
757 - ?>
758 - </p></div>
759 - <?php
760 - }
554 + <h1><?php apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? esc_html_e( 'Autoptimize Pro Settings', 'autoptimize' ) : esc_html_e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
555 + <?php echo autoptimizeConfig::ao_admin_tabs(); ?>
556 + <?php if ( 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_js' ) && 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_css' ) && 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_html' ) && ! autoptimizeImages::imgopt_active() ) { ?>
557 + <div class="notice-warning notice"><p>
558 + <?php esc_html_e( 'Most of below Extra optimizations require at least one of HTML, JS, CSS or Image autoptimizations being active.', 'autoptimize' ); ?>
559 + </p></div>
560 + <?php } ?>
761 561
762 - if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) {
763 - ?>
764 - <div class="notice-warning notice"><p>
765 - <?php
766 - // translators: "Autoptimize support forum" will appear in a "a href".
767 - echo sprintf( __( 'The image optimization service is currently down, image optimization will be skipped until further notice. Check the %1$sAutoptimize support forum%2$s for more info.', 'autoptimize' ), '<a href="https://wordpress.org/support/plugin/autoptimize/" target="_blank">', '</a>' );
768 - ?>
769 - </p></div>
770 - <?php
771 - }
772 -
773 - if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] && ! $this->imgopt_launch_ok() ) {
774 - ?>
775 - <div class="notice-warning notice"><p>
776 - <?php
777 - _e( 'The image optimization service is launching, but not yet available for this domain, it should become available in the next couple of days.', 'autoptimize' );
778 - ?>
779 - </p></div>
780 - <?php
781 - }
782 -
783 - ?>
784 - <form id='ao_settings_form' action='options.php' method='post'>
562 + <form id='ao_settings_form' action='<?php echo admin_url( 'options.php' ); ?>' method='post'>
785 563 <?php settings_fields( 'autoptimize_extra_settings' ); ?>
786 - <h2><?php _e( 'Extra Auto-Optimizations', 'autoptimize' ); ?></h2>
787 - <span id='autoptimize_extra_descr'><?php _e( 'The following settings can improve your site\'s performance even more.', 'autoptimize' ); ?></span>
564 + <h2><?php esc_html_e( 'Extra Auto-Optimizations', 'autoptimize' ); ?></h2>
565 + <span id='autoptimize_extra_descr'><?php esc_html_e( 'The following settings can improve your site\'s performance even more.', 'autoptimize' ); ?></span>
788 566 <table class="form-table">
789 567 <tr>
790 - <th scope="row"><?php _e( 'Google Fonts', 'autoptimize' ); ?></th>
568 + <th scope="row"><?php esc_html_e( 'Google Fonts', 'autoptimize' ); ?></th>
791 569 <td>
792 - <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="1" <?php if ( ! in_array( $gfonts, array( 2, 3, 4, 5 ) ) ) { echo 'checked'; } ?> ><?php _e( 'Leave as is', 'autoptimize' ); ?><br/>
793 - <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="2" <?php checked( 2, $gfonts, true ); ?> ><?php _e( 'Remove Google Fonts', 'autoptimize' ); ?><br/>
794 - <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="3" <?php checked( 3, $gfonts, true ); ?> ><?php _e( 'Combine and link in head (fonts load fast but are render-blocking)', 'autoptimize' ); ?><br/>
795 - <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="5" <?php checked( 5, $gfonts, true ); ?> ><?php _e( 'Combine and preload in head (fonts load late, but are not render-blocking)', 'autoptimize' ); ?><br/>
796 - <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="4" <?php checked( 4, $gfonts, true ); ?> ><?php _e( 'Combine and load fonts asynchronously with <a href="https://github.com/typekit/webfontloader#readme" target="_blank">webfont.js</a>', 'autoptimize' ); ?><br/>
570 + <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="1" <?php if ( ! in_array( $gfonts, array( 2, 3, 4, 5 ) ) ) { echo 'checked'; } ?> ><?php esc_html_e( 'Leave as is', 'autoptimize' ); ?><br/>
571 + <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="2" <?php checked( 2, $gfonts, true ); ?> ><?php esc_html_e( 'Remove Google Fonts', 'autoptimize' ); ?><br/>
572 + <?php // translators: "display:swap" should remain untranslated, will be shown in code tags. ?>
573 + <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="3" <?php checked( 3, $gfonts, true ); ?> ><?php echo esc_html__( 'Combine and link in head (fonts load fast but are render-blocking)', 'autoptimize' ) . ', ' . sprintf( esc_html__( 'includes %1$sdisplay:swap%2$s.', 'autoptimize' ), '<code>', '</code>' ); ?><br/>
574 + <?php // translators: "display:swap" should remain untranslated, will be shown in code tags. ?>
575 + <input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="5" <?php checked( 5, $gfonts, true ); ?> ><?php echo esc_html__( 'Combine and link deferred in head (fonts load late, but are not render-blocking)', 'autoptimize' ) . ', ' . sprintf( esc_html__( 'includes %1$sdisplay:swap%2$s.', 'autoptimize' ), '<code>', '</code>' ); ?>
576 + <span <?php if ( '4' !== $gfonts ){ echo "style='display:none;' "; } ?> ><br/><input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="4" <?php checked( 4, $gfonts, true ); ?> ><?php echo sprintf( esc_html__( 'Combine and load fonts asynchronously with %1$swebfont.js%2$s', 'autoptimize' ), '<a href="https://github.com/typekit/webfontloader#readme" target="_blank">', '</a>' ) . ' ' . esc_html__( '(deprecated)', 'autoptimize' ); ?></span><br/>
797 577 </td>
798 578 </tr>
799 579 <tr>
800 - <th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th>
580 + <th scope="row"><?php esc_html_e( 'Remove emojis', 'autoptimize' ); ?></th>
801 581 <td>
802 - <label><input id='autoptimize_imgopt_checkbox' type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_5]' <?php if ( ! empty( $options['autoptimize_extra_checkbox_field_5'] ) && '1' === $options['autoptimize_extra_checkbox_field_5'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Optimize images on the fly and serve them from a CDN.', 'autoptimize' ); ?></label>
803 - <?php
804 - // show shortpixel status.
805 - $_notice = $this->get_imgopt_status_notice();
806 - if ( $_notice ) {
807 - switch ( $_notice['status'] ) {
808 - case 2:
809 - $_notice_color = 'green';
810 - break;
811 - case 1:
812 - $_notice_color = 'orange';
813 - break;
814 - case -1:
815 - $_notice_color = 'red';
816 - break;
817 - default:
818 - $_notice_color = 'green';
819 - }
820 - echo apply_filters( 'autoptimize_filter_imgopt_settings_status', '<p><strong><span style="color:' . $_notice_color . ';">' . __( 'Shortpixel status: ', 'autoptimize' ) . '</span></strong>' . $_notice['notice'] . '</p>' );
821 - } else {
822 - // translators: link points to shortpixel.
823 - $upsell_msg_1 = '<p>' . sprintf( __( 'Get more Google love and improve your website\'s loading speed by having the images optimized on the fly by %1$sShortPixel%2$s and then cached and served fast from a CDN.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>' );
824 - if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] ) {
825 - $upsell_msg_2 = __( 'For a limited time only, this service is offered free-for-all, <b>don\'t miss the chance to test it</b> and see how much it could improve your site\'s speed.', 'autoptimize' );
826 - } else {
827 - $upsell_msg_2 = __( 'The service is offered for free for 100 images/month regardless of the traffic used. More image optimizations can be purchased starting with $4.99.', 'autoptimize' );
828 - }
829 - echo apply_filters( 'autoptimize_extra_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
830 - }
831 - // translators: link points to shortpixel FAQ.
832 - $faqcopy = sprintf( __( '<strong>Questions</strong>? Have a look at the %1$sShortPixel FAQ%2$s!', 'autoptimize' ), '<strong><a href="https://shortpixel.helpscoutdocs.com/category/60-shortpixel-ai-cdn" target="_blank">', '</strong></a>' );
833 - // translators: links points to shortpixel TOS & Privacy Policy.
834 - $toscopy = sprintf( __( 'Usage of this feature is subject to Shortpixel\'s %1$sTerms of Use%2$s and %3$sPrivacy policy%4$s.', 'autoptimize' ), '<a href="https://shortpixel.com/tos' . $sp_url_suffix . '" target="_blank">', '</a>', '<a href="https://shortpixel.com/pp' . $sp_url_suffix . '" target="_blank">', '</a>' );
835 - echo apply_filters( 'autoptimize_extra_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
836 - ?>
582 + <label><input type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_1]' <?php if ( ! empty( $options['autoptimize_extra_checkbox_field_1'] ) && '1' === $options['autoptimize_extra_checkbox_field_1'] ) { echo 'checked="checked"'; } ?> value='1'><?php esc_html_e( 'Removes WordPress\' core emojis\' inline CSS, inline JavaScript, and an otherwise un-autoptimized JavaScript file.', 'autoptimize' ); ?></label>
837 583 </td>
838 584 </tr>
839 - <tr id='autoptimize_imgopt_quality' <?php if ( ! array_key_exists( 'autoptimize_extra_checkbox_field_5', $options ) || ( ! empty( $options['autoptimize_extra_checkbox_field_5'] ) && '1' !== $options['autoptimize_extra_checkbox_field_5'] ) ) { echo 'class="hidden"'; } ?>>
840 - <th scope="row"><?php _e( 'Image Optimization quality', 'autoptimize' ); ?></th>
585 + <tr>
586 + <th scope="row"><?php esc_html_e( 'Remove query strings from static resources', 'autoptimize' ); ?></th>
841 587 <td>
842 - <label>
843 - <select name='autoptimize_extra_settings[autoptimize_extra_select_field_6]'>
844 - <?php
845 - $_imgopt_array = $this->get_img_quality_array();
846 - $_imgopt_val = $this->get_img_quality_setting();
847 -
848 - foreach ( $_imgopt_array as $key => $value ) {
849 - echo '<option value="' . $key . '"';
850 - if ( $_imgopt_val == $key ) {
851 - echo ' selected';
852 - }
853 - echo '>' . ucfirst( $value ) . '</option>';
854 - }
855 - echo "\n";
856 - ?>
857 - </select>
588 + <label><input type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_0]' <?php if ( ! empty( $options['autoptimize_extra_checkbox_field_0'] ) && '1' === $options['autoptimize_extra_checkbox_field_0'] ) { echo 'checked="checked"'; } ?> value='1'>
589 + <?php
590 + // translators: just a code tag around "ver" which is the parameter added to CSS/ JS URL's by wordpress.
591 + printf( esc_html__( 'Removing query strings (or more specifically the %1$sver%2$s parameter) will not improve load time, but might improve performance scores.', 'autoptimize' ), '<code>', '</code>' );
592 + ?>
858 593 </label>
859 - <p>
860 - <?php
861 - // translators: link points to shortpixel image test page.
862 - echo apply_filters( 'autoptimize_extra_imgopt_quality_copy', sprintf( __( 'You can %1$stest compression levels here%2$s.', 'autoptimize' ), '<a href="https://shortpixel.com/oic' . $sp_url_suffix . '" target="_blank">', '</a>' ) );
863 - ?>
864 - </p>
865 594 </td>
866 595 </tr>
867 596 <tr>
868 - <th scope="row"><?php _e( 'Remove emojis', 'autoptimize' ); ?></th>
597 + <th scope="row"><?php esc_html_e( 'Remove WordPress block CSS', 'autoptimize' ); ?></th>
869 598 <td>
870 - <label><input type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_1]' <?php if ( ! empty( $options['autoptimize_extra_checkbox_field_1'] ) && '1' === $options['autoptimize_extra_checkbox_field_1'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Removes WordPress\' core emojis\' inline CSS, inline JavaScript, and an otherwise un-autoptimized JavaScript file.', 'autoptimize' ); ?></label>
599 + <label><input type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_8]' <?php if ( ! empty( $options['autoptimize_extra_checkbox_field_8'] ) && '1' === $options['autoptimize_extra_checkbox_field_8'] ) { echo 'checked="checked"'; } ?> value='1'><?php esc_html_e( 'WordPress adds block CSS and global styles to improve easy styling of block-based sites, but which can add a significant amount of CSS and SVG. If you are sure your site can do without the block CSS and "global styles", you can disable them here.', 'autoptimize' ); ?></label>
871 600 </td>
872 601 </tr>
873 602 <tr>
874 - <th scope="row"><?php _e( 'Remove query strings from static resources', 'autoptimize' ); ?></th>
603 + <th scope="row"><?php esc_html_e( 'Preconnect to 3rd party domains (advanced users)', 'autoptimize' ); ?></th>
875 604 <td>
876 - <label><input type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_0]' <?php if ( ! empty( $options['autoptimize_extra_checkbox_field_0'] ) && '1' === $options['autoptimize_extra_checkbox_field_0'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Removing query strings (or more specifically the <code>ver</code> parameter) will not improve load time, but might improve performance scores.', 'autoptimize' ); ?></label>
605 + <label><input type='text' style='width:80%' name='autoptimize_extra_settings[autoptimize_extra_text_field_2]' value='<?php if ( array_key_exists( 'autoptimize_extra_text_field_2', $options ) ) { echo esc_attr( $options['autoptimize_extra_text_field_2'] ); } ?>'><br />
606 + <?php
607 + // Translators; link to a page on keycdn blog about preconnecting.
608 + printf( esc_html__( 'Add 3rd party domains you want the browser to %1$spreconnect%2$s to, separated by comma\'s. Make sure to include the correct protocol (HTTP or HTTPS).', 'autoptimize' ), '<a href="https://www.keycdn.com/support/preconnect/#primary" target="_blank">', '</a>' );
609 + ?>
610 + </label>
877 611 </td>
878 612 </tr>
879 613 <tr>
880 - <th scope="row"><?php _e( 'Preconnect to 3rd party domains <em>(advanced users)</em>', 'autoptimize' ); ?></th>
614 + <th scope="row"><?php esc_html_e( 'Preload specific requests (advanced users)', 'autoptimize' ); ?></th>
881 615 <td>
882 - <label><input type='text' style='width:80%' name='autoptimize_extra_settings[autoptimize_extra_text_field_2]' value='<?php echo esc_attr( $options['autoptimize_extra_text_field_2'] ); ?>'><br /><?php _e( 'Add 3rd party domains you want the browser to <a href="https://www.keycdn.com/support/preconnect/#primary" target="_blank">preconnect</a> to, separated by comma\'s. Make sure to include the correct protocol (HTTP or HTTPS).', 'autoptimize' ); ?></label>
616 + <label><input type='text' style='width:80%' name='autoptimize_extra_settings[autoptimize_extra_text_field_7]' value='<?php if ( array_key_exists( 'autoptimize_extra_text_field_7', $options ) ) { echo esc_attr( $options['autoptimize_extra_text_field_7'] ); } ?>'><br /><?php esc_html_e( 'Comma-separated list with full URL\'s of to to-be-preloaded resources. To be used sparingly!', 'autoptimize' ); ?></label>
883 617 </td>
884 618 </tr>
885 619 <tr>
886 - <th scope="row"><?php _e( 'Async Javascript-files <em>(advanced users)</em>', 'autoptimize' ); ?></th>
620 + <th scope="row"><?php esc_html_e( 'Async Javascript-files (advanced users)', 'autoptimize' ); ?></th>
887 621 <td>
888 622 <?php
889 - if ( function_exists( 'is_plugin_active' ) && is_plugin_active( 'async-javascript/async-javascript.php' ) ) {
623 + if ( autoptimizeUtils::is_plugin_active( 'async-javascript/async-javascript.php' ) ) {
890 624 // translators: link points Async Javascript settings page.
891 - printf( __( 'You have "Async JavaScript" installed, %1$sconfiguration of async javascript is best done there%2$s.', 'autoptimize' ), '<a href="' . 'options-general.php?page=async-javascript' . '">', '</a>' );
625 + printf( esc_html__( 'You have "Async JavaScript" installed, %1$sconfiguration of async javascript is best done there%2$s.', 'autoptimize' ), '<a href="' . 'options-general.php?page=async-javascript' . '">', '</a>' );
892 626 } else {
893 - ?>
894 - <input type='text' style='width:80%' name='autoptimize_extra_settings[autoptimize_extra_text_field_3]' value='<?php echo esc_attr( $options['autoptimize_extra_text_field_3'] ); ?>'>
627 + ?>
628 + <input type='text' style='width:80%' name='autoptimize_extra_settings[autoptimize_extra_text_field_3]' value='<?php if ( array_key_exists( 'autoptimize_extra_text_field_3', $options ) ) { echo esc_attr( $options['autoptimize_extra_text_field_3'] ); } ?>'>
895 629 <br />
896 630 <?php
897 - _e( 'Comma-separated list of local or 3rd party JS-files that should loaded with the <code>async</code> flag. JS-files from your own site will be automatically excluded if added here. ', 'autoptimize' );
631 + printf( esc_html__( 'Comma-separated list of local or 3rd party JS-files that should loaded with the %1$sasync%2$s flag. JS-files from your own site will be automatically excluded if added here. ', 'autoptimize' ), '<code>', '</code>' );
898 632 // translators: %s will be replaced by a link to the "async javascript" plugin.
899 - echo sprintf( __( 'Configuration of async javascript is easier and more flexible using the %s plugin.', 'autoptimize' ), '"<a href="https://wordpress.org/plugins/async-javascript" target="_blank">Async Javascript</a>"' );
633 + echo sprintf( esc_html__( 'Configuration of async javascript is easier and more flexible using the %s plugin.', 'autoptimize' ), '"<a href="https://wordpress.org/plugins/async-javascript" target="_blank">Async Javascript</a>"' );
900 634 $asj_install_url = network_admin_url() . 'plugin-install.php?s=async+javascript&tab=search&type=term';
901 - echo sprintf( ' <a href="' . $asj_install_url . '">%s</a>', __( 'Click here to install and activate it.', 'autoptimize' ) );
635 + echo sprintf( ' <a href="' . $asj_install_url . '">%s</a>', esc_html__( 'Click here to install and activate it.', 'autoptimize' ) );
902 636 }
903 637 ?>
904 638 </td>
905 639 </tr>
906 640 <tr>
907 - <th scope="row"><?php _e( 'Optimize YouTube videos', 'autoptimize' ); ?></th>
641 + <th scope="row"><?php esc_html_e( 'Optimize YouTube videos', 'autoptimize' ); ?></th>
908 642 <td>
909 643 <?php
910 - if ( function_exists( 'is_plugin_active' ) && is_plugin_active( 'wp-youtube-lyte/wp-youtube-lyte.php' ) ) {
911 - _e( 'Great, you have WP YouTube Lyte installed.', 'autoptimize' );
644 + if ( autoptimizeUtils::is_plugin_active( 'wp-youtube-lyte/wp-youtube-lyte.php' ) ) {
645 + esc_html_e( 'Great, you have WP YouTube Lyte installed.', 'autoptimize' );
912 646 $lyte_config_url = 'options-general.php?page=lyte_settings_page';
913 - echo sprintf( ' <a href="' . $lyte_config_url . '">%s</a>', __( 'Click here to configure it.', 'autoptimize' ) );
647 + echo sprintf( ' <a href="' . $lyte_config_url . '">%s</a>', esc_html__( 'Click here to configure it.', 'autoptimize' ) );
914 648 } else {
915 649 // translators: %s will be replaced by a link to "wp youtube lyte" plugin.
916 - echo sprintf( __( '%s allows you to “lazy load” your videos, by inserting responsive “Lite YouTube Embeds". ', 'autoptimize' ), '<a href="https://wordpress.org/plugins/wp-youtube-lyte" target="_blank">WP YouTube Lyte</a>' );
650 + echo sprintf( esc_html__( '%s allows you to “lazy load” your videos, by inserting responsive “Lite YouTube Embeds". ', 'autoptimize' ), '<a href="https://wordpress.org/plugins/wp-youtube-lyte" target="_blank">WP YouTube Lyte</a>' );
917 651 $lyte_install_url = network_admin_url() . 'plugin-install.php?s=lyte&tab=search&type=term';
918 - echo sprintf( ' <a href="' . $lyte_install_url . '">%s</a>', __( 'Click here to install and activate it.', 'autoptimize' ) );
652 + echo sprintf( ' <a href="' . $lyte_install_url . '">%s</a>', esc_html__( 'Click here to install and activate it.', 'autoptimize' ) );
919 653 }
920 654 ?>
921 655 </td>
922 656 </tr>
923 657 </table>
924 - <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" /></p>
658 + <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php esc_html_e( 'Save Changes', 'autoptimize' ); ?>" /></p>
925 659 </form>
926 - <script>
927 - jQuery(document).ready(function() {
928 - jQuery( "#autoptimize_imgopt_checkbox" ).change(function() {
929 - if (this.checked) {
930 - jQuery("#autoptimize_imgopt_quality").show("slow");
931 - } else {
932 - jQuery("#autoptimize_imgopt_quality").hide("slow");
933 - }
934 - });
935 - });
936 - </script>
937 - <?php
660 + <?php
938 661 }
939 662 }