PluginProbe
Autoptimize / 3.1.16
Autoptimize v3.1.16
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/autoptimizeImages.php +644 -214 2.5.1 → 3.1.16 View file →
@@ -21,8 +21,15 @@
21 21 *
22 22 * @var self|null
23 23 */
24 24 protected static $instance = null;
25 +
26 + /**
27 + * lazyload counter.
28 + *
29 + * @var int
30 + */
31 + protected $lazyload_counter = 0;
25 32
26 33 public function __construct( array $options = array() )
27 34 {
28 35 // If options are not provided, fetch them.
@@ -41,9 +48,9 @@
41 48 }
42 49
43 50 public static function fetch_options()
44 51 {
45 - $value = get_option( 'autoptimize_imgopt_settings' );
52 + $value = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_settings' );
46 53 if ( empty( $value ) ) {
47 54 // Fallback to returning defaults when no stored option exists yet.
48 55 $value = autoptimizeConfig::get_ao_imgopt_default_options();
49 56 }
@@ -48,12 +55,32 @@
48 55 $value = autoptimizeConfig::get_ao_imgopt_default_options();
49 56 }
50 57
51 58 // get service availability and add it to the options-array.
52 - $value['availabilities'] = get_option( 'autoptimize_service_availablity' );
59 + $value['availabilities'] = autoptimizeOptionWrapper::get_option( 'autoptimize_service_availablity' );
53 60
54 - if ( empty( $value['availabilities'] ) ) {
55 - $value['availabilities'] = autoptimizeUtils::check_service_availability( true );
61 + if ( empty( $value['availabilities'] ) || ! is_array( $value['availabilities'] ) ) {
62 + $value['availabilities'] = null;
63 +
64 + if ( true === autoptimizeImages::imgopt_active() ) {
65 + $value['availabilities'] = autoptimizeUtils::check_service_availability( true );
66 + }
67 +
68 + if ( null === $value['availabilities'] ) {
69 + // We can't seem to check service availability, use mock result with imgopt status UP.
70 + $_mock_settings = array(
71 + 'extra_imgopt' => array(
72 + 'status' => 'up',
73 + 'hosts' => array(
74 + '1' => 'https://sp-ao.shortpixel.ai/',
75 + ),
76 + ),
77 + 'critcss' => array(
78 + 'status' => 'up',
79 + ),
80 + );
81 + $value['availabilities'] = $_mock_settings;
82 + }
56 83 }
57 84
58 85 return $value;
59 86 }
@@ -65,9 +92,9 @@
65 92 // and does not use/ request the availablity data (which could slow things down).
66 93 static $imgopt_active = null;
67 94
68 95 if ( null === $imgopt_active ) {
69 - $opts = get_option( 'autoptimize_imgopt_settings', '' );
96 + $opts = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_settings', '' );
70 97 if ( ! empty( $opts ) && is_array( $opts ) && array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $opts ) && ! empty( $opts['autoptimize_imgopt_checkbox_field_1'] ) && '1' === $opts['autoptimize_imgopt_checkbox_field_1'] ) {
71 98 $imgopt_active = true;
72 99 } else {
73 100 $imgopt_active = false;
@@ -96,12 +123,16 @@
96 123
97 124 public function run()
98 125 {
99 126 if ( is_admin() ) {
100 - add_action( 'admin_menu', array( $this, 'imgopt_admin_menu' ) );
127 + if ( is_multisite() && is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network() ) {
128 + add_action( 'network_admin_menu', array( $this, 'imgopt_admin_menu' ) );
129 + } else {
130 + add_action( 'admin_menu', array( $this, 'imgopt_admin_menu' ) );
131 + }
101 132 add_filter( 'autoptimize_filter_settingsscreen_tabs', array( $this, 'add_imgopt_tab' ), 9 );
102 133 } else {
103 - $this->run_on_frontend();
134 + add_action( 'wp', array( $this, 'run_on_frontend' ) );
104 135 }
105 136 }
106 137
107 138 public function run_on_frontend() {
@@ -107,8 +138,14 @@
107 138 public function run_on_frontend() {
108 139 if ( ! $this->should_run() ) {
109 140 if ( $this->should_lazyload() ) {
110 141 add_filter(
142 + 'wp_lazy_loading_enabled',
143 + array( $this, 'should_disable_core_lazyload' ),
144 + 10,
145 + 3
146 + );
147 + add_filter(
111 148 'autoptimize_html_after_minify',
112 149 array( $this, 'filter_lazyload_images' ),
113 150 10,
114 151 1
@@ -135,8 +172,9 @@
135 172 $active = true;
136 173 }
137 174
138 175 if ( apply_filters( 'autoptimize_filter_imgopt_do_css', true ) ) {
176 + // fixme: also act on already minified CSS!
139 177 add_filter(
140 178 'autoptimize_filter_base_replace_cdn',
141 179 array( $this, 'filter_optimize_css_images' ),
142 180 10,
@@ -141,8 +179,16 @@
141 179 array( $this, 'filter_optimize_css_images' ),
142 180 10,
143 181 1
144 182 );
183 +
184 + add_filter(
185 + 'autoptimize_html_after_minify',
186 + array( $this, 'filter_optimize_inline_css_images' ),
187 + 10,
188 + 1
189 + );
190 +
145 191 $active = true;
146 192 }
147 193
148 194 if ( $active ) {
@@ -154,16 +200,40 @@
154 200 );
155 201 }
156 202
157 203 if ( $this->should_lazyload() ) {
204 + add_filter(
205 + 'wp_lazy_loading_enabled',
206 + array( $this, 'should_disable_core_lazyload' ),
207 + 10,
208 + 3
209 + );
158 210 add_action(
159 211 'wp_footer',
160 - array( $this, 'add_lazyload_js_footer' )
212 + array( $this, 'add_lazyload_js_footer' ),
213 + 10,
214 + 0
161 215 );
162 216 }
163 217 }
164 218
165 219 /**
220 + * Disables core's native lazyload for images, not for iframes.
221 + *
222 + * @param bool $flag Incoming flag (mostly true).
223 + * @param string $tag Tag (img or iframe).
224 + * @param string $context Full context.
225 + *
226 + * @return bool
227 + */
228 + public function should_disable_core_lazyload( $flag = true, $tag = '', $context = '' ) {
229 + if ( 'img' === $tag ) {
230 + return false;
231 + }
232 + return $flag;
233 + }
234 +
235 + /**
166 236 * Basic checks before we can run.
167 237 *
168 238 * @return bool
169 239 */
@@ -174,9 +244,10 @@
174 244 $not_launch_status = ( 'launch' !== $opts['availabilities']['extra_imgopt']['status'] );
175 245
176 246 $do_cdn = true;
177 247 $_userstatus = $this->get_imgopt_provider_userstatus();
178 - if ( -2 == $_userstatus['Status'] ) {
248 + if ( isset( $_userstatus['Status'] ) && ( -2 == $_userstatus['Status'] || -3 == $_userstatus['Status'] ) ) {
249 + // don't even attempt to put images on CDN if heavily exceeded threshold or if site not reachable.
179 250 $do_cdn = false;
180 251 }
181 252
182 253 if (
@@ -194,9 +265,9 @@
194 265 {
195 266 static $imgopt_host = null;
196 267
197 268 if ( null === $imgopt_host ) {
198 - $imgopt_host = 'https://cdn.shortpixel.ai/';
269 + $imgopt_host = 'https://sp-ao.shortpixel.ai/';
199 270 $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
200 271 if ( ! empty( $avail_imgopt ) && array_key_exists( 'hosts', $avail_imgopt ) && is_array( $avail_imgopt['hosts'] ) ) {
201 272 $imgopt_host = array_rand( array_flip( $avail_imgopt['hosts'] ) );
202 273 }
@@ -214,9 +285,9 @@
214 285 }
215 286
216 287 public static function get_service_url_suffix()
217 288 {
218 - $suffix = '/af/GWRGFLW109483/' . AUTOPTIMIZE_SITE_DOMAIN;
289 + $suffix = '/af/ZQXTBY0109483/' . AUTOPTIMIZE_SITE_DOMAIN;
219 290
220 291 return $suffix;
221 292 }
222 293
@@ -301,9 +372,9 @@
301 372
302 373 // get CDN domain once.
303 374 static $cdn_domain = null;
304 375 if ( is_null( $cdn_domain ) ) {
305 - $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', get_option( 'autoptimize_cdn_url', '' ) );
376 + $cdn_url = $this->get_cdn_url();
306 377 if ( ! empty( $cdn_url ) ) {
307 378 $cdn_domain = parse_url( $cdn_url, PHP_URL_HOST );
308 379 } else {
309 380 $cdn_domain = '';
@@ -325,20 +396,29 @@
325 396 }
326 397
327 398 // Do the work on cache miss only.
328 399 if ( ! isset( $cache[ $in ] ) ) {
329 - // Default to what was given to us.
400 + // Default to (the trimmed version of) what was given to us.
330 401 $result = trim( $in );
331 - if ( autoptimizeUtils::is_protocol_relative( $in ) ) {
332 - $result = $parsed_site_url['scheme'] . ':' . $in;
333 - } elseif ( 0 === strpos( $in, '/' ) ) {
402 +
403 + // Some silly plugins wrap background images in html-encoded quotes, so remove those from the img url.
404 + $result = $this->fix_silly_bgimg_quotes( $result );
405 +
406 + if ( autoptimizeUtils::is_protocol_relative( $result ) ) {
407 + $result = $parsed_site_url['scheme'] . ':' . $result;
408 + } elseif ( 0 === strpos( $result, '/' ) ) {
334 409 // Root-relative...
335 - $result = $parsed_site_url['scheme'] . '://' . $parsed_site_url['host'];
336 - $result .= $in;
337 - } elseif ( ! empty( $cdn_domain ) && strpos( $in, $cdn_domain ) !== 0 ) {
338 - $result = str_replace( $cdn_domain, $parsed_site_url['host'], $in );
410 + $result = $parsed_site_url['scheme'] . '://' . $parsed_site_url['host'] . $result;
411 + } elseif ( ! empty( $cdn_domain ) && false === strpos( $this->get_imgopt_host(), $cdn_domain ) && strpos( $result, $cdn_domain ) !== 0 ) {
412 + // remove CDN except if it is the image optimization one.
413 + $result = str_replace( $cdn_domain, $parsed_site_url['host'], $result );
339 414 }
340 415
416 + // filter (default off) to remove QS from image URL's to avoid eating away optimization credits.
417 + if ( apply_filters( 'autoptimize_filter_imgopt_no_querystring', false ) && strpos( $result, '?' ) !== false ) {
418 + $result = strtok( $result, '?' );
419 + }
420 +
341 421 $result = apply_filters( 'autoptimize_filter_imgopt_normalized_url', $result );
342 422
343 423 // Store in cache.
344 424 $cache[ $in ] = $result;
@@ -350,15 +430,41 @@
350 430 public function filter_optimize_css_images( $in )
351 431 {
352 432 $in = $this->normalize_img_url( $in );
353 433
354 - if ( $this->can_optimize_image( $in ) ) {
434 + if ( $this->can_optimize_image( $in ) && false === strpos( $in, $this->get_imgopt_host() ) ) {
355 435 return $this->build_imgopt_url( $in, '', '' );
356 436 } else {
357 437 return $in;
358 438 }
359 439 }
440 +
441 + public function filter_optimize_inline_css_images( $html ) {
442 + preg_match_all( '#<style[^>]*>([^<]*)</style>#Um', $html, $inline_css_blocks, PREG_SET_ORDER );
443 + foreach ( $inline_css_blocks as $inline_css_block ) {
444 + if ( false !== strpos( $inline_css_block[0], 'background' ) ) {
445 + $inline_css_block_new = $this->replace_background_img_css( $inline_css_block[0] );
446 + if ( $inline_css_block_new !== $inline_css_block[0] ) {
447 + $html = str_replace( $inline_css_block[0], $inline_css_block_new, $html );
448 + }
449 + }
450 + }
451 + return $html;
452 + }
360 453
454 + public static function replace_background_img_css( $css ) {
455 + // fixme; can/ should we cache these?
456 + preg_match_all( '#background[^;}]*url\((.*)\)#Ui', $css, $backgrounds, PREG_SET_ORDER );
457 + if ( is_array( $backgrounds ) && ! empty( $backgrounds ) ) {
458 + foreach ( $backgrounds as $background ) {
459 + if ( autoptimizeImages::can_optimize_image_wrapper( $background[1] ) ) {
460 + $css = str_replace( $background[1], autoptimizeImages::build_imgopt_url_wrapper( $background[1] ), $css );
461 + }
462 + }
463 + }
464 + return $css;
465 + }
466 +
361 467 private function get_imgopt_base_url()
362 468 {
363 469 static $imgopt_base_url = null;
364 470
@@ -365,9 +471,15 @@
365 471 if ( null === $imgopt_base_url ) {
366 472 $imgopt_host = $this->get_imgopt_host();
367 473 $quality = $this->get_img_quality_string();
368 474 $ret_val = apply_filters( 'autoptimize_filter_imgopt_wait', 'ret_img' ); // values: ret_wait, ret_img, ret_json, ret_blank.
369 - $imgopt_base_url = $imgopt_host . 'client/' . $quality . ',' . $ret_val;
475 + if ( $this->should_ngimg() ) {
476 + $sp_to_string = 'to_auto';
477 + } else {
478 + $sp_to_string = 'to_webp';
479 + }
480 + $sp_to_string = apply_filters( 'autoptimize_filter_imgopt_format', $sp_to_string ); // values: empty (= jpeg), to_webp (smart; webp or fallback), to_avif (avif or fallback) or to_auto (smart avif, webp or fallback).
481 + $imgopt_base_url = $imgopt_host . 'client/' . $sp_to_string . ',' . $quality . ',' . $ret_val;
370 482 $imgopt_base_url = apply_filters( 'autoptimize_filter_imgopt_base_url', $imgopt_base_url );
371 483 }
372 484
373 485 return $imgopt_base_url;
@@ -372,9 +484,14 @@
372 484
373 485 return $imgopt_base_url;
374 486 }
375 487
376 - private function can_optimize_image( $url )
488 + public static function can_optimize_image_wrapper( $url, $tag = '', $testing = false ) {
489 + $self = new self();
490 + return $self->can_optimize_image( $url, $tag = '', $testing = false );
491 + }
492 +
493 + private function can_optimize_image( $url, $tag = '', $testing = false )
377 494 {
378 495 static $cdn_url = null;
379 496 static $nopti_images = null;
380 497
@@ -380,14 +497,17 @@
380 497
381 498 if ( null === $cdn_url ) {
382 499 $cdn_url = apply_filters(
383 500 'autoptimize_filter_base_cdnurl',
384 - get_option( 'autoptimize_cdn_url', '' )
501 + autoptimizeOptionWrapper::get_option( 'autoptimize_cdn_url', '' )
385 502 );
386 503 }
387 504
388 - if ( null === $nopti_images ) {
389 - $nopti_images = apply_filters( 'autoptimize_filter_imgopt_noptimize', '' );
505 + if ( null === $nopti_images || $testing ) {
506 + if ( is_array( $this->options ) && array_key_exists( 'autoptimize_imgopt_text_field_6', $this->options ) ) {
507 + $nopti_images = $this->options['autoptimize_imgopt_text_field_6'];
508 + }
509 + $nopti_images = apply_filters( 'autoptimize_filter_imgopt_noptimize', $nopti_images );
390 510 }
391 511
392 512 $site_host = AUTOPTIMIZE_SITE_DOMAIN;
393 513 $url = $this->normalize_img_url( $url );
@@ -392,21 +512,25 @@
392 512 $site_host = AUTOPTIMIZE_SITE_DOMAIN;
393 513 $url = $this->normalize_img_url( $url );
394 514 $url_parsed = parse_url( $url );
395 515
396 - if ( array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host && empty( $cdn_url ) ) {
516 + if ( false === is_array( $url_parsed ) ) {
397 517 return false;
518 + } elseif ( array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host && empty( $cdn_url ) ) {
519 + return false;
520 + } elseif ( autoptimizeUtils::is_local_server() ) {
521 + return false;
398 522 } elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host ) {
399 523 return false;
400 524 } elseif ( strpos( $url, '.php' ) !== false ) {
401 525 return false;
402 - } elseif ( str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg', '.webp' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) {
526 + } elseif ( false === array_key_exists( 'path', $url_parsed ) || str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg', '.webp', '.avif' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) {
403 527 // fixme: better check against end of string.
404 528 return false;
405 529 } elseif ( ! empty( $nopti_images ) ) {
406 530 $nopti_images_array = array_filter( array_map( 'trim', explode( ',', $nopti_images ) ) );
407 531 foreach ( $nopti_images_array as $nopti_image ) {
408 - if ( strpos( $url, $nopti_image ) !== false ) {
532 + if ( strpos( $url, $nopti_image ) !== false || ( ( '' !== $tag && strpos( $tag, $nopti_image ) !== false ) ) ) {
409 533 return false;
410 534 }
411 535 }
412 536 }
@@ -412,8 +536,14 @@
412 536 }
413 537 return true;
414 538 }
415 539
540 + // wrapper for reuse in AOPro.
541 + public static function build_imgopt_url_wrapper( $orig_url, $width = 0, $height = 0 ) {
542 + $self = new self();
543 + return $self->build_imgopt_url( $orig_url, $width = 0, $height = 0 );
544 + }
545 +
416 546 private function build_imgopt_url( $orig_url, $width = 0, $height = 0 )
417 547 {
418 548 // sanitize width and height.
419 549 if ( strpos( $width, '%' ) !== false ) {
@@ -436,9 +566,15 @@
436 566 if ( $filtered_url !== $orig_url ) {
437 567 return $filtered_url;
438 568 }
439 569
440 - $orig_url = $this->normalize_img_url( $orig_url );
570 + $normalized_url = $this->normalize_img_url( $orig_url );
571 +
572 + // if the URL is ascii we check if we have a real URL with filter_var (which only works on ascii url's) and if not a real URL we return the original one.
573 + if ( apply_filters( 'autoptimize_filter_imgopt_check_normalized_url', true ) && ! preg_match( '/[^\x20-\x7e]/', $normalized_url ) && false === filter_var( $normalized_url, FILTER_VALIDATE_URL ) ) {
574 + return $orig_url;
575 + }
576 +
441 577 $imgopt_base_url = $this->get_imgopt_base_url();
442 578 $imgopt_size = '';
443 579
444 580 if ( $width && 0 !== $width ) {
@@ -448,9 +584,10 @@
448 584 if ( $height && 0 !== $height ) {
449 585 $imgopt_size .= ',h_' . $height;
450 586 }
451 587
452 - $url = $imgopt_base_url . $imgopt_size . '/' . $orig_url;
588 + $url = $imgopt_base_url . $imgopt_size . '/' . $normalized_url;
589 + $url = apply_filters( 'autoptimize_filter_imgopt_after_build_imgopt_url', $url );
453 590
454 591 return $url;
455 592 }
456 593
@@ -461,9 +598,9 @@
461 598
462 599 public function replace_img_callback( $matches, $width = 0, $height = 0 )
463 600 {
464 601 $_normalized_img_url = $this->normalize_img_url( $matches[1] );
465 - if ( $this->can_optimize_image( $matches[1] ) ) {
602 + if ( $this->can_optimize_image( $matches[1], $matches[0] ) ) {
466 603 return str_replace( $matches[1], $this->build_imgopt_url( $_normalized_img_url, $width, $height ), $matches[0] );
467 604 } else {
468 605 return $matches[0];
469 606 }
@@ -468,10 +605,29 @@
468 605 return $matches[0];
469 606 }
470 607 }
471 608
472 - public function filter_optimize_images( $in )
609 + public function replace_icon_callback( $matches )
473 610 {
611 + if ( array_key_exists( '2', $matches ) ) {
612 + $sizes = explode( 'x', $matches[2] );
613 + $width = $sizes[0];
614 + $height = $sizes[1];
615 + } else {
616 + $width = 180;
617 + $height = 180;
618 + }
619 +
620 + // make sure we're not trying to optimize a *.ico file.
621 + if ( strpos( $matches[1], '.ico' ) === false ) {
622 + return $this->replace_img_callback( $matches, $width, $height );
623 + } else {
624 + return $matches[0];
625 + }
626 + }
627 +
628 + public function filter_optimize_images( $in, $testing = false )
629 + {
474 630 /*
475 631 * potential future functional improvements:
476 632 *
477 633 * filter for critical CSS.
@@ -476,11 +632,12 @@
476 632 *
477 633 * filter for critical CSS.
478 634 */
479 635 $to_replace = array();
636 + $to_preload = '';
480 637
481 - // hide noscript tags to avoid nesting noscript tags (as lazyloaded images add noscript).
482 - if ( $this->should_lazyload() ) {
638 + // hide (no)script tags to avoid replacing (and potentially breaking) images in script tags.
639 + if ( apply_filters( 'autoptimize_filter_imgopt_hide_script', true ) || $this->should_lazyload() ) {
483 640 $in = autoptimizeBase::replace_contents_with_marker_if_exists(
484 641 'SCRIPT',
485 642 '<script',
486 643 '#<(?:no)?script.*?<\/(?:no)?script>#is',
@@ -487,11 +644,18 @@
487 644 $in
488 645 );
489 646 }
490 647
648 + // get img preloads as set in post metabox, exploding ", " instead of "," because LCP preload
649 + // could be a shortpixel URL, which has comma's and results in way too many preloads.
650 + $metabox_preloads = array_filter( array_map( 'trim', explode( ', ', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) );
651 + $metabox_preloads = apply_filters( 'autoptimize_filter_images_metabox_preloads', $metabox_preloads );
652 +
491 653 // extract img tags.
492 654 if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
493 655 foreach ( $matches[0] as $tag ) {
656 + $tag = apply_filters( 'autoptimize_filter_imgopt_tag_preopt', $tag );
657 +
494 658 $orig_tag = $tag;
495 659 $imgopt_w = '';
496 660 $imgopt_h = '';
497 661
@@ -497,20 +661,22 @@
497 661
498 662 // first do (data-)srcsets.
499 663 if ( preg_match_all( '#srcset=("|\')(.*)("|\')#Usmi', $tag, $allsrcsets, PREG_SET_ORDER ) ) {
500 664 foreach ( $allsrcsets as $srcset ) {
501 - $srcset = $srcset[2];
502 - $srcsets = explode( ',', $srcset );
665 + $srcset = $srcset[2];
666 + $orig_srcset = $srcset;
667 + $srcsets = explode( ',', $srcset );
503 668 foreach ( $srcsets as $indiv_srcset ) {
504 669 $indiv_srcset_parts = explode( ' ', trim( $indiv_srcset ) );
505 670 if ( isset( $indiv_srcset_parts[1] ) && rtrim( $indiv_srcset_parts[1], 'w' ) !== $indiv_srcset_parts[1] ) {
506 671 $imgopt_w = rtrim( $indiv_srcset_parts[1], 'w' );
507 672 }
508 - if ( $this->can_optimize_image( $indiv_srcset_parts[0] ) ) {
673 + if ( $this->can_optimize_image( $indiv_srcset_parts[0], $tag, $testing ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
509 674 $imgopt_url = $this->build_imgopt_url( $indiv_srcset_parts[0], $imgopt_w, '' );
510 - $tag = str_replace( $indiv_srcset_parts[0], $imgopt_url, $tag );
675 + $srcset = str_replace( $indiv_srcset_parts[0], $imgopt_url, $srcset );
511 676 }
512 677 }
678 + $tag = str_replace( $orig_srcset, $srcset, $tag );
513 679 }
514 680 }
515 681
516 682 // proceed with img src.
@@ -519,22 +685,33 @@
519 685 $imgopt_w = $_get_size['width'];
520 686 $imgopt_h = $_get_size['height'];
521 687
522 688 // then start replacing images src.
523 - if ( preg_match_all( '#src=(?:"|\')(?!data)(.*)(?:"|\')#Usmi', $tag, $urls, PREG_SET_ORDER ) ) {
524 - foreach ( $urls as $url ) {
525 - $full_src_orig = $url[0];
526 - $url = $url[1];
527 - if ( $this->can_optimize_image( $url ) ) {
528 - $imgopt_url = $this->build_imgopt_url( $url, $imgopt_w, $imgopt_h );
529 - $full_imgopt_src = str_replace( $url, $imgopt_url, $full_src_orig );
530 - $tag = str_replace( $full_src_orig, $full_imgopt_src, $tag );
531 - }
689 + $tag = autoptimizeAttributeParser::modify_attributes( $tag, 'img', '/src$/i', function( $name, $url ) use ( $tag, $testing, $imgopt_w, $imgopt_h ) {
690 + // 1. Skip if empty or a data-URI
691 + if ( ! $url || strpos( $url, 'data:' ) === 0 ) {
692 + return $url;
532 693 }
694 +
695 + // 2. Run Autoptimize logic
696 + if ( $this->can_optimize_image( $url, $tag, $testing ) && ! apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
697 + return $this->build_imgopt_url( $url, $imgopt_w, $imgopt_h );
698 + }
699 +
700 + // 3. No changes needed
701 + return $url;
702 + }, false, true );
703 +
704 + $_url = autoptimizeAttributeParser::get( $tag, 'img', '/src$/i' );
705 + $url = $_url['src'];
706 +
707 + // check if the image needs to be prelaoded.
708 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) {
709 + $to_preload .= $this->create_img_preload_tag( $tag );
533 710 }
534 711
535 712 // do lazyload stuff.
536 - if ( $this->should_lazyload( $in ) ) {
713 + if ( $this->should_lazyload( $in ) && ! empty( $url ) ) {
537 714 // first do lpiq placeholder logic.
538 715 if ( strpos( $url, $this->get_imgopt_host() ) === 0 ) {
539 716 // if all img src have been replaced during srcset, we have to extract the
540 717 // origin url from the imgopt one to be able to set a lqip placeholder.
@@ -542,9 +719,12 @@
542 719 } else {
543 720 $_url = $url;
544 721 }
545 722
546 - if ( $this->can_optimize_image( $_url ) && apply_filters( 'autoptimize_filter_imgopt_lazyload_dolqip', true ) ) {
723 + $_url = $this->normalize_img_url( $_url );
724 +
725 + $placeholder = '';
726 + if ( $this->can_optimize_image( $_url, $tag ) && apply_filters( 'autoptimize_filter_imgopt_lazyload_dolqip', false, $_url ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
547 727 $lqip_w = '';
548 728 $lqip_h = '';
549 729 if ( isset( $imgopt_w ) && ! empty( $imgopt_w ) ) {
550 730 $lqip_w = ',w_' . $imgopt_w;
@@ -557,8 +737,15 @@
557 737 // then call add_lazyload-function with lpiq placeholder if set.
558 738 $tag = $this->add_lazyload( $tag, $placeholder );
559 739 }
560 740
741 + // add decoding="async" behind filter, not sure if I'll make it default true yet.
742 + if ( true === apply_filters( 'autoptimize_filter_imgopt_add_decoding', true ) && false === strpos( $tag, ' decoding=' ) ) {
743 + $tag = str_replace( '<img ', '<img decoding="async" ', $tag );
744 + }
745 +
746 + $tag = apply_filters( 'autoptimize_filter_imgopt_tag_postopt', $tag );
747 +
561 748 // and add tag to array for later replacement.
562 749 if ( $tag !== $orig_tag ) {
563 750 $to_replace[ $orig_tag ] = $tag;
564 751 }
@@ -567,42 +754,72 @@
567 754
568 755 // and replace all.
569 756 $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $in );
570 757
571 - // img thumbnails in e.g. woocommerce.
572 - if ( strpos( $out, 'data-thumb' ) !== false && apply_filters( 'autoptimize_filter_imgopt_datathumbs', true ) ) {
758 + // misc. node attributes that might hold image url's (incl. the previously separate data-thumb).
759 + $extra_attr_with_img = apply_filters( 'autoptimize_filter_imgopt_attr_with_img', array( array( 'div', 'data-thumb'), array( 'div', 'data-background' ), array( 'img', 'data-retina' ) ) );
760 + if ( ! empty( $extra_attr_with_img ) && is_array( $extra_attr_with_img ) ) {
761 + foreach ( $extra_attr_with_img as $candidate ) {
762 + if ( is_array( $candidate ) && strpos( $out, $candidate[1] ) !== false ) {
763 + $_regex = '/\<' . $candidate[0] . '(?:[^>]*)?\s' . $candidate[1] . '=(?:"|\')(.+?)(?:"|\')(?:[^>]*)?>/s';
764 + $out = preg_replace_callback(
765 + $_regex,
766 + array( $this, 'replace_img_callback' ),
767 + $out
768 + );
769 + }
770 + }
771 + }
772 +
773 + // background-image in inline style.
774 + if ( ( strpos( $out, 'background-image:' ) !== false || strpos( $out, 'background:' ) !== false ) && strpos( $out, 'url(' ) !== false && apply_filters( 'autoptimize_filter_imgopt_backgroundimages', true ) ) {
573 775 $out = preg_replace_callback(
574 - '/\<div(?:[^>]?)\sdata-thumb\=(?:\"|\')(.+?)(?:\"|\')(?:[^>]*)?\>/s',
575 - array( $this, 'replace_data_thumbs' ),
776 + '/style=(?:"|\')[^<>]*?background(?:-image)?:[^;"\'()>]*url\((?:"|\')?([^"\')]*)(?:"|\')?\)/',
777 + array( $this, 'replace_img_callback' ),
576 778 $out
577 779 );
578 780 }
579 781
580 - // background-image in inline style.
581 - if ( strpos( $out, 'background-image:' ) !== false && apply_filters( 'autoptimize_filter_imgopt_backgroundimages', true ) ) {
782 + // act on icon links.
783 + if ( ( strpos( $out, '<link rel="icon"' ) !== false || ( strpos( $out, "<link rel='icon'" ) !== false ) ) && apply_filters( 'autoptimize_filter_imgopt_linkicon', true ) ) {
582 784 $out = preg_replace_callback(
583 - '/style=(?:"|\').*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)/',
584 - array( $this, 'replace_img_callback' ),
785 + '/<link\srel=(?:"|\')(?:apple-touch-)?icon(?:-precomposed)?(?:"|\').*\shref=(?:"|\')(.*)(?:"|\')(?:\ssizes=(?:"|\')(\d*x\d*)(?:"|\'))?\s?\/?>/Um',
786 + array( $this, 'replace_icon_callback' ),
585 787 $out
586 788 );
587 789 }
588 790
589 - // lazyload: restore noscript tags + lazyload picture source tags.
791 + // lazyload picture source tags and bgimage.
590 792 if ( $this->should_lazyload() ) {
793 + $out = $this->process_picture_tag( $out, true, true );
794 + $out = $this->process_bgimage( $out );
795 + } else {
796 + $out = $this->process_picture_tag( $out, true, false );
797 + }
798 +
799 + // restore (no)script tags.
800 + if ( apply_filters( 'autoptimize_filter_imgopt_hide_script', true ) || $this->should_lazyload() ) {
591 801 $out = autoptimizeBase::restore_marked_content(
592 802 'SCRIPT',
593 803 $out
594 804 );
805 + }
595 806
596 - $out = $this->process_picture_tag( $out, true, true );
597 - } else {
598 - $out = $this->process_picture_tag( $out, true, false );
807 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
808 + // the preload was not in an img tag, so adding a non-responsive preload instead.
809 + foreach ( $metabox_preloads as $img_preload ) {
810 + $to_preload .= apply_filters( 'autoptimize_filter_imgopt_preload_tag_result', $this->kses_preload_link( '<link fetchpriority="high" rel="preload" href="' . $img_preload . '" as="image">' ) );
811 + }
599 812 }
600 813
814 + if ( ! empty( $to_preload ) ) {
815 + $out = autoptimizeExtra::inject_preloads( $to_preload, $out );
816 + }
817 +
601 818 return $out;
602 819 }
603 820
604 - public function get_size_from_tag( $tag ) {
821 + public static function get_size_from_tag( $tag ) {
605 822 // reusable function to extract widht and height from an image tag
606 823 // enforcing a filterable maximum width and height (default 4999X4999).
607 824 $width = '';
608 825 $height = '';
@@ -621,15 +838,19 @@
621 838 // check for and enforce (filterable) max sizes.
622 839 $_max_width = apply_filters( 'autoptimize_filter_imgopt_max_width', 4999 );
623 840 if ( $width > $_max_width ) {
624 841 $_width = $_max_width;
625 - $height = $_width / $width * $height;
842 + if ( ! empty( $height ) && is_int( $height ) ) {
843 + $height = $_width / $width * $height;
844 + }
626 845 $width = $_width;
627 846 }
628 847 $_max_height = apply_filters( 'autoptimize_filter_imgopt_max_height', 4999 );
629 848 if ( $height > $_max_height ) {
630 849 $_height = $_max_height;
631 - $width = $_height / $height * $width;
850 + if ( ! empty( $width ) && is_int( $width ) ) {
851 + $width = $_height / $height * $width;
852 + }
632 853 $height = $_height;
633 854 }
634 855
635 856 return array(
@@ -640,29 +861,44 @@
640 861
641 862 /**
642 863 * Lazyload functions
643 864 */
644 - public static function should_lazyload_wrapper() {
865 + public static function should_lazyload_wrapper( $no_meta = false ) {
645 866 // needed in autoptimizeMain.php.
646 867 $self = new self();
647 - return $self->should_lazyload();
868 + return $self->should_lazyload( '', $no_meta );
648 869 }
649 870
650 - public function should_lazyload( $context = '' ) {
651 - if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) ) {
871 + public function should_lazyload( $context = '', $no_meta = false ) {
872 + if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) && false === $this->check_nolazy() ) {
652 873 $lazyload_return = true;
653 874 } else {
654 875 $lazyload_return = false;
655 876 }
877 +
878 + // If page/ post check post_meta to see if lazyload is off for page.
879 + if ( false === $no_meta && false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_lazyload' ) ) {
880 + $lazyload_return = false;
881 + }
882 +
656 883 $lazyload_return = apply_filters( 'autoptimize_filter_imgopt_should_lazyload', $lazyload_return, $context );
657 884
658 885 return $lazyload_return;
659 886 }
660 887
888 + public static function check_nolazy() {
889 + if ( array_key_exists( 'ao_nolazy', $_GET ) && '1' === $_GET['ao_nolazy'] ) {
890 + return true;
891 + } else {
892 + return false;
893 + }
894 + }
895 +
661 896 public function filter_lazyload_images( $in )
662 897 {
663 898 // only used is image optimization is NOT active but lazyload is.
664 899 $to_replace = array();
900 + $to_preload = '';
665 901
666 902 // hide (no)script tags to avoid nesting noscript tags (as lazyloaded images add noscript).
667 903 $out = autoptimizeBase::replace_contents_with_marker_if_exists(
668 904 'SCRIPT',
@@ -670,11 +906,20 @@
670 906 '#<(?:no)?script.*?<\/(?:no)?script>#is',
671 907 $in
672 908 );
673 909
674 - // extract img tags and add lazyload attribs.
910 + // get img preloads as set in post metabox.
911 + $metabox_preloads = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) );
912 +
913 + // extract img tags and add lazyload attribs/ add preloads.
675 914 if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $out, $matches ) ) {
676 915 foreach ( $matches[0] as $tag ) {
916 + // check if image needs to be preloaded.
917 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) {
918 + $to_preload .= $this->create_img_preload_tag( $tag );
919 + }
920 +
921 + // and lazyloaded.
677 922 if ( $this->should_lazyload( $out ) ) {
678 923 $to_replace[ $tag ] = $this->add_lazyload( $tag );
679 924 }
680 925 }
@@ -683,8 +928,11 @@
683 928
684 929 // and also lazyload picture tag.
685 930 $out = $this->process_picture_tag( $out, false, true );
686 931
932 + // and inline style blocks with background-image.
933 + $out = $this->process_bgimage( $out );
934 +
687 935 // restore noscript tags.
688 936 $out = autoptimizeBase::restore_marked_content(
689 937 'SCRIPT',
690 938 $out
@@ -689,21 +937,42 @@
689 937 'SCRIPT',
690 938 $out
691 939 );
692 940
941 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
942 + // the preload was not in an img tag, so adding a non-responsive preload instead.
943 + foreach ( $metabox_preloads as $img_preload ) {
944 + $to_preload .= apply_filters( 'autoptimize_filter_imgopt_preload_tag_result', $this->kses_preload_link( '<link fetchpriority="high" rel="preload" href="' . $img_preload . '" as="image">' ) );
945 + }
946 + }
947 +
948 + if ( ! empty( $to_preload ) ) {
949 + $out = autoptimizeExtra::inject_preloads( $to_preload, $out );
950 + }
951 +
693 952 return $out;
694 953 }
695 954
696 955 public function add_lazyload( $tag, $placeholder = '' ) {
697 956 // adds actual lazyload-attributes to an image node.
698 - if ( str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag ) {
957 + $this->lazyload_counter++;
958 +
959 + $_lazyload_from_nth = '';
960 + if ( array_key_exists( 'autoptimize_imgopt_number_field_7', $this->options ) ) {
961 + $_lazyload_from_nth = $this->options['autoptimize_imgopt_number_field_7'];
962 + }
963 + $_lazyload_from_nth = apply_filters( 'autoptimize_filter_imgopt_lazyload_from_nth', $_lazyload_from_nth );
964 +
965 + if ( str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag && $this->lazyload_counter >= $_lazyload_from_nth ) {
699 966 $tag = $this->maybe_fix_missing_quotes( $tag );
700 967
701 968 // store original tag for use in noscript version.
702 - $noscript_tag = '<noscript>' . $tag . '</noscript>';
969 + $noscript_tag = '<noscript>' . autoptimizeUtils::remove_id_from_node( $tag ) . '</noscript>';
703 970
971 + $lazyload_class = apply_filters( 'autoptimize_filter_imgopt_lazyload_class', 'lazyload' );
972 +
704 973 // insert lazyload class.
705 - $tag = $this->inject_classes_in_tag( $tag, 'lazyload ' );
974 + $tag = $this->inject_classes_in_tag( $tag, "$lazyload_class " );
706 975
707 976 if ( ! $placeholder || empty( $placeholder ) ) {
708 977 // get image width & heigth for placeholder fun (and to prevent content reflow).
709 978 $_get_size = $this->get_size_from_tag( $tag );
@@ -708,13 +977,13 @@
708 977 // get image width & heigth for placeholder fun (and to prevent content reflow).
709 978 $_get_size = $this->get_size_from_tag( $tag );
710 979 $width = $_get_size['width'];
711 980 $height = $_get_size['height'];
712 - if ( false === $width ) {
713 - $widht = 210; // default width for SVG placeholder.
981 + if ( false === $width || empty( $width ) ) {
982 + $width = 210; // default width for SVG placeholder.
714 983 }
715 - if ( false === $height ) {
716 - $heigth = $width / 3 * 2; // if no height, base it on width using the 3/2 aspect ratio.
984 + if ( false === $height || empty( $height ) ) {
985 + $height = $width / 3 * 2; // if no height, base it on width using the 3/2 aspect ratio.
717 986 }
718 987
719 988 // insert the actual lazyload stuff.
720 989 // see https://css-tricks.com/preventing-content-reflow-from-lazy-loaded-images/ for great read on why we're using empty svg's.
@@ -719,19 +988,23 @@
719 988 // insert the actual lazyload stuff.
720 989 // see https://css-tricks.com/preventing-content-reflow-from-lazy-loaded-images/ for great read on why we're using empty svg's.
721 990 $placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( $width, $height ) );
722 991 }
723 - $tag = str_replace( ' src=', ' src=\'' . $placeholder . '\' data-src=', $tag );
992 +
993 + $tag = str_replace( ' src=', ' data-src=', $tag );
724 994 $tag = str_replace( ' srcset=', ' data-srcset=', $tag );
995 + $tag = str_replace( '<img ', '<img src=\'' . $placeholder . '\' ', $tag );
725 996
726 997 // move sizes to data-sizes unless filter says no.
727 998 if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_move_sizes', true ) ) {
728 - $tag = str_replace( 'sizes=', 'data-sizes=', $tag );
999 + $tag = str_replace( ' sizes=', ' data-sizes=', $tag );
729 1000 }
730 1001
731 1002 // add the noscript-tag from earlier.
732 1003 $tag = $noscript_tag . $tag;
733 1004 $tag = apply_filters( 'autoptimize_filter_imgopt_lazyloaded_img', $tag );
1005 + } else {
1006 + $tag = apply_filters( 'autoptimize_filter_imgopt_not_lazyloaded_img', $tag );
734 1007 }
735 1008
736 1009 return $tag;
737 1010 }
@@ -736,8 +1009,12 @@
736 1009 return $tag;
737 1010 }
738 1011
739 1012 public function add_lazyload_js_footer() {
1013 + if ( false === autoptimizeMain::should_buffer() || autoptimizeMain::is_amp_markup( '' ) ) {
1014 + return;
1015 + }
1016 +
740 1017 // The JS will by default be excluded form autoptimization but this can be changed with a filter.
741 1018 $noptimize_flag = '';
742 1019 if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_js_noptimize', true ) ) {
743 1020 $noptimize_flag = ' data-noptimize="1"';
@@ -742,21 +1019,93 @@
742 1019 if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_js_noptimize', true ) ) {
743 1020 $noptimize_flag = ' data-noptimize="1"';
744 1021 }
745 1022
1023 + $_extra = autoptimizeOptionWrapper::get_option( 'autoptimize_extra_settings', '' );
1024 + if ( is_array( $_extra ) && array_key_exists( 'autoptimize_extra_checkbox_field_0', $_extra ) && ! empty( $_extra['autoptimize_extra_checkbox_field_0'] ) ) {
1025 + // if "remove query strings" is active in "extra", then let's be consistant and not add one ourselves :-) ?
1026 + $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js', __FILE__ );
1027 + } else {
1028 + $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js?ao_version=' . AUTOPTIMIZE_PLUGIN_VERSION, __FILE__ );
1029 + }
1030 +
1031 + $cdn_url = $this->get_cdn_url();
1032 + if ( ! empty( $cdn_url ) ) {
1033 + $cdn_url = rtrim( $cdn_url, '/' );
1034 + $lazysizes_js = str_replace( AUTOPTIMIZE_WP_SITE_URL, $cdn_url, $lazysizes_js );
1035 + }
1036 +
1037 + $type_js = '';
1038 + if ( apply_filters( 'autoptimize_filter_cssjs_addtype', false ) ) {
1039 + $type_js = ' type="text/javascript"';
1040 + }
1041 +
746 1042 // Adds lazyload CSS & JS to footer, using echo because wp_enqueue_script seems not to support pushing attributes (async).
747 - echo apply_filters( 'autoptimize_filter_imgopt_lazyload_cssoutput', '<style>.lazyload,.lazyloading{opacity:0;}.lazyloaded{opacity:1;transition:opacity 300ms;}</style><noscript><style>.lazyload{display:none;}</style></noscript>' );
748 - echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' );
749 - echo '<script async' . $noptimize_flag . ' src=\'' . plugins_url( 'external/js/lazysizes.min.js', __FILE__ ) . '\'></script>';
1043 + echo apply_filters( 'autoptimize_filter_imgopt_lazyload_cssoutput', '<noscript><style>.lazyload{display:none;}</style></noscript>' );
1044 + echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $type_js . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' );
1045 + echo apply_filters( 'autoptimize_filter_imgopt_lazyload_js', '<script async' . $type_js . $noptimize_flag . ' src=\'' . $lazysizes_js . '\'></script>' );
1046 + }
750 1047
751 - // And add webp detection and loading JS.
752 - if ( $this->should_webp() ) {
753 - $_webp_detect = "function c_webp(A){var n=new Image;n.onload=function(){var e=0<n.width&&0<n.height;A(e)},n.onerror=function(){A(!1)},n.src='data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA=='}function s_webp(e){window.supportsWebP=e}c_webp(s_webp);";
754 - $_webp_load = "document.addEventListener('lazybeforeunveil',function({target:c}){supportsWebP&&['data-src','data-srcset'].forEach(function(a){attr=c.getAttribute(a),null!==attr&&c.setAttribute(a,attr.replace(/\/client\//,'/client/to_webp,'))})});";
755 - echo apply_filters( 'autoptimize_filter_imgopt_webp_js', '<script' . $noptimize_flag . '>' . $_webp_detect . $_webp_load . '</script>' );
1048 + public function create_img_preload_tag( $tag ) {
1049 + if ( false === apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
1050 + return '';
756 1051 }
1052 +
1053 + // clean up; remove tabs/ linebreaks/ spaces.
1054 + $tag = preg_replace( '/\s+/', ' ', $tag );
1055 +
1056 + // remove noscript.
1057 + if ( false !== strpos( $tag, '<noscript' ) ) {
1058 + $tag = preg_replace( '/<noscript.*<\/noscript>/mU', '', $tag );
1059 + }
1060 +
1061 + // rewrite img tag to link preload img.
1062 + $_from = array( '<img ', ' src=', ' sizes=', ' srcset=' );
1063 + $_to = array( '<link fetchpriority="high" rel="preload" as="image" ', ' href=', ' imagesizes=', ' imagesrcset=' );
1064 + $tag = str_replace( $_from, $_to, $tag );
1065 +
1066 + // sanitize output
1067 + $tag = $this->kses_preload_link( $tag );
1068 +
1069 + // and provide filter for late changes.
1070 + $tag = apply_filters( 'autoptimize_filter_imgopt_preload_tag_result', $tag );
1071 +
1072 + return $tag;
757 1073 }
758 1074
1075 + public function kses_preload_link( $_preload ) {
1076 + // using kses, remove all unneeded attributes
1077 + // keeping only those we *know* are OK and/ or needed.
1078 + $allowed_html = array(
1079 + 'link' => array(
1080 + 'rel' => true,
1081 + 'as' => true,
1082 + 'href' => true,
1083 + 'imagesizes' => true,
1084 + 'imagesrcset' => true,
1085 + 'type' => true,
1086 + 'media' => true,
1087 + 'fetchpriority' => true,
1088 + ),
1089 + );
1090 + $_preload = wp_kses( $_preload, $allowed_html );
1091 +
1092 + return $_preload;
1093 + }
1094 +
1095 + public static function get_cdn_url() {
1096 + // getting CDN url here to avoid having to make bigger changes to autoptimizeBase.
1097 + static $cdn_url = null;
1098 +
1099 + if ( null === $cdn_url ) {
1100 + $cdn_url = autoptimizeOptionWrapper::get_option( 'autoptimize_cdn_url', '' );
1101 + $cdn_url = autoptimizeUtils::tweak_cdn_url_if_needed( $cdn_url );
1102 + $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', $cdn_url );
1103 + }
1104 +
1105 + return $cdn_url;
1106 + }
1107 +
759 1108 public function get_lazyload_exclusions() {
760 1109 // returns array of strings that if found in an <img tag will stop the img from being lazy-loaded.
761 1110 static $exclude_lazyload_array = null;
762 1111
@@ -763,9 +1112,9 @@
763 1112 if ( null === $exclude_lazyload_array ) {
764 1113 $options = $this->options;
765 1114
766 1115 // set default exclusions.
767 - $exclude_lazyload_array = array( 'skip-lazy', 'data-no-lazy', 'notlazy', 'data-src', 'data-srcset', 'data:image/', 'data-lazyload', 'rev-slidebg' );
1116 + $exclude_lazyload_array = array( 'skip-lazy', 'data-no-lazy', 'notlazy', 'data-src', 'data-srcset', 'data:image/', 'data-lazyload', 'rev-slidebg', 'loading="eager"', 'fetchpriority="high"' );
768 1117
769 1118 // add from setting.
770 1119 if ( array_key_exists( 'autoptimize_imgopt_text_field_5', $options ) ) {
771 1120 $exclude_lazyload_option = $options['autoptimize_imgopt_text_field_5'];
@@ -784,9 +1133,9 @@
784 1133 public function inject_classes_in_tag( $tag, $target_class ) {
785 1134 if ( strpos( $tag, 'class=' ) !== false ) {
786 1135 $tag = preg_replace( '/(\sclass\s?=\s?("|\'))/', '$1' . $target_class, $tag );
787 1136 } else {
788 - $tag = str_replace( '<img ', '<img class="' . trim( $target_class ) . '" ', $tag );
1137 + $tag = preg_replace( '/(<[a-zA-Z]*)\s/', '$1 class="' . trim( $target_class ) . '" ', $tag );
789 1138 }
790 1139
791 1140 return $tag;
792 1141 }
@@ -794,21 +1143,21 @@
794 1143 public function get_default_lazyload_placeholder( $imgopt_w, $imgopt_h ) {
795 1144 return 'data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20' . $imgopt_w . '%20' . $imgopt_h . '%22%3E%3C/svg%3E';
796 1145 }
797 1146
798 - public function should_webp() {
799 - static $webp_return = null;
1147 + public function should_ngimg() {
1148 + static $ngimg_return = null;
800 1149
801 - if ( is_null( $webp_return ) ) {
802 - // webp only works if imgopt and lazyload are also active.
803 - if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) && $this->imgopt_active() ) {
804 - $webp_return = true;
1150 + if ( is_null( $ngimg_return ) ) {
1151 + // nextgen img only works if imgopt is active.
1152 + if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && $this->imgopt_active() ) {
1153 + $ngimg_return = true;
805 1154 } else {
806 - $webp_return = false;
1155 + $ngimg_return = false;
807 1156 }
808 1157 }
809 1158
810 - return $webp_return;
1159 + return $ngimg_return;
811 1160 }
812 1161
813 1162 public function process_picture_tag( $in, $imgopt = false, $lazy = false ) {
814 1163 // check if "<picture" is present and if filter allows us to process <picture>.
@@ -827,13 +1176,13 @@
827 1176 foreach ( $_sources as $_source ) {
828 1177 $_picture_replacement = $_source[0];
829 1178
830 1179 // should we optimize the image?
831 - if ( $imgopt && $this->can_optimize_image( $_source[1] ) ) {
1180 + if ( $imgopt && $this->can_optimize_image( $_source[1], $_picture[0] ) ) {
832 1181 $_picture_replacement = str_replace( $_source[1], $this->build_imgopt_url( $_source[1] ), $_picture_replacement );
833 1182 }
834 1183 // should we lazy-load?
835 - if ( $lazy && str_ireplace( $_exclusions, '', $_picture_replacement ) === $_picture_replacement ) {
1184 + if ( $lazy && $this->should_lazyload() && str_ireplace( $_exclusions, '', $_picture_replacement ) === $_picture_replacement ) {
836 1185 $_picture_replacement = str_replace( ' srcset=', ' data-srcset=', $_picture_replacement );
837 1186 }
838 1187 $to_replace_pict[ $_source[0] ] = $_picture_replacement;
839 1188 }
@@ -845,12 +1194,50 @@
845 1194
846 1195 return $out;
847 1196 }
848 1197
1198 + public function process_bgimage( $in ) {
1199 + if ( strpos( $in, 'background-image:' ) !== false && apply_filters( 'autoptimize_filter_imgopt_lazyload_backgroundimages', true ) ) {
1200 + $out = preg_replace_callback(
1201 + '/(<(?:article|aside|body|div|footer|header|p|section|span|table)[^>]*)\sstyle=(?:"|\')[^<>]*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)[^>]*/',
1202 + array( $this, 'lazyload_bgimg_callback' ),
1203 + $in
1204 + );
1205 + return $out;
1206 + }
1207 + return $in;
1208 + }
1209 +
1210 + public function lazyload_bgimg_callback( $matches ) {
1211 + if ( str_ireplace( $this->get_lazyload_exclusions(), '', $matches[0] ) === $matches[0] ) {
1212 + // get placeholder & lazyload class strings.
1213 + $placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( 500, 300 ) );
1214 + $lazyload_class = apply_filters( 'autoptimize_filter_imgopt_lazyload_class', 'lazyload' );
1215 + // remove quotes from url() to be able to replace in next step.
1216 + $out = str_replace( array( "url('" . $matches[2] . "')", 'url("' . $matches[2] . '")' ), 'url(' . $matches[2] . ')', $matches[0] );
1217 + // replace background-image URL with SVG placeholder.
1218 + $out = str_replace( 'url(' . $matches[2], 'url(' . $placeholder, $out );
1219 + // sanitize bgimg src for quote sillyness.
1220 + $bgimg_src = $this->fix_silly_bgimg_quotes( $matches[2] );
1221 + // add data-bg attribute with real background-image URL for lazyload to pick up.
1222 + $out = str_replace( $matches[1], $matches[1] . ' data-bg="' . $bgimg_src . '"', $out );
1223 + // and finally add lazyload class to tag.
1224 + $out = $this->inject_classes_in_tag( $out, "$lazyload_class " );
1225 + return $out;
1226 + }
1227 + return $matches[0];
1228 + }
1229 +
1230 + public function fix_silly_bgimg_quotes( $tag_in ) {
1231 + // some themes/ pagebuilders wrap backgroundimages in HTML-encoded quotes (or linebreaks) which breaks imgopt/ lazyloading, this removes them.
1232 + return trim( str_replace( array( "\r\n", '"', '&quot;', '&#034;', '&apos;', '&#039;' ), '', $tag_in ) );
1233 + }
1234 +
849 1235 public function maybe_fix_missing_quotes( $tag_in ) {
850 - // W3TC's Minify_HTML class removes quotes around attribute value, this re-adds them.
851 - if ( file_exists( WP_PLUGIN_DIR . '/w3-total-cache/w3-total-cache.php' ) && class_exists( 'Minify_HTML' ) && apply_filters( 'autoptimize_filter_imgopt_fixquotes', true ) ) {
852 - return preg_replace( '/=([^("|\')]*)(\s|>)/U', '=\'$1\'$2', $tag_in );
1236 + // W3TC's Minify_HTML class removes quotes around attribute value, this re-adds them for the class and width/height attributes so we can lazyload properly.
1237 + if ( ( file_exists( WP_PLUGIN_DIR . '/w3-total-cache/w3-total-cache.php' ) && class_exists( 'Minify_HTML' ) && apply_filters( 'autoptimize_filter_imgopt_fixquotes', true ) ) ) {
1238 + $tag_out = autoptimizeAttributeParser::rebuild( $tag_in );
1239 + return $tag_out;
853 1240 } else {
854 1241 return $tag_in;
855 1242 }
856 1243 }
@@ -859,22 +1246,27 @@
859 1246 * Admin page logic and related functions below.
860 1247 */
861 1248 public function imgopt_admin_menu()
862 1249 {
863 - add_submenu_page(
864 - null,
865 - 'autoptimize_imgopt',
866 - 'autoptimize_imgopt',
867 - 'manage_options',
868 - 'autoptimize_imgopt',
869 - array( $this, 'imgopt_options_page' )
870 - );
1250 + // no acces if multisite and not network admin and no site config allowed.
1251 + if ( autoptimizeConfig::should_show_menu_tabs() ) {
1252 + add_submenu_page(
1253 + '',
1254 + 'autoptimize_imgopt',
1255 + 'autoptimize_imgopt',
1256 + 'manage_options',
1257 + 'autoptimize_imgopt',
1258 + array( $this, 'imgopt_options_page' )
1259 + );
1260 + }
871 1261 register_setting( 'autoptimize_imgopt_settings', 'autoptimize_imgopt_settings' );
872 1262 }
873 1263
874 1264 public function add_imgopt_tab( $in )
875 1265 {
876 - $in = array_merge( $in, array( 'autoptimize_imgopt' => __( 'Images', 'autoptimize' ) ) );
1266 + if ( autoptimizeConfig::should_show_menu_tabs() ) {
1267 + $in = array_merge( $in, array( 'autoptimize_imgopt' => apply_filters( 'autoptimize_filter_imgopt_tab_text', esc_html__( 'Images', 'autoptimize' ) ) ) );
1268 + }
877 1269
878 1270 return $in;
879 1271 }
880 1272
@@ -879,11 +1271,14 @@
879 1271 }
880 1272
881 1273 public function imgopt_options_page()
882 1274 {
1275 + // phpcs:disable Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace
1276 + // phpcs:disable Generic.Formatting.DisallowMultipleStatements.SameLine
1277 +
883 1278 // Check querystring for "refreshCacheChecker" and call cachechecker if so.
884 1279 if ( array_key_exists( 'refreshImgProvStats', $_GET ) && 1 == $_GET['refreshImgProvStats'] ) {
885 - $this->query_img_provider_stats();
1280 + $this->query_img_provider_stats( true );
886 1281 }
887 1282
888 1283 $options = $this->fetch_options();
889 1284 $sp_url_suffix = $this->get_service_url_suffix();
@@ -891,17 +1286,26 @@
891 1286 <style>
892 1287 #ao_settings_form {background: white;border: 1px solid #ccc;padding: 1px 15px;margin: 15px 10px 10px 0;}
893 1288 #ao_settings_form .form-table th {font-weight: normal;}
894 1289 #autoptimize_imgopt_descr{font-size: 120%;}
1290 + #ao_settings_form td p.condition-warning {color: orange;}
895 1291 </style>
1292 + <script>document.title = "Autoptimize: <?php esc_html_e( 'Images', 'autoptimize' ); ?> " + document.title;</script>
896 1293 <div class="wrap">
897 - <h1><?php _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
1294 + <h1><?php apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? esc_html_e( 'Autoptimize Pro Settings', 'autoptimize' ) : esc_html_e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
898 1295 <?php echo autoptimizeConfig::ao_admin_tabs(); ?>
1296 + <?php if ( autoptimizeUtils::is_local_server() ) { ?>
1297 + <div class="notice-warning notice"><p>
1298 + <?php
1299 + echo esc_html__( 'The image optimization service does not work on locally hosted sites or when the server is on a private network.', 'autoptimize' );
1300 + ?>
1301 + </p></div>
1302 + <?php } ?>
899 1303 <?php if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) { ?>
900 1304 <div class="notice-warning notice"><p>
901 1305 <?php
902 1306 // translators: "Autoptimize support forum" will appear in a "a href".
903 - 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>' );
1307 + echo sprintf( esc_html__( '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>' );
904 1308 ?>
905 1309 </p></div>
906 1310 <?php } ?>
907 1311
@@ -906,9 +1310,9 @@
906 1310 <?php } ?>
907 1311
908 1312 <?php if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] && ! autoptimizeImages::instance()->launch_ok() ) { ?>
909 1313 <div class="notice-warning notice"><p>
910 - <?php _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' ); ?>
1314 + <?php esc_html_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' ); ?>
911 1315 </p></div>
912 1316 <?php } ?>
913 1317
914 1318 <?php if ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'get_active_modules' ) && in_array( 'photon', Jetpack::get_active_modules() ) ) { ?>
@@ -914,24 +1318,24 @@
914 1318 <?php if ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'get_active_modules' ) && in_array( 'photon', Jetpack::get_active_modules() ) ) { ?>
915 1319 <div class="notice-warning notice"><p>
916 1320 <?php
917 1321 // translators: "disable Jetpack's site accelerator for images" will appear in a "a href" linking to the jetpack settings page.
918 - echo sprintf( __( 'Please %1$sdisable Jetpack\'s site accelerator for images%2$s to be able to use Autoptomize\'s advanced image optimization features below.', 'autoptimize' ), '<a href="admin.php?page=jetpack#/settings">', '</a>' );
1322 + echo sprintf( esc_html__( 'Please %1$sdisable Jetpack\'s site accelerator for images%2$s to be able to use Autoptomize\'s advanced image optimization features below.', 'autoptimize' ), '<a href="admin.php?page=jetpack#/settings">', '</a>' );
919 1323 ?>
920 1324 </p></div>
921 1325 <?php } ?>
922 - <form id='ao_settings_form' action='options.php' method='post'>
1326 + <form id='ao_settings_form' action='<?php echo admin_url( 'options.php' ); ?>' method='post'>
923 1327 <?php settings_fields( 'autoptimize_imgopt_settings' ); ?>
924 - <h2><?php _e( 'Image optimization', 'autoptimize' ); ?></h2>
925 - <span id='autoptimize_imgopt_descr'><?php _e( 'Make your site significantly faster by just ticking a couple of checkboxes to optimize and lazy load your images, WebP support included!', 'autoptimize' ); ?></span>
1328 + <h2><?php esc_html_e( 'Image optimization', 'autoptimize' ); ?></h2>
1329 + <span id='autoptimize_imgopt_descr'><?php echo apply_filters( 'autoptimize_filter_imgopt_intro_copy', esc_html__( 'Make your site significantly faster by simply ticking a few boxes and start serving CDN powered, optimized images in the next-gen WebP image format! No additional plugins or services needed.', 'autoptimize' ) ); ?></span>
926 1330 <table class="form-table">
927 1331 <tr>
928 - <th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th>
1332 + <th scope="row"><?php esc_html_e( 'Image optimization & CDN', 'autoptimize' ); ?></th>
929 1333 <td>
930 - <label><input id='autoptimize_imgopt_checkbox' type='checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_1]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_1'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Optimize images on the fly and serve them from Shortpixel\'s global CDN.', 'autoptimize' ); ?></label>
1334 + <label><input id='autoptimize_imgopt_checkbox' type='checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_1]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_1'] ) { echo 'checked="checked"'; } ?> value='1'><?php echo apply_filters( 'autoptimize_filter_imgopt_main_setting_copy', esc_html__( 'On-the-fly image optimization and fast delivery via the Shortpixel global CDN.', 'autoptimize' ) ); ?></label>
931 1335 <?php
932 1336 // show shortpixel status.
933 - $_notice = autoptimizeImages::instance()->get_status_notice();
1337 + $_notice = autoptimizeImages::instance()->get_imgopt_status_notice();
934 1338 if ( $_notice ) {
935 1339 switch ( $_notice['status'] ) {
936 1340 case 2:
937 1341 $_notice_color = 'green';
@@ -939,38 +1343,44 @@
939 1343 case 1:
940 1344 $_notice_color = 'orange';
941 1345 break;
942 1346 case -1:
943 - $_notice_color = 'red';
944 - break;
945 1347 case -2:
1348 + case -3:
946 1349 $_notice_color = 'red';
947 1350 break;
948 1351 default:
949 1352 $_notice_color = 'green';
950 1353 }
951 - echo apply_filters( 'autoptimize_filter_imgopt_settings_status', '<p><strong><span style="color:' . $_notice_color . ';">' . __( 'Shortpixel status: ', 'autoptimize' ) . '</span></strong>' . $_notice['notice'] . '</p>' );
1354 + echo apply_filters( 'autoptimize_filter_imgopt_settings_status', '<p><strong><span style="color:' . $_notice_color . ';">' . esc_html__( 'Shortpixel status: ', 'autoptimize' ) . '</span></strong>' . $_notice['notice'] . '</p>' );
952 1355 } else {
953 1356 // translators: link points to shortpixel.
954 - $upsell_msg_1 = '<p>' . sprintf( __( 'Get more Google love and improve your website\'s loading speed by having the images optimized on the fly (also in the "next-gen" WebP image format) by %1$sShortPixel%2$s and then cached and served fast from Shortpixel\'s global CDN.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>' );
1357 + $upsell_msg_1 = '<p>' . sprintf( esc_html__( 'Get more Google love by speeding up your website. Start serving on-the-fly optimized images (also in the "next-gen" %4$sWebP%5$s image format) by %1$sShortPixel%2$s. No additional image optimization plugins are needed: your images are optimized, cached and served from %3$sShortPixel\'s global CDN%2$s.', 'autoptimize' ), '<a href="https://misc.optimizingmatters.com/partners/?from=aofree&partner=shortpixelupsell" target="_blank">', '</a>', '<a href="https://help.shortpixel.com/article/62-where-does-the-cdn-has-pops" target="_blank">', '<strong>', '</strong>' );
955 1358 if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] ) {
956 - $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' );
1359 + $upsell_msg_2 = sprintf( esc_html__( 'For a limited time only, this service is offered free for all Autoptimize users, %1$sdon\'t miss the chance to test it%2$s and see how much it could improve your site\'s speed.', 'autoptimize' ), '<strong>', '</strong>' );
957 1360 } else {
958 - // translators: link points to shortpixel.
959 - $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>' );
1361 + // translators: 1st link points to autoptimize.com.pro, 2nd to shortpixel.
1362 + $upsell_msg_2 = sprintf( esc_html__( 'For (nearly) %5$sunlimited image optimizations %1$sbuy Autoptimize Pro%2$s%6$s which also includes Critical CSS and extra "booster" options or %3$ssign up at Shortpixel%4$s.', 'autoptimize' ), '<a href="https://autoptimize.com/pro/" target="_blank">', '</a>', '<a href="https://misc.optimizingmatters.com/partners/?from=aofree&partner=shortpixelupsell" target="_blank">', '</a>', '<strong>', '</strong>' );
960 1363 }
961 - echo apply_filters( 'autoptimize_imgopt_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
1364 + echo apply_filters( 'autoptimize_filter_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
962 1365 }
963 1366 // translators: link points to shortpixel FAQ.
964 - $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>' );
1367 + $faqcopy = sprintf( esc_html__( '%3$sQuestions%4$s? Take a look at the %1$sAutoptimize + ShortPixel FAQ%2$s!', 'autoptimize' ), '<strong><a href="https://help.shortpixel.com/category/405-autoptimize" target="_blank">', '</strong></a>', '<strong>', '</strong>' );
1368 + $faqcopy = $faqcopy . ' ' . esc_html__( 'Only works for websites and images that are publicly available.', 'autoptimize' );
965 1369 // translators: links points to shortpixel TOS & Privacy Policy.
966 - $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>' );
967 - echo apply_filters( 'autoptimize_imgopt_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
1370 + $toscopy = sprintf( esc_html__( '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/privacy' . $sp_url_suffix . '" target="_blank">', '</a>' );
1371 + echo apply_filters( 'autoptimize_filter_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
968 1372 ?>
969 1373 </td>
970 1374 </tr>
1375 + <tr id='autoptimize_imgopt_optimization_exclusions' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>>
1376 + <th scope="row"><?php esc_html_e( 'Optimization exclusions', 'autoptimize' ); ?></th>
1377 + <td>
1378 + <label><input type='text' style='width:80%' id='autoptimize_imgopt_optimization_exclusions' name='autoptimize_imgopt_settings[autoptimize_imgopt_text_field_6]' value='<?php if ( ! empty( $options['autoptimize_imgopt_text_field_6'] ) ) { echo esc_attr( $options['autoptimize_imgopt_text_field_6'] ); } ?>'><br /><?php esc_html_e( 'Comma-separated list of image classes or filenames that should not be optimized.', 'autoptimize' ); ?></label>
1379 + </td>
1380 + </tr>
971 1381 <tr id='autoptimize_imgopt_quality' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>>
972 - <th scope="row"><?php _e( 'Image Optimization quality', 'autoptimize' ); ?></th>
1382 + <th scope="row"><?php esc_html_e( 'Image Optimization quality', 'autoptimize' ); ?></th>
973 1383 <td>
974 1384 <label>
975 1385 <select name='autoptimize_imgopt_settings[autoptimize_imgopt_select_field_2]'>
976 1386 <?php
@@ -990,33 +1400,60 @@
990 1400 </label>
991 1401 <p>
992 1402 <?php
993 1403 // translators: link points to shortpixel image test page.
994 - echo apply_filters( 'autoptimize_imgopt_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>' ) );
1404 + echo apply_filters( 'autoptimize_filter_imgopt_quality_copy', sprintf( esc_html__( 'You can %1$stest compression levels here%2$s.', 'autoptimize' ), '<a href="https://shortpixel.com/online-image-compression' . $sp_url_suffix . '" target="_blank">', '</a>' ) );
995 1405 ?>
996 1406 </p>
997 1407 </td>
998 1408 </tr>
999 - <tr id='autoptimize_imgopt_webp' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>>
1000 - <th scope="row"><?php _e( 'Load WebP in supported browsers?', 'autoptimize' ); ?></th>
1409 + <?php
1410 + if ( apply_filters( 'autoptimize_filter_imgopt_settings_show_avif', false ) || $this->should_ngimg() ) {
1411 + ?>
1412 + <tr id='autoptimize_imgopt_ngimg' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>>
1413 + <th scope="row">
1414 + <?php esc_html_e( 'Load AVIF in supported browsers?', 'autoptimize' ); ?>
1415 + </th>
1416 + <td>
1417 + <p class="condition-warning">
1418 + <?php
1419 + if ( '3' === autoptimizeImages::instance()->get_img_quality_setting() && $this->should_ngimg() ) {
1420 + _e( 'Your Image optimization quality is set to "lossless", but AVIF files can end up being bigger than jpeg or webp for lossless images, so consider choosing a different quality or disable the AVIF option.', 'autoptimize' );
1421 + }
1422 + ?>
1423 + </p>
1424 + <label><input type='checkbox' id='autoptimize_imgopt_ngimg_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_4'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_4'] ) { echo 'checked="checked"'; } ?> value='1'>
1425 + <?php esc_html_e( 'Automatically serve AVIF image format to any browser that supports it.', 'autoptimize' ); ?> <?php printf( esc_html__( '%1$sImportant caveat%2$s; although it %5$scan result in even smaller image sizes for lossy images%4$s it should be taken into account that %3$s%1$sAVIF can require more resources%2$s to decode/ display%4$s and as such %1$smight be slower%2$s on low-end (mobile) devices.', 'autoptimize' ), '<strong>', '</strong>', '<a href="https://storage.googleapis.com/avif-comparison/decode-timing.html" target="_blank">', '</a>', '<a href="https://tsev.dev/posts/2023-11-10-should-avif-be-the-dominant-image-format/" target="_blank">' ); ?>
1426 + </label>
1427 + </td>
1428 + </tr>
1429 + <?php
1430 + } else {
1431 + ?>
1432 + <input type='hidden' id='autoptimize_imgopt_ngimg_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' value='0'>
1433 + <?php
1434 + }
1435 + ?>
1436 + <tr>
1437 + <th scope="row"><?php esc_html_e( 'Lazy-load images?', 'autoptimize' ); ?></th>
1001 1438 <td>
1002 - <label><input type='checkbox' id='autoptimize_imgopt_webp_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_4'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_3'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Automatically serve "next-gen" WebP image format to any browser that supports it (requires lazy load to be active).', 'autoptimize' ); ?></label>
1439 + <label><input type='checkbox' id='autoptimize_imgopt_lazyload_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_3]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_3'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_3'] ) { echo 'checked="checked"'; } ?> value='1'><?php esc_html_e( 'Image lazy-loading will delay the loading of non-visible images to allow the browser to optimally load all resources for the "above the fold"-page first.', 'autoptimize' ); ?></label>
1003 1440 </td>
1004 1441 </tr>
1005 - <tr>
1006 - <th scope="row"><?php _e( 'Lazy-load images?', 'autoptimize' ); ?></th>
1442 + <tr id='autoptimize_imgopt_lazyload_exclusions' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_3', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_3'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_3'] ) ) { echo 'class="autoptimize_lazyload_child hidden"'; } else { echo 'class="autoptimize_lazyload_child"'; } ?>>
1443 + <th scope="row"><?php esc_html_e( 'Lazy-load exclusions', 'autoptimize' ); ?></th>
1007 1444 <td>
1008 - <label><input type='checkbox' id='autoptimize_imgopt_lazyload_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_3]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_3'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_3'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Image lazy-loading will delay the loading of non-visible images to allow the browser to optimally load all resources for the "above the fold"-page first.', 'autoptimize' ); ?></label>
1445 + <label><input type='text' style='width:80%' id='autoptimize_imgopt_lazyload_exclusions_text' name='autoptimize_imgopt_settings[autoptimize_imgopt_text_field_5]' value='<?php if ( ! empty( $options['autoptimize_imgopt_text_field_5'] ) ) { echo esc_attr( $options['autoptimize_imgopt_text_field_5'] ); } ?>'><br /><?php esc_html_e( 'Comma-separated list of to be excluded image classes or filenames.', 'autoptimize' ); ?></label>
1009 1446 </td>
1010 1447 </tr>
1011 - <tr id='autoptimize_imgopt_lazyload_exclusions' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_3', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_3'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_3'] ) ) { echo 'class="hidden"'; } ?>>
1012 - <th scope="row"><?php _e( 'Lazy-load exclusions', 'autoptimize' ); ?></th>
1448 + <tr id='autoptimize_imgopt_lazyload_from_nth_image' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_3', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_3'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_3'] ) ) { echo 'class="autoptimize_lazyload_child hidden"'; } else { echo 'class="autoptimize_lazyload_child"'; } ?>>
1449 + <th scope="row"><?php esc_html_e( 'Lazy-load from nth image', 'autoptimize' ); ?></th>
1013 1450 <td>
1014 - <label><input type='text' style='width:80%' id='autoptimize_imgopt_lazyload_exclusions' name='autoptimize_imgopt_settings[autoptimize_imgopt_text_field_5]' value='<?php if ( ! empty( $options['autoptimize_imgopt_text_field_5'] ) ) { echo esc_attr( $options['autoptimize_imgopt_text_field_5'] ); } ?>'><br /><?php _e( 'Comma-separated list of to be excluded image classes or filenames.', 'autoptimize' ); ?></label>
1451 + <label><input type='number' min='0' max='50' style='width:80%' id='autoptimize_imgopt_lazyload_from_nth_image_number' name='autoptimize_imgopt_settings[autoptimize_imgopt_number_field_7]' value='<?php if ( ! empty( $options['autoptimize_imgopt_number_field_7'] ) ) { echo esc_attr( $options['autoptimize_imgopt_number_field_7'] ); } else { echo '1'; } ?>'><br /><?php esc_html_e( 'Don\'t lazyload the first X images, \'1\' lazyloads all.', 'autoptimize' ); ?></label>
1015 1452 </td>
1016 1453 </tr>
1017 1454 </table>
1018 - <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" /></p>
1455 + <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php esc_html_e( 'Save Changes', 'autoptimize' ); ?>" /></p>
1019 1456 </form>
1020 1457 <script>
1021 1458 jQuery(document).ready(function() {
1022 1459 jQuery("#autoptimize_imgopt_checkbox").change(function() {
@@ -1021,26 +1458,21 @@
1021 1458 jQuery(document).ready(function() {
1022 1459 jQuery("#autoptimize_imgopt_checkbox").change(function() {
1023 1460 if (this.checked) {
1024 1461 jQuery("#autoptimize_imgopt_quality").show("slow");
1025 - jQuery("#autoptimize_imgopt_webp").show("slow");
1462 + jQuery("#autoptimize_imgopt_ngimg").show("slow");
1463 + jQuery("#autoptimize_imgopt_optimization_exclusions").show("slow");
1026 1464 } else {
1027 1465 jQuery("#autoptimize_imgopt_quality").hide("slow");
1028 - jQuery("#autoptimize_imgopt_webp").hide("slow");
1466 + jQuery("#autoptimize_imgopt_ngimg").hide("slow");
1467 + jQuery("#autoptimize_imgopt_optimization_exclusions").hide("slow");
1029 1468 }
1030 1469 });
1031 - jQuery("#autoptimize_imgopt_webp_checkbox").change(function() {
1032 - if (this.checked) {
1033 - jQuery("#autoptimize_imgopt_lazyload_checkbox")[0].checked = true;
1034 - jQuery("#autoptimize_imgopt_lazyload_exclusions").show("slow");
1035 - }
1036 - });
1037 1470 jQuery("#autoptimize_imgopt_lazyload_checkbox").change(function() {
1038 1471 if (this.checked) {
1039 - jQuery("#autoptimize_imgopt_lazyload_exclusions").show("slow");
1472 + jQuery(".autoptimize_lazyload_child").show("slow");
1040 1473 } else {
1041 - jQuery("#autoptimize_imgopt_lazyload_exclusions").hide("slow");
1042 - jQuery("#autoptimize_imgopt_webp_checkbox")[0].checked = false;
1474 + jQuery(".autoptimize_lazyload_child").hide("slow");
1043 1475 }
1044 1476 });
1045 1477 });
1046 1478 </script>
@@ -1050,38 +1482,54 @@
1050 1482 /**
1051 1483 * Ïmg opt status as used on dashboard.
1052 1484 */
1053 1485 public function get_imgopt_status_notice() {
1054 - if ( $this->imgopt_active() ) {
1055 - $_imgopt_notice = '';
1056 - $_stat = get_option( 'autoptimize_imgopt_provider_stat', '' );
1057 - $_site_host = AUTOPTIMIZE_SITE_DOMAIN;
1058 - $_imgopt_upsell = 'https://shortpixel.com/aospai/af/GWRGFLW109483/' . $_site_host;
1486 + if ( $this->imgopt_active() && apply_filters( 'autoptimize_filter_imgopt_status_shortpixel', true ) ) {
1487 + $_imgopt_notice = '';
1488 + $_stat = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' );
1489 + $_site_host = AUTOPTIMIZE_SITE_DOMAIN;
1490 + $_imgopt_upsell = 'https://misc.optimizingmatters.com/partners/?from=aofree&partner=shortpixelupsell';
1491 + $_imgopt_assoc = 'https://shortpixel.helpscoutdocs.com/article/94-how-to-associate-a-domain-to-my-account';
1492 + $_imgopt_unreach = 'https://shortpixel.helpscoutdocs.com/article/148-why-are-my-images-redirected-from-cdn-shortpixel-ai';
1059 1493
1060 1494 if ( is_array( $_stat ) ) {
1061 1495 if ( 1 == $_stat['Status'] ) {
1062 1496 // translators: "add more credits" will appear in a "a href".
1063 - $_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>' );
1497 + $_imgopt_notice = sprintf( esc_html__( '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 %4$sor consider using %3$sAutoptimize Pro%2$s which comes with (nearly) unlimited image optimization%5$s but also automated critical CSS and extra booster options.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>', '<a href="https://autoptimize.com/pro/" target="_blank">', '<strong>', '</strong>' );
1064 1498 } elseif ( -1 == $_stat['Status'] || -2 == $_stat['Status'] ) {
1065 1499 // translators: "add more credits" will appear in a "a href".
1066 - $_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>' );
1067 - $_imgopt_stats_refresh_url = add_query_arg( array(
1068 - 'page' => 'autoptimize_imgopt',
1069 - 'refreshImgProvStats' => '1',
1070 - ), admin_url( 'options-general.php' ) );
1500 + $_imgopt_notice = sprintf( esc_html__( 'Your ShortPixel image optimization and CDN quota has been exhausted, %1$sadd more credits%2$s to continue to quickly deliver optimized images on your website %4$sor consider using %3$sAutoptimize Pro%2$s which comes with (nearly) unlimited image optimization%5$s but also automated critical CSS and extra booster options.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>', '<a href="https://autoptimize.com/pro/" target="_blank">', '<strong>', '</strong>' );
1501 + // translators: "associate your domain" will appear in a "a href".
1502 + $_imgopt_notice = $_imgopt_notice . ' ' . sprintf( esc_html__( 'If you have enough CDN quota remaining, then you may need to %1$sassociate your domain%2$s to your Shortpixel account.', 'autoptimize' ), '<a rel="noopener noreferrer" href="' . $_imgopt_assoc . '" target="_blank">', '</a>' );
1503 + } elseif ( -3 == $_stat['Status'] ) {
1504 + // translators: "check the documentation here" will appear in a "a href".
1505 + $_imgopt_notice = sprintf( esc_html__( 'It seems ShortPixel image optimization is not able to fetch images from your site, %1$scheck the documentation here%2$s for more information', 'autoptimize' ), '<a href="' . $_imgopt_unreach . '" target="_blank">', '</a>' );
1506 + } else {
1507 + $_imgopt_upsell = 'https://misc.optimizingmatters.com/partners/?from=aofree&partner=shortpixelupsell';
1508 + // translators: "log in to check your account" will appear in a "a href".
1509 + $_imgopt_notice = sprintf( esc_html__( '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>' );
1510 + }
1511 +
1512 + // add info on freshness + refresh link if status is not 2 (good shape).
1513 + if ( 2 != $_stat['Status'] ) {
1514 + $_imgopt_stats_refresh_url = add_query_arg(
1515 + array(
1516 + 'page' => 'autoptimize_imgopt',
1517 + 'refreshImgProvStats' => '1',
1518 + ),
1519 + admin_url( 'options-general.php' )
1520 + );
1071 1521 if ( $_stat && array_key_exists( 'timestamp', $_stat ) && ! empty( $_stat['timestamp'] ) ) {
1072 - $_imgopt_stats_last_run = __( 'based on status at ', 'autoptimize' ) . date_i18n( get_option( 'time_format' ), $_stat['timestamp'] );
1522 + $_imgopt_stats_last_run = esc_html__( 'based on status at ', 'autoptimize' ) . date_i18n( autoptimizeOptionWrapper::get_option( 'time_format' ), $_stat['timestamp'] );
1073 1523 } else {
1074 - $_imgopt_stats_last_run = __( 'based on previously fetched data', 'autoptimize' );
1524 + $_imgopt_stats_last_run = esc_html__( 'based on previously fetched data', 'autoptimize' );
1075 1525 }
1076 1526 $_imgopt_notice .= ' (' . $_imgopt_stats_last_run . ', ';
1077 1527 // translators: "here to refresh" links to the Autoptimize Extra page and forces a refresh of the img opt stats.
1078 - $_imgopt_notice .= sprintf( __( 'click %1$shere to refresh%2$s', 'autoptimize' ), '<a href="' . $_imgopt_stats_refresh_url . '">', '</a>).' );
1079 - } else {
1080 - $_imgopt_upsell = 'https://shortpixel.com/g/af/GWRGFLW109483';
1081 - // translators: "log in to check your account" will appear in a "a href".
1082 - $_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>' );
1528 + $_imgopt_notice .= sprintf( esc_html__( 'you can click %1$shere to refresh your quota status%2$s', 'autoptimize' ), '<a href="' . $_imgopt_stats_refresh_url . '">', '</a>).' );
1083 1529 }
1530 +
1531 + // and make the full notice filterable.
1084 1532 $_imgopt_notice = apply_filters( 'autoptimize_filter_imgopt_notice', $_imgopt_notice );
1085 1533
1086 1534 return array(
1087 1535 'status' => $_stat['Status'],
@@ -1099,18 +1547,24 @@
1099 1547 }
1100 1548
1101 1549 /**
1102 1550 * Get img provider stats (used to display notice).
1551 + *
1552 + * @param bool $_refresh Should the stats be forcefully refreshed or not.
1103 1553 */
1104 - public function query_img_provider_stats() {
1105 - if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_1'] ) ) {
1554 + public function query_img_provider_stats( $_refresh = false ) {
1555 + if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_1'] ) && apply_filters( 'autoptimize_filter_imgopt_status_shortpixel', true ) ) {
1106 1556 $url = '';
1107 - $endpoint = $this->get_imgopt_host() . 'read-domain/';
1557 + $stat_dom = 'https://no-cdn.shortpixel.ai/';
1558 + $endpoint = $stat_dom . 'read-domain/';
1108 1559 $domain = AUTOPTIMIZE_SITE_DOMAIN;
1109 1560
1110 1561 // make sure parse_url result makes sense, keeping $url empty if not.
1111 1562 if ( $domain && ! empty( $domain ) ) {
1112 1563 $url = $endpoint . $domain;
1564 + if ( true === $_refresh ) {
1565 + $url = $url . '/refresh';
1566 + }
1113 1567 }
1114 1568
1115 1569 $url = apply_filters(
1116 1570 'autoptimize_filter_imgopt_stat_url',
@@ -1123,9 +1577,9 @@
1123 1577 $response = wp_remote_get( $url );
1124 1578 if ( ! is_wp_error( $response ) ) {
1125 1579 if ( '200' == wp_remote_retrieve_response_code( $response ) ) {
1126 1580 $stats = json_decode( wp_remote_retrieve_body( $response ), true );
1127 - update_option( 'autoptimize_imgopt_provider_stat', $stats );
1581 + autoptimizeOptionWrapper::update_option( 'autoptimize_imgopt_provider_stat', $stats );
1128 1582 }
1129 1583 }
1130 1584 }
1131 1585 }
@@ -1147,16 +1601,20 @@
1147 1601 {
1148 1602 static $launch_status = null;
1149 1603
1150 1604 if ( null === $launch_status ) {
1151 - $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
1605 + $avail_imgopt = '';
1606 + if ( is_array( $this->options ) && array_key_exists( 'availabilities', $this->options ) && is_array( $this->options['availabilities'] ) && array_key_exists( 'extra_imgopt', $this->options['availabilities'] ) ) {
1607 + $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
1608 + }
1609 +
1152 1610 $magic_number = intval( substr( md5( parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ), 0, 3 ), 16 );
1153 - $has_launched = get_option( 'autoptimize_imgopt_launched', '' );
1611 + $has_launched = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_launched', '' );
1154 1612 $launch_status = false;
1155 1613 if ( $has_launched || ( is_array( $avail_imgopt ) && array_key_exists( 'launch-threshold', $avail_imgopt ) && $magic_number < $avail_imgopt['launch-threshold'] ) ) {
1156 1614 $launch_status = true;
1157 1615 if ( ! $has_launched ) {
1158 - update_option( 'autoptimize_imgopt_launched', 'on' );
1616 + autoptimizeOptionWrapper::update_option( 'autoptimize_imgopt_launched', 'on' );
1159 1617 }
1160 1618 }
1161 1619 }
1162 1620
@@ -1172,9 +1630,9 @@
1172 1630 public function get_imgopt_provider_userstatus() {
1173 1631 static $_provider_userstatus = null;
1174 1632
1175 1633 if ( is_null( $_provider_userstatus ) ) {
1176 - $_stat = get_option( 'autoptimize_imgopt_provider_stat', '' );
1634 + $_stat = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' );
1177 1635 if ( is_array( $_stat ) ) {
1178 1636 if ( array_key_exists( 'Status', $_stat ) ) {
1179 1637 $_provider_userstatus['Status'] = $_stat['Status'];
1180 1638 } else {
@@ -1186,42 +1644,14 @@
1186 1644 } else {
1187 1645 // if no timestamp then we return "".
1188 1646 $_provider_userstatus['timestamp'] = '';
1189 1647 }
1648 + } else {
1649 + // no provider_stat yet, assume/ return all OK.
1650 + $_provider_userstatus['Status'] = 2;
1651 + $_provider_userstatus['timestamp'] = '';
1190 1652 }
1191 1653 }
1192 1654
1193 1655 return $_provider_userstatus;
1194 - }
1195 -
1196 - public function get_status_notice() {
1197 - if ( $this->imgopt_active() ) {
1198 - $notice = '';
1199 - $stat = $this->get_imgopt_provider_userstatus();
1200 - $upsell = 'https://shortpixel.com/aospai/af/GWRGFLW109483/' . AUTOPTIMIZE_SITE_DOMAIN;
1201 - $assoc = 'https://shortpixel.helpscoutdocs.com/article/94-how-to-associate-a-domain-to-my-account';
1202 -
1203 - if ( is_array( $stat ) ) {
1204 - if ( 1 == $stat['Status'] ) {
1205 - // translators: "add more credits" will appear in a "a href".
1206 - $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 rel="noopener noreferrer" href="' . $upsell . '" target="_blank">', '</a>' );
1207 - } elseif ( -1 == $stat['Status'] || -2 == $stat['Status'] ) {
1208 - // translators: "add more credits" will appear in a "a href".
1209 - $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 rel="noopener noreferrer" href="' . $upsell . '" target="_blank">', '</a>' );
1210 - // translators: "associate your domain" will appear in a "a href".
1211 - $notice = $notice . ' ' . sprintf( __( 'If you already have enough credits then you may need to %1$sassociate your domain%2$s to your Shortpixel account.', 'autoptimize' ), '<a rel="noopener noreferrer" href="' . $assoc . '" target="_blank">', '</a>' );
1212 - } else {
1213 - $upsell = 'https://shortpixel.com/g/af/GWRGFLW109483';
1214 - // translators: "log in to check your account" will appear in a "a href".
1215 - $notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota are in good shape, %1$slog in to check your account%2$s.', 'autoptimize' ), '<a rel="noopener noreferrer" href="' . $upsell . '" target="_blank">', '</a>' );
1216 - }
1217 - $notice = apply_filters( 'autoptimize_filter_imgopt_notice', $notice );
1218 -
1219 - return array(
1220 - 'status' => $stat['Status'],
1221 - 'notice' => $notice,
1222 - );
1223 - }
1224 - }
1225 - return false;
1226 1656 }
1227 1657 }