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 +263 -622 2.4.2 → 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,41 +195,19 @@
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 kicks in if;
157 - // * the option is activated by user.
158 - // * imgopt user stats does not have status -2.
159 - // * imgopt status is not "down".
160 - // * imgopt status is not "launch" or imgopt_launch_ok() returns be true.
161 - $_do_cdn = true;
162 - $_userstatus = $this->get_imgopt_provider_userstatus();
163 - if ( -2 == $_userstatus['Status'] ) {
164 - $_do_cdn = false;
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 );
165 202 }
166 203
167 - if ( ! empty( $options['autoptimize_extra_checkbox_field_5'] ) && $_do_cdn && 'down' !== $options['availabilities']['extra_imgopt']['status'] && ( 'launch' !== $options['availabilities']['extra_imgopt']['status'] || $this->imgopt_launch_ok() ) ) {
168 - if ( apply_filters( 'autoptimize_filter_extra_imgopt_do', true ) ) {
169 - add_filter( 'autoptimize_html_after_minify', array( $this, 'filter_optimize_images' ), 10, 1 );
170 - $_imgopt_active = true;
171 - }
172 - if ( apply_filters( 'autoptimize_filter_extra_imgopt_do_css', true ) ) {
173 - add_filter( 'autoptimize_filter_base_replace_cdn', array( $this, 'filter_optimize_css_images' ), 10, 1 );
174 - $_imgopt_active = true;
175 - }
176 - if ( $_imgopt_active ) {
177 - add_filter( 'autoptimize_extra_filter_tobepreconn', array( $this, 'filter_preconnect_imgopt_url' ), 10, 1 );
178 - }
204 + // Remove global styles.
205 + if ( ! empty( $options['autoptimize_extra_checkbox_field_8'] ) ) {
206 + $this->disable_global_styles();
179 207 }
180 208 }
181 209
182 - public function filter_remove_emoji_dns_prefetch( $urls, $relation_type )
183 - {
184 - $emoji_svg_url = apply_filters( 'emoji_svg_url', 'https://s.w.org/images/core/emoji/' );
185 -
186 - return $this->filter_remove_dns_prefetch( $urls, $relation_type, $emoji_svg_url );
187 - }
188 -
189 210 public function filter_remove_gfonts_dnsprefetch( $urls, $relation_type )
190 211 {
191 212 return $this->filter_remove_dns_prefetch( $urls, $relation_type, 'fonts.googleapis.com' );
192 213 }
@@ -192,12 +213,23 @@
192 213 }
193 214
194 215 public function filter_remove_dns_prefetch( $urls, $relation_type, $url_to_remove )
195 216 {
196 - if ( 'dns-prefetch' === $relation_type ) {
217 + $url_to_remove = (string) $url_to_remove;
218 +
219 + if ( ! empty( $url_to_remove ) && 'dns-prefetch' === $relation_type ) {
197 220 $cnt = 0;
198 221 foreach ( $urls as $url ) {
199 - 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 ) ) {
200 232 unset( $urls[ $cnt ] );
201 233 }
202 234 $cnt++;
203 235 }
@@ -222,8 +254,14 @@
222 254 foreach ( $matches[2] as $font ) {
223 255 if ( ! preg_match( '/rel=["\']dns-prefetch["\']/', $matches[0][ $i ] ) ) {
224 256 // Get fonts name.
225 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 + }
226 264 $font = explode( 'family=', $font );
227 265 $font = ( isset( $font[1] ) ) ? explode( '&', $font[1] ) : array();
228 266 // Add font to $fonts[$i] but make sure not to pollute with an empty family!
229 267 $_thisfont = array_values( array_filter( explode( '|', reset( $font ) ) ) );
@@ -264,17 +302,21 @@
264 302 $subset_string = str_replace( ',', '%2C', ltrim( $subset_string, ',' ) );
265 303 $fonts_string = $fonts_string . '&subset=' . $subset_string;
266 304 }
267 305
268 - $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 + }
269 311
270 312 if ( ! empty( $fonts_string ) ) {
271 313 if ( '5' === $options['autoptimize_extra_radio_field_4'] ) {
272 - $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() . '"';
273 315 } else {
274 316 $rel_string = 'rel="stylesheet"';
275 317 }
276 - $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 . '">';
277 319 }
278 320 } elseif ( '4' === $options['autoptimize_extra_radio_field_4'] ) {
279 321 // Aggregate & load async (webfont.js impl.)!
280 322 $fonts_array = array();
@@ -288,43 +330,53 @@
288 330 }
289 331 $fonts_array = array_merge( $fonts_array, $_fonts['fonts'] );
290 332 }
291 333
292 - $fonts_markup = '<script data-cfasync="false" id="ao_optimized_gfonts" type="text/javascript">WebFontConfig={google:{families:[\'';
293 - foreach ( $fonts_array as $fnt ) {
294 - $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" ';
295 346 }
296 - $fonts_markup = trim( trim( $fonts_markup, "'" ), ',' );
297 - $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>' ) );
298 351 }
299 352
300 353 // Replace back in markup.
301 - $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 ) );
302 356 unset( $fonts_collection );
303 357
304 - // and insert preload polyfill if "link preload" and if the polyfill isn't there yet (courtesy of inline&defer).
305 - $preload_polyfill = autoptimizeConfig::get_ao_css_preload_polyfill();
306 - if ( '5' === $options['autoptimize_extra_radio_field_4'] && strpos( $out, $preload_polyfill ) === false ) {
307 - $out = str_replace( '</body>', $preload_polyfill . '</body>', $out );
308 - }
309 358 return $out;
310 359 }
311 360
312 361 public function filter_preconnect( $hints, $relation_type )
313 362 {
314 - $options = $this->options;
363 + $options = $this->options;
364 + $preconns = array();
315 365
316 366 // Get settings and store in array.
317 - $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 + }
318 370 $preconns = apply_filters( 'autoptimize_extra_filter_tobepreconn', $preconns );
319 371
320 372 // Walk array, extract domain and add to new array with crossorigin attribute.
321 373 foreach ( $preconns as $preconn ) {
374 + $domain = '';
322 375 $parsed = parse_url( $preconn );
323 -
324 - if ( is_array( $parsed ) && empty( $parsed['scheme'] ) ) {
376 + if ( is_array( $parsed ) && ! empty( $parsed['host'] ) && empty( $parsed['scheme'] ) ) {
325 377 $domain = '//' . $parsed['host'];
326 - } elseif ( is_array( $parsed ) ) {
378 + } elseif ( is_array( $parsed ) && ! empty( $parsed['host'] ) ) {
327 379 $domain = $parsed['scheme'] . '://' . $parsed['host'];
328 380 }
329 381
330 382 if ( ! empty( $domain ) ) {
@@ -362,444 +414,122 @@
362 414
363 415 return $in;
364 416 }
365 417
366 - public function filter_optimize_images( $in )
367 - {
368 - /*
369 - * potential future functional improvements:
370 - *
371 - * picture element.
372 - * filter for critical CSS.
373 - */
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 + }
374 425
375 - $imgopt_base_url = $this->get_imgopt_base_url();
376 - $to_replace = array();
377 -
378 - // extract img tags.
379 - if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
380 - foreach ( $matches[0] as $tag ) {
381 - $orig_tag = $tag;
382 - $imgopt_w = '';
383 - $imgopt_h = '';
384 -
385 - // first do (data-)srcsets.
386 - if ( preg_match_all( '#srcset=("|\')(.*)("|\')#Usmi', $tag, $allsrcsets, PREG_SET_ORDER ) ) {
387 - foreach ( $allsrcsets as $srcset ) {
388 - $srcset = $srcset[2];
389 - $srcsets = explode( ',', $srcset );
390 - foreach ( $srcsets as $indiv_srcset ) {
391 - $indiv_srcset_parts = explode( ' ', trim( $indiv_srcset ) );
392 - if ( $indiv_srcset_parts[1] && rtrim( $indiv_srcset_parts[1], 'w' ) !== $indiv_srcset_parts[1] ) {
393 - $imgopt_w = rtrim( $indiv_srcset_parts[1], 'w' );
394 - }
395 - if ( $this->can_optimize_image( $indiv_srcset_parts[0] ) ) {
396 - $imgopt_url = $this->build_imgopt_url( $indiv_srcset_parts[0], $imgopt_w, '' );
397 - $tag = str_replace( $indiv_srcset_parts[0], $imgopt_url, $tag );
398 - $to_replace[ $orig_tag ] = $tag;
399 - }
400 - }
401 - }
402 - }
403 -
404 - // proceed with img src.
405 - // first reset and then get width and height and add to $imgopt_size.
406 - $imgopt_w = '';
407 - $imgopt_h = '';
408 - if ( preg_match( '#width=("|\')(.*)("|\')#Usmi', $tag, $width ) ) {
409 - $imgopt_w = $width[2];
410 - }
411 - if ( preg_match( '#height=("|\')(.*)("|\')#Usmi', $tag, $height ) ) {
412 - $imgopt_h = $height[2];
413 - }
414 -
415 - // then start replacing images src.
416 - if ( preg_match_all( '#src=(?:"|\')(?!data)(.*)(?:"|\')#Usmi', $tag, $urls, PREG_SET_ORDER ) ) {
417 - foreach ( $urls as $url ) {
418 - $full_src_orig = $url[0];
419 - $url = $url[1];
420 - if ( $this->can_optimize_image( $url ) ) {
421 - $imgopt_url = $this->build_imgopt_url( $url, $imgopt_w, $imgopt_h );
422 - $full_imgopt_src = str_replace( $url, $imgopt_url, $full_src_orig );
423 - $tag = str_replace( $full_src_orig, $full_imgopt_src, $tag );
424 - $to_replace[ $orig_tag ] = $tag;
425 - }
426 - }
427 - }
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 );
428 431 }
429 432 }
430 - $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $in );
431 433
432 - // img thumbnails in e.g. woocommerce.
433 - if ( strpos( $out, 'data-thumb' ) !== false && apply_filters( 'autoptimize_filter_extra_imgopt_datathumbs', true ) ) {
434 - $out = preg_replace_callback(
435 - '/\<div(?:[^>]?)\sdata-thumb\=(?:\"|\')(.+?)(?:\"|\')(?:[^>]*)?\>/s',
436 - array( $this, 'replace_data_thumbs' ),
437 - $out
438 - );
439 - }
434 + $preloads = apply_filters( 'autoptimize_filter_extra_tobepreloaded', $preloads );
440 435
441 - return $out;
442 - }
443 -
444 - public function filter_optimize_css_images( $in )
445 - {
446 - $imgopt_base_url = $this->get_imgopt_base_url();
447 - $in = $this->normalize_img_urls( $in );
448 -
449 - if ( $this->can_optimize_image( $in ) ) {
450 - return $this->build_imgopt_url( $in, '', '' );
451 - } else {
436 + // immediately return if nothing to be preloaded.
437 + if ( empty( $preloads ) ) {
452 438 return $in;
453 439 }
454 - }
455 440
456 - private function get_imgopt_base_url()
457 - {
458 - 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, '?' );
459 452
460 - if ( is_null( $imgopt_base_url ) ) {
461 - $imgopt_host = $this->get_imgopt_host();
462 - $quality = $this->get_img_quality_string();
463 - $ret_val = apply_filters( 'autoptimize_filter_extra_imgopt_wait', 'ret_img' ); // values: ret_wait, ret_img, ret_json, ret_blank.
464 - $imgopt_base_url = $imgopt_host . 'client/' . $quality . ',' . $ret_val;
465 - $imgopt_base_url = apply_filters( 'autoptimize_filter_extra_imgopt_base_url', $imgopt_base_url );
466 - }
467 -
468 - return $imgopt_base_url;
469 - }
470 -
471 - private function can_optimize_image( $url )
472 - {
473 - static $cdn_url = null;
474 - static $nopti_images = null;
475 -
476 - if ( is_null( $cdn_url ) ) {
477 - $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', get_option( 'autoptimize_cdn_url', '' ) );
478 - }
479 -
480 - if ( is_null( $nopti_images ) ) {
481 - $nopti_images = apply_filters( 'autoptimize_filter_extra_imgopt_noptimize', '' );
482 - }
483 -
484 - $imgopt_base_url = $this->get_imgopt_base_url();
485 - $site_host = AUTOPTIMIZE_SITE_DOMAIN;
486 - $url_parsed = parse_url( $url );
487 -
488 - if ( $url_parsed['host'] !== $site_host && empty( $cdn_url ) ) {
489 - return false;
490 - } elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && $url_parsed['host'] !== $site_host ) {
491 - return false;
492 - } elseif ( strpos( $url, '.php' ) !== false ) {
493 - return false;
494 - } elseif ( str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg', '.webp' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) {
495 - // fixme: better check against end of string.
496 - return false;
497 - } elseif ( ! empty( $nopti_images ) ) {
498 - $nopti_images_array = array_filter( array_map( 'trim', explode( ',', $nopti_images ) ) );
499 - foreach ( $nopti_images_array as $nopti_image ) {
500 - if ( strpos( $url, $nopti_image ) !== false ) {
501 - 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';
502 463 }
503 - }
504 - }
505 - return true;
506 - }
507 -
508 - private function build_imgopt_url( $orig_url, $width = 0, $height = 0 )
509 - {
510 - // sanitize width and height.
511 - if ( strpos( $width, '%' ) !== false ) {
512 - $width = 0;
513 - }
514 - if ( strpos( $height, '%' ) !== false ) {
515 - $height = 0;
516 - }
517 - $width = (int) $width;
518 - $height = (int) $height;
519 -
520 - $filtered_url = apply_filters( 'autoptimize_filter_extra_imgopt_build_url', $orig_url, $width, $height );
521 -
522 - if ( $filtered_url !== $orig_url ) {
523 - return $filtered_url;
524 - }
525 -
526 - $orig_url = $this->normalize_img_urls( $orig_url );
527 - $imgopt_base_url = $this->get_imgopt_base_url();
528 - $imgopt_size = '';
529 -
530 - if ( $width && 0 !== $width ) {
531 - $imgopt_size = ',w_' . $width;
532 - }
533 -
534 - if ( $height && 0 !== $height ) {
535 - $imgopt_size .= ',h_' . $height;
536 - }
537 -
538 - $url = $imgopt_base_url . $imgopt_size . '/' . $orig_url;
539 -
540 - return $url;
541 - }
542 -
543 - public function replace_data_thumbs( $matches )
544 - {
545 - if ( $this->can_optimize_image( $matches[1] ) ) {
546 - return str_replace( $matches[1], $this->build_imgopt_url( $matches[1], 150, 150 ), $matches[0] );
547 - } else {
548 - return $matches[0];
549 - }
550 - }
551 -
552 - public function filter_preconnect_imgopt_url( $in )
553 - {
554 - $imgopt_url_array = parse_url( $this->get_imgopt_base_url() );
555 - $in[] = $imgopt_url_array['scheme'] . '://' . $imgopt_url_array['host'];
556 -
557 - return $in;
558 - }
559 -
560 - private function normalize_img_urls( $in )
561 - {
562 - static $cdn_domain = null;
563 - if ( is_null( $cdn_domain ) ) {
564 - $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', get_option( 'autoptimize_cdn_url', '' ) );
565 - if ( ! empty( $cdn_url ) ) {
566 - $cdn_domain = parse_url( $cdn_url, PHP_URL_HOST );
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';
567 466 } else {
568 - $cdn_domain = '';
467 + $preload_as = 'other';
569 468 }
570 - }
571 469
572 - $parsed_site_url = parse_url( site_url() );
573 -
574 - if ( strpos( $in, 'http' ) !== 0 && strpos( $in, '//' ) === 0 ) {
575 - $in = $parsed_site_url['scheme'] . ':' . $in;
576 - } elseif ( strpos( $in, '/' ) === 0 ) {
577 - $in = $parsed_site_url['scheme'] . '://' . $parsed_site_url['host'] . $in;
578 - } elseif ( ! empty( $cdn_domain ) && strpos( $in, $cdn_domain ) !== 0 ) {
579 - $in = str_replace( $cdn_domain, $parsed_site_url['host'], $in );
470 + $preload_output .= '<link rel="preload" fetchpriority="high" href="' . $preload . '" as="' . $preload_as . '"' . $mime_type . $crossorigin . '>';
580 471 }
472 + $preload_output = apply_filters( 'autoptimize_filter_extra_preload_output', $preload_output );
581 473
582 - return apply_filters( 'autoptimize_filter_extra_imgopt_normalized_url', $in );
474 + return $this->inject_preloads( $preload_output, $in );
583 475 }
584 476
585 - private function get_img_quality_array()
586 - {
587 - static $img_quality_array = null;
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 );
588 481
589 - if ( is_null( $img_quality_array ) ) {
590 - $img_quality_array = array(
591 - '1' => 'lossy',
592 - '2' => 'glossy',
593 - '3' => 'lossless',
594 - );
595 - $img_quality_array = apply_filters( 'autoptimize_filter_extra_imgopt_quality_array', $img_quality_array );
596 - }
597 -
598 - return $img_quality_array;
482 + return autoptimizeUtils::substr_replace( $html, $preloads . $preload_inject, $position, strlen( $preload_inject ) );
599 483 }
600 484
601 - private function get_img_quality_setting()
485 + public function disable_global_styles()
602 486 {
603 - static $_img_q = 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' );
604 490
605 - if ( is_null( $_img_q ) ) {
606 - if ( is_array( $this->options ) && array_key_exists( 'autoptimize_extra_select_field_6', $this->options ) ) {
607 - $_setting = $this->options['autoptimize_extra_select_field_6'];
608 - }
609 -
610 - if ( ! $_setting || empty( $_setting ) || ( '1' !== $_setting && '3' !== $_setting ) ) {
611 - // default image opt. value is 2 ("glossy").
612 - $_img_q = '2';
613 - } else {
614 - $_img_q = $_setting;
615 - }
616 - }
617 -
618 - return $_img_q;
619 - }
620 -
621 - private function get_img_quality_string()
622 - {
623 - static $_img_q_string = null;
624 -
625 - if ( is_null( $_img_q_string ) ) {
626 - $_quality_array = $this->get_img_quality_array();
627 - $_setting = $this->get_img_quality_setting();
628 - $_img_q_string = apply_filters( 'autoptimize_filter_extra_imgopt_quality', 'q_' . $_quality_array[ $_setting ] );
629 - }
630 -
631 - return $_img_q_string;
632 - }
633 -
634 - public static function get_img_provider_stats()
635 - {
636 - // wrapper around query_img_provider_stats() so we can get to $this->options from cronjob() in autoptimizeCacheChecker.
637 - $self = new self();
638 - return $self->query_img_provider_stats();
639 - }
640 -
641 - public function query_img_provider_stats()
642 - {
643 - if ( ! empty( $this->options['autoptimize_extra_checkbox_field_5'] ) ) {
644 - $_img_provider_stat_url = '';
645 - $_img_provider_endpoint = $this->get_imgopt_host() . 'read-domain/';
646 - $_site_host = AUTOPTIMIZE_SITE_DOMAIN;
647 -
648 - // make sure parse_url result makes sense, keeping $_img_provider_stat_url empty if not.
649 - if ( $_site_host && ! empty( $_site_host ) ) {
650 - $_img_provider_stat_url = $_img_provider_endpoint . $_site_host;
651 - }
652 -
653 - $_img_provider_stat_url = apply_filters( 'autoptimize_filter_extra_imgopt_stat_url', $_img_provider_stat_url );
654 -
655 - // only do the remote call if $_img_provider_stat_url is not empty to make sure no parse_url weirdness results in useless calls.
656 - if ( ! empty( $_img_provider_stat_url ) ) {
657 - $_img_stat_resp = wp_remote_get( $_img_provider_stat_url );
658 - if ( ! is_wp_error( $_img_stat_resp ) ) {
659 - if ( '200' == wp_remote_retrieve_response_code( $_img_stat_resp ) ) {
660 - $_img_provider_stat = json_decode( wp_remote_retrieve_body( $_img_stat_resp ), true );
661 - $_img_provider_stat['timestamp'] = time();
662 - update_option( 'autoptimize_imgopt_provider_stat', $_img_provider_stat );
663 - }
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' );
664 497 }
665 - }
498 + );
666 499 }
667 - }
668 500
669 - public function imgopt_launch_ok()
670 - {
671 - static $launch_status = null;
672 -
673 - if ( is_null( $launch_status ) ) {
674 - $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
675 - $magic_number = intval( substr( md5( parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ), 0, 3 ), 16 );
676 - $has_launched = get_option( 'autoptimize_imgopt_launched', '' );
677 - if ( $has_launched || ( is_array( $avail_imgopt ) && array_key_exists( 'launch-threshold', $avail_imgopt ) && $magic_number < $avail_imgopt['launch-threshold'] ) ) {
678 - $launch_status = true;
679 - if ( ! $has_launched ) {
680 - update_option( 'autoptimize_imgopt_launched', 'on' );
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' );
681 506 }
682 - } else {
683 - $launch_status = false;
684 - }
507 + );
685 508 }
686 -
687 - return $launch_status;
688 509 }
689 510
690 - public static function imgopt_launch_ok_wrapper()
511 + public function admin_menu()
691 512 {
692 - // needed for "plug" notice in autoptimizeMain.php.
693 - $self = new self();
694 - return $self->imgopt_launch_ok();
695 - }
696 -
697 - public function get_imgopt_host()
698 - {
699 - static $imgopt_host = null;
700 -
701 - if ( is_null( $imgopt_host ) ) {
702 - $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
703 - if ( ! empty( $avail_imgopt ) && array_key_exists( 'hosts', $avail_imgopt ) && is_array( $avail_imgopt['hosts'] ) ) {
704 - $imgopt_host = array_rand( array_flip( $avail_imgopt['hosts'] ) );
705 - } else {
706 - $imgopt_host = 'https://cdn.shortpixel.ai/';
707 - }
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 + );
708 523 }
709 -
710 - return $imgopt_host;
711 - }
712 -
713 - public static function get_imgopt_host_wrapper()
714 - {
715 - // needed for CI tests.
716 - $self = new self();
717 - return $self->get_imgopt_host();
718 - }
719 -
720 - public function get_imgopt_status_notice() {
721 - $_extra_options = $this->options;
722 - 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'] ) ) {
723 - $_imgopt_notice = '';
724 - $_stat = $this->get_imgopt_provider_userstatus();
725 - $_site_host = AUTOPTIMIZE_SITE_DOMAIN;
726 - $_imgopt_upsell = 'https://shortpixel.com/aospai/af/GWRGFLW109483/' . $_site_host;
727 -
728 - if ( is_array( $_stat ) ) {
729 - if ( 1 == $_stat['Status'] ) {
730 - // translators: "add more credits" will appear in a "a href".
731 - $_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>' );
732 - } elseif ( -1 == $_stat['Status'] || -2 == $_stat['Status'] ) {
733 - // translators: "add more credits" will appear in a "a href".
734 - $_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>' );
735 - $_imgopt_stats_refresh_url = add_query_arg( array(
736 - 'page' => 'autoptimize_extra',
737 - 'refreshImgProvStats' => '1',
738 - ), admin_url( 'options-general.php' ) );
739 - if ( $_stat && array_key_exists( 'timestamp', $_stat ) && ! empty( $_stat['timestamp'] ) ) {
740 - $_imgopt_stats_last_run = __( 'based on status at ', 'autoptimize' ) . date_i18n( get_option( 'time_format' ), $_stat['timestamp'] );
741 - } else {
742 - $_imgopt_stats_last_run = __( 'based on previously fetched data', 'autoptimize' );
743 - }
744 - $_imgopt_notice .= ' (' . $_imgopt_stats_last_run . ', ';
745 - // translators: "here to refresh" links to the Autoptimize Extra page and forces a refresh of the img opt stats.
746 - $_imgopt_notice .= sprintf( __( 'click %1$shere to refresh%2$s', 'autoptimize' ), '<a href="' . $_imgopt_stats_refresh_url . '">', '</a>).' );
747 - } else {
748 - $_imgopt_upsell = 'https://shortpixel.com/g/af/GWRGFLW109483';
749 - // translators: "log in to check your account" will appear in a "a href".
750 - $_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>' );
751 - }
752 - $_imgopt_notice = apply_filters( 'autoptimize_filter_imgopt_notice', $_imgopt_notice );
753 -
754 - return array(
755 - 'status' => $_stat['Status'],
756 - 'notice' => $_imgopt_notice,
757 - );
758 - }
759 - }
760 - return false;
761 - }
762 -
763 - public static function get_imgopt_status_notice_wrapper() {
764 - // needed for notice being shown in autoptimizeCacheChecker.php.
765 - $self = new self();
766 - return $self->get_imgopt_status_notice();
767 - }
768 -
769 - public function get_imgopt_provider_userstatus() {
770 - static $_provider_userstatus = null;
771 -
772 - if ( is_null( $_provider_userstatus ) ) {
773 - $_stat = get_option( 'autoptimize_imgopt_provider_stat', '' );
774 - if ( is_array( $_stat ) ) {
775 - if ( array_key_exists( 'Status', $_stat ) ) {
776 - $_provider_userstatus['Status'] = $_stat['Status'];
777 - } else {
778 - // if no stats then we assume all is well.
779 - $_provider_userstatus['Status'] = 2;
780 - }
781 - if ( array_key_exists( 'timestamp', $_stat ) ) {
782 - $_provider_userstatus['timestamp'] = $_stat['timestamp'];
783 - } else {
784 - // if no timestamp then we return "".
785 - $_provider_userstatus['timestamp'] = '';
786 - }
787 - }
788 - }
789 -
790 - return $_provider_userstatus;
791 - }
792 -
793 - public function admin_menu()
794 - {
795 - add_submenu_page( null, 'autoptimize_extra', 'autoptimize_extra', 'manage_options', 'autoptimize_extra', array( $this, 'options_page' ) );
796 524 register_setting( 'autoptimize_extra_settings', 'autoptimize_extra_settings' );
797 525 }
798 526
799 527 public function add_extra_tab( $in )
800 528 {
801 - $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 + }
802 532
803 533 return $in;
804 534 }
805 535
@@ -804,218 +534,129 @@
804 534 }
805 535
806 536 public function options_page()
807 537 {
808 - // Check querystring for "refreshCacheChecker" and call cachechecker if so.
809 - if ( array_key_exists( 'refreshImgProvStats', $_GET ) && 1 == $_GET['refreshImgProvStats'] ) {
810 - $this->query_img_provider_stats();
811 - }
538 + // phpcs:disable Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace
812 539
813 540 // Working with actual option values from the database here.
814 541 // That way any saves are still processed as expected, but we can still
815 542 // override behavior by using `new autoptimizeExtra($custom_options)` and not have that custom
816 543 // behavior being persisted in the DB even if save is done here.
817 - $options = $this->fetch_options();
818 - $gfonts = $options['autoptimize_extra_radio_field_4'];
819 - $sp_url_suffix = '/af/GWRGFLW109483/' . AUTOPTIMIZE_SITE_DOMAIN;
820 - ?>
544 + $options = $this->fetch_options();
545 + $gfonts = $options['autoptimize_extra_radio_field_4'];
546 + ?>
821 547 <style>
822 548 #ao_settings_form {background: white;border: 1px solid #ccc;padding: 1px 15px;margin: 15px 10px 10px 0;}
823 549 #ao_settings_form .form-table th {font-weight: normal;}
824 550 #autoptimize_extra_descr{font-size: 120%;}
825 551 </style>
552 + <script>document.title = "Autoptimize: <?php esc_html_e( 'Extra', 'autoptimize' ); ?> " + document.title;</script>
826 553 <div class="wrap">
827 - <h1><?php _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
828 - <?php echo autoptimizeConfig::ao_admin_tabs(); ?>
829 - <?php
830 - if ( 'on' !== get_option( 'autoptimize_js' ) && 'on' !== get_option( 'autoptimize_css' ) && 'on' !== get_option( 'autoptimize_html' ) ) {
831 - ?>
832 - <div class="notice-warning notice"><p>
833 - <?php
834 - _e( 'Most of below Extra optimizations require at least one of HTML, JS or CSS autoptimizations being active.', 'autoptimize' );
835 - ?>
836 - </p></div>
837 - <?php
838 - }
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 } ?>
839 561
840 - if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) {
841 - ?>
842 - <div class="notice-warning notice"><p>
843 - <?php
844 - // translators: "Autoptimize support forum" will appear in a "a href".
845 - 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>' );
846 - ?>
847 - </p></div>
848 - <?php
849 - }
850 -
851 - if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] && ! $this->imgopt_launch_ok() ) {
852 - ?>
853 - <div class="notice-warning notice"><p>
854 - <?php
855 - _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' );
856 - ?>
857 - </p></div>
858 - <?php
859 - }
860 -
861 - ?>
862 - <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'>
863 563 <?php settings_fields( 'autoptimize_extra_settings' ); ?>
864 - <h2><?php _e( 'Extra Auto-Optimizations', 'autoptimize' ); ?></h2>
865 - <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>
866 566 <table class="form-table">
867 567 <tr>
868 - <th scope="row"><?php _e( 'Google Fonts', 'autoptimize' ); ?></th>
568 + <th scope="row"><?php esc_html_e( 'Google Fonts', 'autoptimize' ); ?></th>
869 569 <td>
870 - <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/>
871 - <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/>
872 - <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/>
873 - <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/>
874 - <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/>
875 577 </td>
876 578 </tr>
877 579 <tr>
878 - <th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th>
580 + <th scope="row"><?php esc_html_e( 'Remove emojis', 'autoptimize' ); ?></th>
879 581 <td>
880 - <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>
881 - <?php
882 - // show shortpixel status.
883 - $_notice = $this->get_imgopt_status_notice();
884 - if ( $_notice ) {
885 - switch ( $_notice['status'] ) {
886 - case 2:
887 - $_notice_color = 'green';
888 - break;
889 - case 1:
890 - $_notice_color = 'orange';
891 - break;
892 - case -1:
893 - $_notice_color = 'red';
894 - break;
895 - case -2:
896 - $_notice_color = 'red';
897 - break;
898 - default:
899 - $_notice_color = 'green';
900 - }
901 - echo apply_filters( 'autoptimize_filter_imgopt_settings_status', '<p><strong><span style="color:' . $_notice_color . ';">' . __( 'Shortpixel status: ', 'autoptimize' ) . '</span></strong>' . $_notice['notice'] . '</p>' );
902 - } else {
903 - // translators: link points to shortpixel.
904 - $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>' );
905 - if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] ) {
906 - $upsell_msg_2 = __( 'For a limited time only, this service is offered free for all Autoptimize users, <b>don\'t miss the chance to test it</b> and see how much it could improve your site\'s speed.', 'autoptimize' );
907 - } else {
908 - // translators: link points to shortpixel.
909 - $upsell_msg_2 = sprintf( __( '%1$sSign-up now%2$s to receive a 1 000 bonus + 50&#37; more image optimization credits regardless of the traffic used. More image optimizations can be purchased starting with $4.99.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>' );
910 - }
911 - echo apply_filters( 'autoptimize_extra_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
912 - }
913 - // translators: link points to shortpixel FAQ.
914 - $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>' );
915 - // translators: links points to shortpixel TOS & Privacy Policy.
916 - $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>' );
917 - echo apply_filters( 'autoptimize_extra_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
918 - ?>
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>
919 583 </td>
920 584 </tr>
921 - <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"'; } ?>>
922 - <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>
923 587 <td>
924 - <label>
925 - <select name='autoptimize_extra_settings[autoptimize_extra_select_field_6]'>
926 - <?php
927 - $_imgopt_array = $this->get_img_quality_array();
928 - $_imgopt_val = $this->get_img_quality_setting();
929 -
930 - foreach ( $_imgopt_array as $key => $value ) {
931 - echo '<option value="' . $key . '"';
932 - if ( $_imgopt_val == $key ) {
933 - echo ' selected';
934 - }
935 - echo '>' . ucfirst( $value ) . '</option>';
936 - }
937 - echo "\n";
938 - ?>
939 - </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 + ?>
940 593 </label>
941 - <p>
942 - <?php
943 - // translators: link points to shortpixel image test page.
944 - 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>' ) );
945 - ?>
946 - </p>
947 594 </td>
948 595 </tr>
949 596 <tr>
950 - <th scope="row"><?php _e( 'Remove emojis', 'autoptimize' ); ?></th>
597 + <th scope="row"><?php esc_html_e( 'Remove WordPress block CSS', 'autoptimize' ); ?></th>
951 598 <td>
952 - <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>
953 600 </td>
954 601 </tr>
955 602 <tr>
956 - <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>
957 604 <td>
958 - <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>
959 611 </td>
960 612 </tr>
961 613 <tr>
962 - <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>
963 615 <td>
964 - <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 /><?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>
965 617 </td>
966 618 </tr>
967 619 <tr>
968 - <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>
969 621 <td>
970 622 <?php
971 - 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' ) ) {
972 624 // translators: link points Async Javascript settings page.
973 - 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>' );
974 626 } else {
975 - ?>
627 + ?>
976 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'] ); } ?>'>
977 629 <br />
978 630 <?php
979 - _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>' );
980 632 // translators: %s will be replaced by a link to the "async javascript" plugin.
981 - 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>"' );
982 634 $asj_install_url = network_admin_url() . 'plugin-install.php?s=async+javascript&tab=search&type=term';
983 - 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' ) );
984 636 }
985 637 ?>
986 638 </td>
987 639 </tr>
988 640 <tr>
989 - <th scope="row"><?php _e( 'Optimize YouTube videos', 'autoptimize' ); ?></th>
641 + <th scope="row"><?php esc_html_e( 'Optimize YouTube videos', 'autoptimize' ); ?></th>
990 642 <td>
991 643 <?php
992 - if ( function_exists( 'is_plugin_active' ) && is_plugin_active( 'wp-youtube-lyte/wp-youtube-lyte.php' ) ) {
993 - _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' );
994 646 $lyte_config_url = 'options-general.php?page=lyte_settings_page';
995 - 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' ) );
996 648 } else {
997 649 // translators: %s will be replaced by a link to "wp youtube lyte" plugin.
998 - 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>' );
999 651 $lyte_install_url = network_admin_url() . 'plugin-install.php?s=lyte&tab=search&type=term';
1000 - 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' ) );
1001 653 }
1002 654 ?>
1003 655 </td>
1004 656 </tr>
1005 657 </table>
1006 - <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>
1007 659 </form>
1008 - <script>
1009 - jQuery(document).ready(function() {
1010 - jQuery( "#autoptimize_imgopt_checkbox" ).change(function() {
1011 - if (this.checked) {
1012 - jQuery("#autoptimize_imgopt_quality").show("slow");
1013 - } else {
1014 - jQuery("#autoptimize_imgopt_quality").hide("slow");
1015 - }
1016 - });
1017 - });
1018 - </script>
1019 - <?php
660 + <?php
1020 661 }
1021 662 }