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/autoptimizeImages.php +644 -214 2.5.1 → trunk 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 }