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