PluginProbe
Autoptimize / 3.1.4
Autoptimize v3.1.4
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 2.7.8 All 107 releases
← All changes | classes/autoptimizeImages.php +403 -126 2.6.23.1.4 View file →
@@ -30,8 +30,9 @@
30 30 $options = $this->fetch_options();
31 31 }
32 32
33 33 $this->set_options( $options );
34 + $this->lazyload_counter = 0;
34 35 }
35 36
36 37 public function set_options( array $options )
37 38 {
@@ -50,10 +51,30 @@
50 51
51 52 // get service availability and add it to the options-array.
52 53 $value['availabilities'] = autoptimizeOptionWrapper::get_option( 'autoptimize_service_availablity' );
53 54
54 - if ( empty( $value['availabilities'] ) ) {
55 - $value['availabilities'] = autoptimizeUtils::check_service_availability( true );
55 + if ( empty( $value['availabilities'] ) || ! is_array( $value['availabilities'] ) ) {
56 + $value['availabilities'] = null;
57 +
58 + if ( true === autoptimizeImages::imgopt_active() ) {
59 + $value['availabilities'] = autoptimizeUtils::check_service_availability( true );
60 + }
61 +
62 + if ( null === $value['availabilities'] ) {
63 + // We can't seem to check service availability, use mock result with imgopt status UP.
64 + $_mock_settings = array(
65 + 'extra_imgopt' => array(
66 + 'status' => 'up',
67 + 'hosts' => array(
68 + '1' => 'https://sp-ao.shortpixel.ai/',
69 + ),
70 + ),
71 + 'critcss' => array(
72 + 'status' => 'up',
73 + ),
74 + );
75 + $value['availabilities'] = $_mock_settings;
76 + }
56 77 }
57 78
58 79 return $value;
59 80 }
@@ -111,8 +132,14 @@
111 132 public function run_on_frontend() {
112 133 if ( ! $this->should_run() ) {
113 134 if ( $this->should_lazyload() ) {
114 135 add_filter(
136 + 'wp_lazy_loading_enabled',
137 + array( $this, 'should_disable_core_lazyload' ),
138 + 10,
139 + 3
140 + );
141 + add_filter(
115 142 'autoptimize_html_after_minify',
116 143 array( $this, 'filter_lazyload_images' ),
117 144 10,
118 145 1
@@ -158,8 +185,14 @@
158 185 );
159 186 }
160 187
161 188 if ( $this->should_lazyload() ) {
189 + add_filter(
190 + 'wp_lazy_loading_enabled',
191 + array( $this, 'should_disable_core_lazyload' ),
192 + 10,
193 + 3
194 + );
162 195 add_action(
163 196 'wp_footer',
164 197 array( $this, 'add_lazyload_js_footer' ),
165 198 10,
@@ -168,8 +201,24 @@
168 201 }
169 202 }
170 203
171 204 /**
205 + * Disables core's native lazyload for images, not for iframes.
206 + *
207 + * @param bool $flag Incoming flag (mostly true).
208 + * @param string $tag Tag (img or iframe).
209 + * @param string $context Full context.
210 + *
211 + * @return bool
212 + */
213 + public function should_disable_core_lazyload( $flag = true, $tag = '', $context = '' ) {
214 + if ( 'img' === $tag ) {
215 + return false;
216 + }
217 + return $flag;
218 + }
219 +
220 + /**
172 221 * Basic checks before we can run.
173 222 *
174 223 * @return bool
175 224 */
@@ -201,9 +250,9 @@
201 250 {
202 251 static $imgopt_host = null;
203 252
204 253 if ( null === $imgopt_host ) {
205 - $imgopt_host = 'https://cdn.shortpixel.ai/';
254 + $imgopt_host = 'https://sp-ao.shortpixel.ai/';
206 255 $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
207 256 if ( ! empty( $avail_imgopt ) && array_key_exists( 'hosts', $avail_imgopt ) && is_array( $avail_imgopt['hosts'] ) ) {
208 257 $imgopt_host = array_rand( array_flip( $avail_imgopt['hosts'] ) );
209 258 }
@@ -221,9 +270,9 @@
221 270 }
222 271
223 272 public static function get_service_url_suffix()
224 273 {
225 - $suffix = '/af/GWRGFLW109483/' . AUTOPTIMIZE_SITE_DOMAIN;
274 + $suffix = '/af/U0ZIWMK109483/' . AUTOPTIMIZE_SITE_DOMAIN;
226 275
227 276 return $suffix;
228 277 }
229 278
@@ -336,11 +385,9 @@
336 385 // Default to (the trimmed version of) what was given to us.
337 386 $result = trim( $in );
338 387
339 388 // Some silly plugins wrap background images in html-encoded quotes, so remove those from the img url.
340 - if ( strpos( $result, '"' ) !== false ) {
341 - $result = str_replace( '"', '', $result );
342 - }
389 + $result = $this->fix_silly_bgimg_quotes( $result );
343 390
344 391 if ( autoptimizeUtils::is_protocol_relative( $result ) ) {
345 392 $result = $parsed_site_url['scheme'] . ':' . $result;
346 393 } elseif ( 0 === strpos( $result, '/' ) ) {
@@ -345,12 +392,18 @@
345 392 $result = $parsed_site_url['scheme'] . ':' . $result;
346 393 } elseif ( 0 === strpos( $result, '/' ) ) {
347 394 // Root-relative...
348 395 $result = $parsed_site_url['scheme'] . '://' . $parsed_site_url['host'] . $result;
349 - } elseif ( ! empty( $cdn_domain ) && strpos( $result, $cdn_domain ) !== 0 ) {
396 + } elseif ( ! empty( $cdn_domain ) && false === strpos( $this->get_imgopt_host(), $cdn_domain ) && strpos( $result, $cdn_domain ) !== 0 ) {
397 + // remove CDN except if it is the image optimization one.
350 398 $result = str_replace( $cdn_domain, $parsed_site_url['host'], $result );
351 399 }
352 400
401 + // filter (default off) to remove QS from image URL's to avoid eating away optimization credits.
402 + if ( apply_filters( 'autoptimize_filter_imgopt_no_querystring', false ) && strpos( $result, '?' ) !== false ) {
403 + $result = strtok( $result, '?' );
404 + }
405 +
353 406 $result = apply_filters( 'autoptimize_filter_imgopt_normalized_url', $result );
354 407
355 408 // Store in cache.
356 409 $cache[ $in ] = $result;
@@ -362,9 +415,9 @@
362 415 public function filter_optimize_css_images( $in )
363 416 {
364 417 $in = $this->normalize_img_url( $in );
365 418
366 - if ( $this->can_optimize_image( $in ) ) {
419 + if ( $this->can_optimize_image( $in ) && false === strpos( $in, $this->get_imgopt_host() ) ) {
367 420 return $this->build_imgopt_url( $in, '', '' );
368 421 } else {
369 422 return $in;
370 423 }
@@ -377,9 +430,15 @@
377 430 if ( null === $imgopt_base_url ) {
378 431 $imgopt_host = $this->get_imgopt_host();
379 432 $quality = $this->get_img_quality_string();
380 433 $ret_val = apply_filters( 'autoptimize_filter_imgopt_wait', 'ret_img' ); // values: ret_wait, ret_img, ret_json, ret_blank.
381 - $imgopt_base_url = $imgopt_host . 'client/' . $quality . ',' . $ret_val;
434 + if ( $this->should_ngimg() ) {
435 + $sp_to_string = 'to_auto';
436 + } else {
437 + $sp_to_string = 'to_webp';
438 + }
439 + $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).
440 + $imgopt_base_url = $imgopt_host . 'client/' . $sp_to_string . ',' . $quality . ',' . $ret_val;
382 441 $imgopt_base_url = apply_filters( 'autoptimize_filter_imgopt_base_url', $imgopt_base_url );
383 442 }
384 443
385 444 return $imgopt_base_url;
@@ -384,9 +443,14 @@
384 443
385 444 return $imgopt_base_url;
386 445 }
387 446
388 - private function can_optimize_image( $url )
447 + public static function can_optimize_image_wrapper( $url, $tag = '', $testing = false ) {
448 + $self = new self();
449 + return $self->can_optimize_image( $url, $tag = '', $testing = false );
450 + }
451 +
452 + private function can_optimize_image( $url, $tag = '', $testing = false )
389 453 {
390 454 static $cdn_url = null;
391 455 static $nopti_images = null;
392 456
@@ -396,10 +460,13 @@
396 460 autoptimizeOptionWrapper::get_option( 'autoptimize_cdn_url', '' )
397 461 );
398 462 }
399 463
400 - if ( null === $nopti_images ) {
401 - $nopti_images = apply_filters( 'autoptimize_filter_imgopt_noptimize', '' );
464 + if ( null === $nopti_images || $testing ) {
465 + if ( is_array( $this->options ) && array_key_exists( 'autoptimize_imgopt_text_field_6', $this->options ) ) {
466 + $nopti_images = $this->options['autoptimize_imgopt_text_field_6'];
467 + }
468 + $nopti_images = apply_filters( 'autoptimize_filter_imgopt_noptimize', $nopti_images );
402 469 }
403 470
404 471 $site_host = AUTOPTIMIZE_SITE_DOMAIN;
405 472 $url = $this->normalize_img_url( $url );
@@ -406,19 +473,21 @@
406 473 $url_parsed = parse_url( $url );
407 474
408 475 if ( array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host && empty( $cdn_url ) ) {
409 476 return false;
477 + } elseif ( autoptimizeUtils::is_local_server() ) {
478 + return false;
410 479 } elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host ) {
411 480 return false;
412 481 } elseif ( strpos( $url, '.php' ) !== false ) {
413 482 return false;
414 - } elseif ( str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg', '.webp' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) {
483 + } elseif ( str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg', '.webp', '.avif' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) {
415 484 // fixme: better check against end of string.
416 485 return false;
417 486 } elseif ( ! empty( $nopti_images ) ) {
418 487 $nopti_images_array = array_filter( array_map( 'trim', explode( ',', $nopti_images ) ) );
419 488 foreach ( $nopti_images_array as $nopti_image ) {
420 - if ( strpos( $url, $nopti_image ) !== false ) {
489 + if ( strpos( $url, $nopti_image ) !== false || ( ( '' !== $tag && strpos( $tag, $nopti_image ) !== false ) ) ) {
421 490 return false;
422 491 }
423 492 }
424 493 }
@@ -424,8 +493,14 @@
424 493 }
425 494 return true;
426 495 }
427 496
497 + // wrapper for reuse in AOPro.
498 + public static function build_imgopt_url_wrapper( $orig_url, $width = 0, $height = 0 ) {
499 + $self = new self();
500 + return $self->build_imgopt_url( $orig_url, $width = 0, $height = 0 );
501 + }
502 +
428 503 private function build_imgopt_url( $orig_url, $width = 0, $height = 0 )
429 504 {
430 505 // sanitize width and height.
431 506 if ( strpos( $width, '%' ) !== false ) {
@@ -448,9 +523,15 @@
448 523 if ( $filtered_url !== $orig_url ) {
449 524 return $filtered_url;
450 525 }
451 526
452 - $orig_url = $this->normalize_img_url( $orig_url );
527 + $normalized_url = $this->normalize_img_url( $orig_url );
528 +
529 + // 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.
530 + if ( apply_filters( 'autoptimize_filter_imgopt_check_normalized_url', true ) && ! preg_match( '/[^\x20-\x7e]/', $normalized_url ) && false === filter_var( $normalized_url, FILTER_VALIDATE_URL ) ) {
531 + return $orig_url;
532 + }
533 +
453 534 $imgopt_base_url = $this->get_imgopt_base_url();
454 535 $imgopt_size = '';
455 536
456 537 if ( $width && 0 !== $width ) {
@@ -460,9 +541,9 @@
460 541 if ( $height && 0 !== $height ) {
461 542 $imgopt_size .= ',h_' . $height;
462 543 }
463 544
464 - $url = $imgopt_base_url . $imgopt_size . '/' . $orig_url;
545 + $url = $imgopt_base_url . $imgopt_size . '/' . $normalized_url;
465 546
466 547 return $url;
467 548 }
468 549
@@ -473,9 +554,9 @@
473 554
474 555 public function replace_img_callback( $matches, $width = 0, $height = 0 )
475 556 {
476 557 $_normalized_img_url = $this->normalize_img_url( $matches[1] );
477 - if ( $this->can_optimize_image( $matches[1] ) ) {
558 + if ( $this->can_optimize_image( $matches[1], $matches[0] ) ) {
478 559 return str_replace( $matches[1], $this->build_imgopt_url( $_normalized_img_url, $width, $height ), $matches[0] );
479 560 } else {
480 561 return $matches[0];
481 562 }
@@ -480,10 +561,29 @@
480 561 return $matches[0];
481 562 }
482 563 }
483 564
484 - public function filter_optimize_images( $in )
565 + public function replace_icon_callback( $matches )
485 566 {
567 + if ( array_key_exists( '2', $matches ) ) {
568 + $sizes = explode( 'x', $matches[2] );
569 + $width = $sizes[0];
570 + $height = $sizes[1];
571 + } else {
572 + $width = 180;
573 + $height = 180;
574 + }
575 +
576 + // make sure we're not trying to optimize a *.ico file.
577 + if ( strpos( $matches[1], '.ico' ) === false ) {
578 + return $this->replace_img_callback( $matches, $width, $height );
579 + } else {
580 + return $matches[0];
581 + }
582 + }
583 +
584 + public function filter_optimize_images( $in, $testing = false )
585 + {
486 586 /*
487 587 * potential future functional improvements:
488 588 *
489 589 * filter for critical CSS.
@@ -488,11 +588,12 @@
488 588 *
489 589 * filter for critical CSS.
490 590 */
491 591 $to_replace = array();
592 + $to_preload = '';
492 593
493 - // hide noscript tags to avoid nesting noscript tags (as lazyloaded images add noscript).
494 - if ( $this->should_lazyload() ) {
594 + // hide (no)script tags to avoid replacing (and potentially breaking) images in script tags.
595 + if ( apply_filters( 'autoptimize_filter_imgopt_hide_script', true ) || $this->should_lazyload() ) {
495 596 $in = autoptimizeBase::replace_contents_with_marker_if_exists(
496 597 'SCRIPT',
497 598 '<script',
498 599 '#<(?:no)?script.*?<\/(?:no)?script>#is',
@@ -499,11 +600,18 @@
499 600 $in
500 601 );
501 602 }
502 603
604 + // get img preloads as set in post metabox, exploding ", " instead of "," because LCP preload
605 + // could be a shortpixel URL, which has comma's and results in way too many preloads.
606 + $metabox_preloads = array_filter( array_map( 'trim', explode( ', ', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) );
607 + $metabox_preloads = apply_filters( 'autoptimize_filter_images_metabox_preloads', $metabox_preloads );
608 +
503 609 // extract img tags.
504 610 if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
505 611 foreach ( $matches[0] as $tag ) {
612 + $tag = apply_filters( 'autoptimize_filter_imgopt_tag_preopt', $tag );
613 +
506 614 $orig_tag = $tag;
507 615 $imgopt_w = '';
508 616 $imgopt_h = '';
509 617
@@ -509,20 +617,22 @@
509 617
510 618 // first do (data-)srcsets.
511 619 if ( preg_match_all( '#srcset=("|\')(.*)("|\')#Usmi', $tag, $allsrcsets, PREG_SET_ORDER ) ) {
512 620 foreach ( $allsrcsets as $srcset ) {
513 - $srcset = $srcset[2];
514 - $srcsets = explode( ',', $srcset );
621 + $srcset = $srcset[2];
622 + $orig_srcset = $srcset;
623 + $srcsets = explode( ',', $srcset );
515 624 foreach ( $srcsets as $indiv_srcset ) {
516 625 $indiv_srcset_parts = explode( ' ', trim( $indiv_srcset ) );
517 626 if ( isset( $indiv_srcset_parts[1] ) && rtrim( $indiv_srcset_parts[1], 'w' ) !== $indiv_srcset_parts[1] ) {
518 627 $imgopt_w = rtrim( $indiv_srcset_parts[1], 'w' );
519 628 }
520 - if ( $this->can_optimize_image( $indiv_srcset_parts[0] ) ) {
629 + if ( $this->can_optimize_image( $indiv_srcset_parts[0], $tag, $testing ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
521 630 $imgopt_url = $this->build_imgopt_url( $indiv_srcset_parts[0], $imgopt_w, '' );
522 - $tag = str_replace( $indiv_srcset_parts[0], $imgopt_url, $tag );
631 + $srcset = str_replace( $indiv_srcset_parts[0], $imgopt_url, $srcset );
523 632 }
524 633 }
634 + $tag = str_replace( $orig_srcset, $srcset, $tag );
525 635 }
526 636 }
527 637
528 638 // proceed with img src.
@@ -535,9 +645,9 @@
535 645 if ( preg_match_all( '#src=(?:"|\')(?!data)(.*)(?:"|\')#Usmi', $tag, $urls, PREG_SET_ORDER ) ) {
536 646 foreach ( $urls as $url ) {
537 647 $full_src_orig = $url[0];
538 648 $url = $url[1];
539 - if ( $this->can_optimize_image( $url ) ) {
649 + if ( $this->can_optimize_image( $url, $tag, $testing ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
540 650 $imgopt_url = $this->build_imgopt_url( $url, $imgopt_w, $imgopt_h );
541 651 $full_imgopt_src = str_replace( $url, $imgopt_url, $full_src_orig );
542 652 $tag = str_replace( $full_src_orig, $full_imgopt_src, $tag );
543 653 }
@@ -543,10 +653,15 @@
543 653 }
544 654 }
545 655 }
546 656
657 + // check if the image needs to be prelaoded.
658 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) {
659 + $to_preload .= $this->create_img_preload_tag( $tag );
660 + }
661 +
547 662 // do lazyload stuff.
548 - if ( $this->should_lazyload( $in ) ) {
663 + if ( $this->should_lazyload( $in ) && ! empty( $url ) ) {
549 664 // first do lpiq placeholder logic.
550 665 if ( strpos( $url, $this->get_imgopt_host() ) === 0 ) {
551 666 // if all img src have been replaced during srcset, we have to extract the
552 667 // origin url from the imgopt one to be able to set a lqip placeholder.
@@ -557,9 +672,9 @@
557 672
558 673 $_url = $this->normalize_img_url( $_url );
559 674
560 675 $placeholder = '';
561 - if ( $this->can_optimize_image( $_url ) && apply_filters( 'autoptimize_filter_imgopt_lazyload_dolqip', true ) ) {
676 + 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 ) ) {
562 677 $lqip_w = '';
563 678 $lqip_h = '';
564 679 if ( isset( $imgopt_w ) && ! empty( $imgopt_w ) ) {
565 680 $lqip_w = ',w_' . $imgopt_w;
@@ -572,8 +687,15 @@
572 687 // then call add_lazyload-function with lpiq placeholder if set.
573 688 $tag = $this->add_lazyload( $tag, $placeholder );
574 689 }
575 690
691 + // add decoding="async" behind filter, not sure if I'll make it default true yet.
692 + if ( true === apply_filters( 'autoptimize_filter_imgopt_add_decoding', true ) && false === strpos( $tag, ' decoding=' ) ) {
693 + $tag = str_replace( '<img ', '<img decoding="async" ', $tag );
694 + }
695 +
696 + $tag = apply_filters( 'autoptimize_filter_imgopt_tag_postopt', $tag );
697 +
576 698 // and add tag to array for later replacement.
577 699 if ( $tag !== $orig_tag ) {
578 700 $to_replace[ $orig_tag ] = $tag;
579 701 }
@@ -582,15 +704,21 @@
582 704
583 705 // and replace all.
584 706 $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $in );
585 707
586 - // img thumbnails in e.g. woocommerce.
587 - if ( strpos( $out, 'data-thumb' ) !== false && apply_filters( 'autoptimize_filter_imgopt_datathumbs', true ) ) {
588 - $out = preg_replace_callback(
589 - '/\<div(?:[^>]?)\sdata-thumb\=(?:\"|\')(.+?)(?:\"|\')(?:[^>]*)?\>/s',
590 - array( $this, 'replace_data_thumbs' ),
591 - $out
592 - );
708 + // misc. node attributes that might hold image url's (incl. the previously separate data-thumb).
709 + $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' ) ) );
710 + if ( ! empty( $extra_attr_with_img ) && is_array( $extra_attr_with_img ) ) {
711 + foreach ( $extra_attr_with_img as $candidate ) {
712 + if ( is_array( $candidate ) && strpos( $out, $candidate[1] ) !== false ) {
713 + $_regex = '/\<' . $candidate[0] . '(?:[^>]*)?\s' . $candidate[1] . '=(?:"|\')(.+?)(?:"|\')(?:[^>]*)?>/s';
714 + $out = preg_replace_callback(
715 + $_regex,
716 + array( $this, 'replace_img_callback' ),
717 + $out
718 + );
719 + }
720 + }
593 721 }
594 722
595 723 // background-image in inline style.
596 724 if ( strpos( $out, 'background-image:' ) !== false && apply_filters( 'autoptimize_filter_imgopt_backgroundimages', true ) ) {
@@ -600,15 +728,19 @@
600 728 $out
601 729 );
602 730 }
603 731
604 - // lazyload: restore noscript tags + lazyload picture source tags and bgimage.
605 - if ( $this->should_lazyload() ) {
606 - $out = autoptimizeBase::restore_marked_content(
607 - 'SCRIPT',
732 + // act on icon links.
733 + if ( ( strpos( $out, '<link rel="icon"' ) !== false || ( strpos( $out, "<link rel='icon'" ) !== false ) ) && apply_filters( 'autoptimize_filter_imgopt_linkicon', true ) ) {
734 + $out = preg_replace_callback(
735 + '/<link\srel=(?:"|\')(?:apple-touch-)?icon(?:"|\').*\shref=(?:"|\')(.*)(?:"|\')(?:\ssizes=(?:"|\')(\d*x\d*)(?:"|\'))?\s\/>/Um',
736 + array( $this, 'replace_icon_callback' ),
608 737 $out
609 738 );
739 + }
610 740
741 + // lazyload picture source tags and bgimage.
742 + if ( $this->should_lazyload() ) {
611 743 $out = $this->process_picture_tag( $out, true, true );
612 744 $out = $this->process_bgimage( $out );
613 745 } else {
614 746 $out = $this->process_picture_tag( $out, true, false );
@@ -613,12 +745,31 @@
613 745 } else {
614 746 $out = $this->process_picture_tag( $out, true, false );
615 747 }
616 748
749 + // restore (no)script tags.
750 + if ( apply_filters( 'autoptimize_filter_imgopt_hide_script', true ) || $this->should_lazyload() ) {
751 + $out = autoptimizeBase::restore_marked_content(
752 + 'SCRIPT',
753 + $out
754 + );
755 + }
756 +
757 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
758 + // the preload was not in an img tag, so adding a non-responsive preload instead.
759 + foreach ( $metabox_preloads as $img_preload ) {
760 + $to_preload .= '<link rel="preload" href="' . $img_preload . '" as="image">';
761 + }
762 + }
763 +
764 + if ( ! empty( $to_preload ) ) {
765 + $out = autoptimizeExtra::inject_preloads( $to_preload, $out );
766 + }
767 +
617 768 return $out;
618 769 }
619 770
620 - public function get_size_from_tag( $tag ) {
771 + public static function get_size_from_tag( $tag ) {
621 772 // reusable function to extract widht and height from an image tag
622 773 // enforcing a filterable maximum width and height (default 4999X4999).
623 774 $width = '';
624 775 $height = '';
@@ -637,15 +788,19 @@
637 788 // check for and enforce (filterable) max sizes.
638 789 $_max_width = apply_filters( 'autoptimize_filter_imgopt_max_width', 4999 );
639 790 if ( $width > $_max_width ) {
640 791 $_width = $_max_width;
641 - $height = $_width / $width * $height;
792 + if ( ! empty( $height ) && is_int( $height ) ) {
793 + $height = $_width / $width * $height;
794 + }
642 795 $width = $_width;
643 796 }
644 797 $_max_height = apply_filters( 'autoptimize_filter_imgopt_max_height', 4999 );
645 798 if ( $height > $_max_height ) {
646 799 $_height = $_max_height;
647 - $width = $_height / $height * $width;
800 + if ( ! empty( $width ) && is_int( $width ) ) {
801 + $width = $_height / $height * $width;
802 + }
648 803 $height = $_height;
649 804 }
650 805
651 806 return array(
@@ -668,14 +823,20 @@
668 823 $lazyload_return = true;
669 824 } else {
670 825 $lazyload_return = false;
671 826 }
827 +
828 + // If page/ post check post_meta to see if lazyload is off for page.
829 + if ( false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_lazyload' ) ) {
830 + $lazyload_return = false;
831 + }
832 +
672 833 $lazyload_return = apply_filters( 'autoptimize_filter_imgopt_should_lazyload', $lazyload_return, $context );
673 834
674 835 return $lazyload_return;
675 836 }
676 837
677 - public function check_nolazy() {
838 + public static function check_nolazy() {
678 839 if ( array_key_exists( 'ao_nolazy', $_GET ) && '1' === $_GET['ao_nolazy'] ) {
679 840 return true;
680 841 } else {
681 842 return false;
@@ -685,8 +846,9 @@
685 846 public function filter_lazyload_images( $in )
686 847 {
687 848 // only used is image optimization is NOT active but lazyload is.
688 849 $to_replace = array();
850 + $to_preload = '';
689 851
690 852 // hide (no)script tags to avoid nesting noscript tags (as lazyloaded images add noscript).
691 853 $out = autoptimizeBase::replace_contents_with_marker_if_exists(
692 854 'SCRIPT',
@@ -694,11 +856,20 @@
694 856 '#<(?:no)?script.*?<\/(?:no)?script>#is',
695 857 $in
696 858 );
697 859
698 - // extract img tags and add lazyload attribs.
860 + // get img preloads as set in post metabox.
861 + $metabox_preloads = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) );
862 +
863 + // extract img tags and add lazyload attribs/ add preloads.
699 864 if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $out, $matches ) ) {
700 865 foreach ( $matches[0] as $tag ) {
866 + // check if image needs to be preloaded.
867 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) {
868 + $to_preload .= $this->create_img_preload_tag( $tag );
869 + }
870 +
871 + // and lazyloaded.
701 872 if ( $this->should_lazyload( $out ) ) {
702 873 $to_replace[ $tag ] = $this->add_lazyload( $tag );
703 874 }
704 875 }
@@ -716,14 +887,33 @@
716 887 'SCRIPT',
717 888 $out
718 889 );
719 890
891 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
892 + // the preload was not in an img tag, so adding a non-responsive preload instead.
893 + foreach ( $metabox_preloads as $img_preload ) {
894 + $to_preload .= '<link rel="preload" href="' . $img_preload . '" as="image">';
895 + }
896 + }
897 +
898 + if ( ! empty( $to_preload ) ) {
899 + $out = autoptimizeExtra::inject_preloads( $to_preload, $out );
900 + }
901 +
720 902 return $out;
721 903 }
722 904
723 905 public function add_lazyload( $tag, $placeholder = '' ) {
724 906 // adds actual lazyload-attributes to an image node.
725 - if ( str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag ) {
907 + $this->lazyload_counter++;
908 +
909 + $_lazyload_from_nth = '';
910 + if ( array_key_exists( 'autoptimize_imgopt_number_field_7', $this->options ) ) {
911 + $_lazyload_from_nth = $this->options['autoptimize_imgopt_number_field_7'];
912 + }
913 + $_lazyload_from_nth = apply_filters( 'autoptimize_filter_imgopt_lazyload_from_nth', $_lazyload_from_nth );
914 +
915 + if ( str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag && $this->lazyload_counter >= $_lazyload_from_nth ) {
726 916 $tag = $this->maybe_fix_missing_quotes( $tag );
727 917
728 918 // store original tag for use in noscript version.
729 919 $noscript_tag = '<noscript>' . autoptimizeUtils::remove_id_from_node( $tag ) . '</noscript>';
@@ -737,13 +927,13 @@
737 927 // get image width & heigth for placeholder fun (and to prevent content reflow).
738 928 $_get_size = $this->get_size_from_tag( $tag );
739 929 $width = $_get_size['width'];
740 930 $height = $_get_size['height'];
741 - if ( false === $width ) {
742 - $widht = 210; // default width for SVG placeholder.
931 + if ( false === $width || empty( $width ) ) {
932 + $width = 210; // default width for SVG placeholder.
743 933 }
744 - if ( false === $height ) {
745 - $heigth = $width / 3 * 2; // if no height, base it on width using the 3/2 aspect ratio.
934 + if ( false === $height || empty( $height ) ) {
935 + $height = $width / 3 * 2; // if no height, base it on width using the 3/2 aspect ratio.
746 936 }
747 937
748 938 // insert the actual lazyload stuff.
749 939 // see https://css-tricks.com/preventing-content-reflow-from-lazy-loaded-images/ for great read on why we're using empty svg's.
@@ -760,8 +950,10 @@
760 950
761 951 // add the noscript-tag from earlier.
762 952 $tag = $noscript_tag . $tag;
763 953 $tag = apply_filters( 'autoptimize_filter_imgopt_lazyloaded_img', $tag );
954 + } else {
955 + $tag = apply_filters( 'autoptimize_filter_imgopt_not_lazyloaded_img', $tag );
764 956 }
765 957
766 958 return $tag;
767 959 }
@@ -766,9 +958,9 @@
766 958 return $tag;
767 959 }
768 960
769 961 public function add_lazyload_js_footer() {
770 - if ( false === autoptimizeMain::should_buffer() ) {
962 + if ( false === autoptimizeMain::should_buffer() || autoptimizeMain::is_amp_markup( '' ) ) {
771 963 return;
772 964 }
773 965
774 966 // The JS will by default be excluded form autoptimization but this can be changed with a filter.
@@ -776,28 +968,62 @@
776 968 if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_js_noptimize', true ) ) {
777 969 $noptimize_flag = ' data-noptimize="1"';
778 970 }
779 971
780 - $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js?ao_version=' . AUTOPTIMIZE_PLUGIN_VERSION, __FILE__ );
972 + $_extra = autoptimizeOptionWrapper::get_option( 'autoptimize_extra_settings', '' );
973 + if ( is_array( $_extra ) && array_key_exists( 'autoptimize_extra_checkbox_field_0', $_extra ) && ! empty( $_extra['autoptimize_extra_checkbox_field_0'] ) ) {
974 + // if "remove query strings" is active in "extra", then let's be consistant and not add one ourselves :-) ?
975 + $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js', __FILE__ );
976 + } else {
977 + $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js?ao_version=' . AUTOPTIMIZE_PLUGIN_VERSION, __FILE__ );
978 + }
979 +
781 980 $cdn_url = $this->get_cdn_url();
782 981 if ( ! empty( $cdn_url ) ) {
982 + $cdn_url = rtrim( $cdn_url, '/' );
783 983 $lazysizes_js = str_replace( AUTOPTIMIZE_WP_SITE_URL, $cdn_url, $lazysizes_js );
784 984 }
785 985
986 + $type_js = '';
987 + if ( apply_filters( 'autoptimize_filter_cssjs_addtype', false ) ) {
988 + $type_js = ' type="text/javascript"';
989 + }
990 +
786 991 // Adds lazyload CSS & JS to footer, using echo because wp_enqueue_script seems not to support pushing attributes (async).
787 - 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>' );
788 - echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' );
789 - echo apply_filters( 'autoptimize_filter_imgopt_lazyload_js', '<script async' . $noptimize_flag . ' src=\'' . $lazysizes_js . '\'></script>' );
992 + echo apply_filters( 'autoptimize_filter_imgopt_lazyload_cssoutput', '<noscript><style>.lazyload{display:none;}</style></noscript>' );
993 + echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $type_js . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' );
994 + echo apply_filters( 'autoptimize_filter_imgopt_lazyload_js', '<script async' . $type_js . $noptimize_flag . ' src=\'' . $lazysizes_js . '\'></script>' );
995 + }
790 996
791 - // And add webp detection and loading JS.
792 - if ( $this->should_webp() ) {
793 - $_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);";
794 - $_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,'))})});";
795 - echo apply_filters( 'autoptimize_filter_imgopt_webp_js', '<script' . $noptimize_flag . '>' . $_webp_detect . $_webp_load . '</script>' );
997 + public static function create_img_preload_tag( $tag ) {
998 + if ( false === apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
999 + return '';
796 1000 }
1001 +
1002 + // clean up; remove tabs/ linebreaks/ spaces.
1003 + $tag = preg_replace( '/\s+/', ' ', $tag );
1004 +
1005 + // remove noscript.
1006 + if ( false !== strpos( $tag, '<noscript' ) ) {
1007 + $tag = preg_replace( '/<noscript.*<\/noscript>/mU', '', $tag );
1008 + }
1009 +
1010 + // rewrite img tag to link preload img.
1011 + $_from = array( '<img ', ' src=', ' sizes=', ' srcset=' );
1012 + $_to = array( '<link rel="preload" as="image" ', ' href=', ' imagesizes=', ' imagesrcset=' );
1013 + $tag = str_replace( $_from, $_to, $tag );
1014 +
1015 + // and remove title, alt, class and id.
1016 + $tag = preg_replace( '/ ((?:title|alt|class|id|loading|fetchpriority|decoding|data-no-lazy)=".*")/Um', '', $tag );
1017 + if ( str_replace( array( ' title=', ' class=', ' alt=', ' id=', ' fetchpriority=', ' decoding=', ' data-no-lazy=' ), '', $tag ) !== $tag ) {
1018 + // 2nd regex pass if still title/ class/ alt in case single quotes were used iso doubles.
1019 + $tag = preg_replace( '/ ((?:title|alt|class|id|loading|fetchpriority|decoding|data-no-lazy)=\'.*\')/Um', '', $tag );
1020 + }
1021 +
1022 + return $tag;
797 1023 }
798 1024
799 - public function get_cdn_url() {
1025 + public static function get_cdn_url() {
800 1026 // getting CDN url here to avoid having to make bigger changes to autoptimizeBase.
801 1027 static $cdn_url = null;
802 1028
803 1029 if ( null === $cdn_url ) {
@@ -837,9 +1063,9 @@
837 1063 public function inject_classes_in_tag( $tag, $target_class ) {
838 1064 if ( strpos( $tag, 'class=' ) !== false ) {
839 1065 $tag = preg_replace( '/(\sclass\s?=\s?("|\'))/', '$1' . $target_class, $tag );
840 1066 } else {
841 - $tag = preg_replace( '/(<img)\s/', '$1 class="' . trim( $target_class ) . '" ', $tag );
1067 + $tag = preg_replace( '/(<[a-zA-Z]*)\s/', '$1 class="' . trim( $target_class ) . '" ', $tag );
842 1068 }
843 1069
844 1070 return $tag;
845 1071 }
@@ -847,21 +1073,21 @@
847 1073 public function get_default_lazyload_placeholder( $imgopt_w, $imgopt_h ) {
848 1074 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';
849 1075 }
850 1076
851 - public function should_webp() {
852 - static $webp_return = null;
1077 + public function should_ngimg() {
1078 + static $ngimg_return = null;
853 1079
854 - if ( is_null( $webp_return ) ) {
855 - // webp only works if imgopt and lazyload are also active.
856 - if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) && $this->imgopt_active() ) {
857 - $webp_return = true;
1080 + if ( is_null( $ngimg_return ) ) {
1081 + // nextgen img only works if imgopt is active.
1082 + if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && $this->imgopt_active() ) {
1083 + $ngimg_return = true;
858 1084 } else {
859 - $webp_return = false;
1085 + $ngimg_return = false;
860 1086 }
861 1087 }
862 1088
863 - return $webp_return;
1089 + return $ngimg_return;
864 1090 }
865 1091
866 1092 public function process_picture_tag( $in, $imgopt = false, $lazy = false ) {
867 1093 // check if "<picture" is present and if filter allows us to process <picture>.
@@ -880,9 +1106,9 @@
880 1106 foreach ( $_sources as $_source ) {
881 1107 $_picture_replacement = $_source[0];
882 1108
883 1109 // should we optimize the image?
884 - if ( $imgopt && $this->can_optimize_image( $_source[1] ) ) {
1110 + if ( $imgopt && $this->can_optimize_image( $_source[1], $_picture[0] ) ) {
885 1111 $_picture_replacement = str_replace( $_source[1], $this->build_imgopt_url( $_source[1] ), $_picture_replacement );
886 1112 }
887 1113 // should we lazy-load?
888 1114 if ( $lazy && $this->should_lazyload() && str_ireplace( $_exclusions, '', $_picture_replacement ) === $_picture_replacement ) {
@@ -901,9 +1127,9 @@
901 1127
902 1128 public function process_bgimage( $in ) {
903 1129 if ( strpos( $in, 'background-image:' ) !== false && apply_filters( 'autoptimize_filter_imgopt_lazyload_backgroundimages', true ) ) {
904 1130 $out = preg_replace_callback(
905 - '/(<(?:article|aside|body|div|footer|header|p|section|table)[^>]*)\sstyle=(?:"|\')[^<>]*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)[^>]*/',
1131 + '/(<(?:article|aside|body|div|footer|header|p|section|span|table)[^>]*)\sstyle=(?:"|\')[^<>]*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)[^>]*/',
906 1132 array( $this, 'lazyload_bgimg_callback' ),
907 1133 $in
908 1134 );
909 1135 return $out;
@@ -915,13 +1141,17 @@
915 1141 if ( str_ireplace( $this->get_lazyload_exclusions(), '', $matches[0] ) === $matches[0] ) {
916 1142 // get placeholder & lazyload class strings.
917 1143 $placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( 500, 300 ) );
918 1144 $lazyload_class = apply_filters( 'autoptimize_filter_imgopt_lazyload_class', 'lazyload' );
1145 + // remove quotes from url() to be able to replace in next step.
1146 + $out = str_replace( array( "url('" . $matches[2] . "')", 'url("' . $matches[2] . '")' ), 'url(' . $matches[2] . ')', $matches[0] );
919 1147 // replace background-image URL with SVG placeholder.
920 - $out = str_replace( $matches[2], $placeholder, $matches[0] );
1148 + $out = str_replace( 'url(' . $matches[2], 'url(' . $placeholder, $out );
1149 + // sanitize bgimg src for quote sillyness.
1150 + $bgimg_src = $this->fix_silly_bgimg_quotes( $matches[2] );
921 1151 // add data-bg attribute with real background-image URL for lazyload to pick up.
922 - $out = str_replace( $matches[1], $matches[1] . ' data-bg="' . trim( str_replace( "\r\n", '', $matches[2] ) ) . '"', $out );
923 - // add lazyload class to tag.
1152 + $out = str_replace( $matches[1], $matches[1] . ' data-bg="' . $bgimg_src . '"', $out );
1153 + // and finally add lazyload class to tag.
924 1154 $out = $this->inject_classes_in_tag( $out, "$lazyload_class " );
925 1155 return $out;
926 1156 }
927 1157 return $matches[0];
@@ -926,12 +1156,19 @@
926 1156 }
927 1157 return $matches[0];
928 1158 }
929 1159
1160 + public function fix_silly_bgimg_quotes( $tag_in ) {
1161 + // some themes/ pagebuilders wrap backgroundimages in HTML-encoded quotes (or linebreaks) which breaks imgopt/ lazyloading, this removes them.
1162 + return trim( str_replace( array( "\r\n", '&quot;', '&#034;', '&apos;', '&#039;' ), '', $tag_in ) );
1163 + }
1164 +
930 1165 public function maybe_fix_missing_quotes( $tag_in ) {
931 - // W3TC's Minify_HTML class removes quotes around attribute value, this re-adds them for the class attribute only so we can safely add the lazyload class.
1166 + // 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.
932 1167 if ( file_exists( WP_PLUGIN_DIR . '/w3-total-cache/w3-total-cache.php' ) && class_exists( 'Minify_HTML' ) && apply_filters( 'autoptimize_filter_imgopt_fixquotes', true ) ) {
933 - return preg_replace( '/class\s?=([^("|\')]*)(\s|>)/U', 'class=\'$1\'$2', $tag_in );
1168 + $tag_out = preg_replace( '/class\s?=([^("|\')]*)(\s|>)/U', 'class=\'$1\'$2', $tag_in );
1169 + $tag_out = preg_replace( '/\s(width|height)=(?:"|\')?([^\s"\'>]*)(?:"|\')?/', ' $1=\'$2\'', $tag_out );
1170 + return $tag_out;
934 1171 } else {
935 1172 return $tag_in;
936 1173 }
937 1174 }
@@ -943,9 +1180,9 @@
943 1180 {
944 1181 // no acces if multisite and not network admin and no site config allowed.
945 1182 if ( autoptimizeConfig::should_show_menu_tabs() ) {
946 1183 add_submenu_page(
947 - null,
1184 + '',
948 1185 'autoptimize_imgopt',
949 1186 'autoptimize_imgopt',
950 1187 'manage_options',
951 1188 'autoptimize_imgopt',
@@ -957,9 +1194,9 @@
957 1194
958 1195 public function add_imgopt_tab( $in )
959 1196 {
960 1197 if ( autoptimizeConfig::should_show_menu_tabs() ) {
961 - $in = array_merge( $in, array( 'autoptimize_imgopt' => __( 'Images', 'autoptimize' ) ) );
1198 + $in = array_merge( $in, array( 'autoptimize_imgopt' => apply_filters( 'autoptimize_filter_imgopt_tab_text', __( 'Images', 'autoptimize' ) ) ) );
962 1199 }
963 1200
964 1201 return $in;
965 1202 }
@@ -965,11 +1202,14 @@
965 1202 }
966 1203
967 1204 public function imgopt_options_page()
968 1205 {
1206 + // phpcs:disable Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace
1207 + // phpcs:disable Generic.Formatting.DisallowMultipleStatements.SameLine
1208 +
969 1209 // Check querystring for "refreshCacheChecker" and call cachechecker if so.
970 1210 if ( array_key_exists( 'refreshImgProvStats', $_GET ) && 1 == $_GET['refreshImgProvStats'] ) {
971 - $this->query_img_provider_stats();
1211 + $this->query_img_provider_stats( true );
972 1212 }
973 1213
974 1214 $options = $this->fetch_options();
975 1215 $sp_url_suffix = $this->get_service_url_suffix();
@@ -980,10 +1220,17 @@
980 1220 #autoptimize_imgopt_descr{font-size: 120%;}
981 1221 </style>
982 1222 <script>document.title = "Autoptimize: <?php _e( 'Images', 'autoptimize' ); ?> " + document.title;</script>
983 1223 <div class="wrap">
984 - <h1><?php _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
1224 + <h1><?php apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? _e( 'Autoptimize Pro Settings', 'autoptimize' ) : _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
985 1225 <?php echo autoptimizeConfig::ao_admin_tabs(); ?>
1226 + <?php if ( autoptimizeUtils::is_local_server() ) { ?>
1227 + <div class="notice-warning notice"><p>
1228 + <?php
1229 + echo __( 'The image optimization service does not work on locally hosted sites or when the server is on a private network.', 'autoptimize' );
1230 + ?>
1231 + </p></div>
1232 + <?php } ?>
986 1233 <?php if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) { ?>
987 1234 <div class="notice-warning notice"><p>
988 1235 <?php
989 1236 // translators: "Autoptimize support forum" will appear in a "a href".
@@ -1008,14 +1255,14 @@
1008 1255 <?php } ?>
1009 1256 <form id='ao_settings_form' action='<?php echo admin_url( 'options.php' ); ?>' method='post'>
1010 1257 <?php settings_fields( 'autoptimize_imgopt_settings' ); ?>
1011 1258 <h2><?php _e( 'Image optimization', 'autoptimize' ); ?></h2>
1012 - <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>
1259 + <span id='autoptimize_imgopt_descr'><?php echo apply_filters( 'autoptimize_filter_imgopt_intro_copy', __( 'Make your site significantly faster by simply ticking a few boxes and start serving CDN powered, optimized images in next-get formats like WebP and AVIF! No additional plugins or services needed.', 'autoptimize' ) ); ?></span>
1013 1260 <table class="form-table">
1014 1261 <tr>
1015 - <th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th>
1262 + <th scope="row"><?php _e( 'Image optimization & CDN', 'autoptimize' ); ?></th>
1016 1263 <td>
1017 - <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>
1264 + <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', __( 'On-the-fly image optimization and fast delivery via the Shortpixel global CDN.', 'autoptimize' ) ); ?></label>
1018 1265 <?php
1019 1266 // show shortpixel status.
1020 1267 $_notice = autoptimizeImages::instance()->get_imgopt_status_notice();
1021 1268 if ( $_notice ) {
@@ -1036,26 +1283,32 @@
1036 1283 }
1037 1284 echo apply_filters( 'autoptimize_filter_imgopt_settings_status', '<p><strong><span style="color:' . $_notice_color . ';">' . __( 'Shortpixel status: ', 'autoptimize' ) . '</span></strong>' . $_notice['notice'] . '</p>' );
1038 1285 } else {
1039 1286 // translators: link points to shortpixel.
1040 - $upsell_msg_1 = '<p>' . sprintf( __( 'Get more Google love and improve your website\'s loading speed by having your publicly available 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>' );
1287 + $upsell_msg_1 = '<p>' . sprintf( __( 'Get more Google love by speeding up your website. Start serving on-the-fly optimized images (also in the "next-gen" <strong>WebP</strong> and <strong>AVIF</strong> image formats) 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://autoptimize.shortpixel.com/" target="_blank">', '</a>', '<a href="https://help.shortpixel.com/article/62-where-does-the-cdn-has-pops" target="_blank">' );
1041 1288 if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] ) {
1042 1289 $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' );
1043 1290 } else {
1044 - // translators: link points to shortpixel.
1045 - $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>' );
1291 + // translators: 1st link points to autoptimize.com.pro, 2nd to shortpixel.
1292 + $upsell_msg_2 = sprintf( __( 'For <strong>unlimited image optimizations %1$sbuy Autoptimize Pro%2$s</strong> 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://autoptimize.shortpixel.com/' . $sp_url_suffix . '" target="_blank">', '</a>' );
1046 1293 }
1047 - echo apply_filters( 'autoptimize_imgopt_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
1294 + echo apply_filters( 'autoptimize_filter_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
1048 1295 }
1049 1296 // translators: link points to shortpixel FAQ.
1050 - $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>' );
1051 - $faqcopy = $faqcopy . ' ' . __( 'Only works for sites/ images that are publicly available.', 'autoptimize' );
1297 + $faqcopy = sprintf( __( '<strong>Questions</strong>? 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>' );
1298 + $faqcopy = $faqcopy . ' ' . __( 'Only works for websites and images that are publicly available.', 'autoptimize' );
1052 1299 // translators: links points to shortpixel TOS & Privacy Policy.
1053 - $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>' );
1054 - echo apply_filters( 'autoptimize_imgopt_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
1300 + $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/privacy' . $sp_url_suffix . '" target="_blank">', '</a>' );
1301 + echo apply_filters( 'autoptimize_filter_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
1055 1302 ?>
1056 1303 </td>
1057 1304 </tr>
1305 + <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"'; } ?>>
1306 + <th scope="row"><?php _e( 'Optimization exclusions', 'autoptimize' ); ?></th>
1307 + <td>
1308 + <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 _e( 'Comma-separated list of image classes or filenames that should not be optimized.', 'autoptimize' ); ?></label>
1309 + </td>
1310 + </tr>
1058 1311 <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"'; } ?>>
1059 1312 <th scope="row"><?php _e( 'Image Optimization quality', 'autoptimize' ); ?></th>
1060 1313 <td>
1061 1314 <label>
@@ -1077,19 +1330,29 @@
1077 1330 </label>
1078 1331 <p>
1079 1332 <?php
1080 1333 // translators: link points to shortpixel image test page.
1081 - 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>' ) );
1334 + echo apply_filters( 'autoptimize_filter_imgopt_quality_copy', sprintf( __( 'You can %1$stest compression levels here%2$s.', 'autoptimize' ), '<a href="https://shortpixel.com/online-image-compression' . $sp_url_suffix . '" target="_blank">', '</a>' ) );
1082 1335 ?>
1083 1336 </p>
1084 1337 </td>
1085 1338 </tr>
1086 - <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"'; } ?>>
1087 - <th scope="row"><?php _e( 'Load WebP in supported browsers?', 'autoptimize' ); ?></th>
1088 - <td>
1089 - <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>
1090 - </td>
1091 - </tr>
1339 + <?php
1340 + if ( apply_filters( 'autoptimize_filter_imgopt_settings_show_avif', true ) ) {
1341 + ?>
1342 + <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"'; } ?>>
1343 + <th scope="row"><?php _e( 'Load AVIF in supported browsers?', 'autoptimize' ); ?></th>
1344 + <td>
1345 + <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'><?php _e( 'Automatically serve AVIF image format to any browser that supports it.', 'autoptimize' ); ?></label>
1346 + </td>
1347 + </tr>
1348 + <?php
1349 + } else {
1350 + ?>
1351 + <input type='hidden' id='autoptimize_imgopt_ngimg_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' value='0'>
1352 + <?php
1353 + }
1354 + ?>
1092 1355 <tr>
1093 1356 <th scope="row"><?php _e( 'Lazy-load images?', 'autoptimize' ); ?></th>
1094 1357 <td>
1095 1358 <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>
@@ -1094,14 +1357,20 @@
1094 1357 <td>
1095 1358 <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>
1096 1359 </td>
1097 1360 </tr>
1098 - <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"'; } ?>>
1361 + <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"'; } ?>>
1099 1362 <th scope="row"><?php _e( 'Lazy-load exclusions', 'autoptimize' ); ?></th>
1100 1363 <td>
1101 - <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>
1364 + <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 _e( 'Comma-separated list of to be excluded image classes or filenames.', 'autoptimize' ); ?></label>
1102 1365 </td>
1103 1366 </tr>
1367 + <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"'; } ?>>
1368 + <th scope="row"><?php _e( 'Lazy-load from nth image', 'autoptimize' ); ?></th>
1369 + <td>
1370 + <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 _e( 'Don\'t lazyload the first X images, \'1\' lazyloads all.', 'autoptimize' ); ?></label>
1371 + </td>
1372 + </tr>
1104 1373 </table>
1105 1374 <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" /></p>
1106 1375 </form>
1107 1376 <script>
@@ -1108,26 +1377,21 @@
1108 1377 jQuery(document).ready(function() {
1109 1378 jQuery("#autoptimize_imgopt_checkbox").change(function() {
1110 1379 if (this.checked) {
1111 1380 jQuery("#autoptimize_imgopt_quality").show("slow");
1112 - jQuery("#autoptimize_imgopt_webp").show("slow");
1381 + jQuery("#autoptimize_imgopt_ngimg").show("slow");
1382 + jQuery("#autoptimize_imgopt_optimization_exclusions").show("slow");
1113 1383 } else {
1114 1384 jQuery("#autoptimize_imgopt_quality").hide("slow");
1115 - jQuery("#autoptimize_imgopt_webp").hide("slow");
1385 + jQuery("#autoptimize_imgopt_ngimg").hide("slow");
1386 + jQuery("#autoptimize_imgopt_optimization_exclusions").hide("slow");
1116 1387 }
1117 1388 });
1118 - jQuery("#autoptimize_imgopt_webp_checkbox").change(function() {
1119 - if (this.checked) {
1120 - jQuery("#autoptimize_imgopt_lazyload_checkbox")[0].checked = true;
1121 - jQuery("#autoptimize_imgopt_lazyload_exclusions").show("slow");
1122 - }
1123 - });
1124 1389 jQuery("#autoptimize_imgopt_lazyload_checkbox").change(function() {
1125 1390 if (this.checked) {
1126 - jQuery("#autoptimize_imgopt_lazyload_exclusions").show("slow");
1391 + jQuery(".autoptimize_lazyload_child").show("slow");
1127 1392 } else {
1128 - jQuery("#autoptimize_imgopt_lazyload_exclusions").hide("slow");
1129 - jQuery("#autoptimize_imgopt_webp_checkbox")[0].checked = false;
1393 + jQuery(".autoptimize_lazyload_child").hide("slow");
1130 1394 }
1131 1395 });
1132 1396 });
1133 1397 </script>
@@ -1137,13 +1401,13 @@
1137 1401 /**
1138 1402 * Ïmg opt status as used on dashboard.
1139 1403 */
1140 1404 public function get_imgopt_status_notice() {
1141 - if ( $this->imgopt_active() ) {
1405 + if ( $this->imgopt_active() && apply_filters( 'autoptimize_filter_imgopt_status_shortpixel', true ) ) {
1142 1406 $_imgopt_notice = '';
1143 1407 $_stat = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' );
1144 1408 $_site_host = AUTOPTIMIZE_SITE_DOMAIN;
1145 - $_imgopt_upsell = 'https://shortpixel.com/aospai/af/GWRGFLW109483/' . $_site_host;
1409 + $_imgopt_upsell = 'https://autoptimize.shortpixel.com/' . $_site_host;
1146 1410 $_imgopt_assoc = 'https://shortpixel.helpscoutdocs.com/article/94-how-to-associate-a-domain-to-my-account';
1147 1411 $_imgopt_unreach = 'https://shortpixel.helpscoutdocs.com/article/148-why-are-my-images-redirected-from-cdn-shortpixel-ai';
1148 1412
1149 1413 if ( is_array( $_stat ) ) {
@@ -1148,19 +1412,19 @@
1148 1412
1149 1413 if ( is_array( $_stat ) ) {
1150 1414 if ( 1 == $_stat['Status'] ) {
1151 1415 // translators: "add more credits" will appear in a "a href".
1152 - $_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>' );
1416 + $_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 <strong>or consider using %3$sAutoptimize Pro%2$s which comes with (nearly) unlimited image optimization</strong> 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">' );
1153 1417 } elseif ( -1 == $_stat['Status'] || -2 == $_stat['Status'] ) {
1154 1418 // translators: "add more credits" will appear in a "a href".
1155 - $_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>' );
1419 + $_imgopt_notice = sprintf( __( '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 <strong>or consider using %3$sAutoptimize Pro%2$s which comes with (nearly) unlimited image optimization</strong> 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">' );
1156 1420 // translators: "associate your domain" will appear in a "a href".
1157 - $_imgopt_notice = $_imgopt_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="' . $_imgopt_assoc . '" target="_blank">', '</a>' );
1421 + $_imgopt_notice = $_imgopt_notice . ' ' . sprintf( __( '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>' );
1158 1422 } elseif ( -3 == $_stat['Status'] ) {
1159 1423 // translators: "check the documentation here" will appear in a "a href".
1160 1424 $_imgopt_notice = sprintf( __( '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>' );
1161 1425 } else {
1162 - $_imgopt_upsell = 'https://shortpixel.com/g/af/GWRGFLW109483';
1426 + $_imgopt_upsell = 'https://autoptimize.shortpixel.com/';
1163 1427 // translators: "log in to check your account" will appear in a "a href".
1164 1428 $_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>' );
1165 1429 }
1166 1430
@@ -1165,12 +1429,15 @@
1165 1429 }
1166 1430
1167 1431 // add info on freshness + refresh link if status is not 2 (good shape).
1168 1432 if ( 2 != $_stat['Status'] ) {
1169 - $_imgopt_stats_refresh_url = add_query_arg( array(
1170 - 'page' => 'autoptimize_imgopt',
1171 - 'refreshImgProvStats' => '1',
1172 - ), admin_url( 'options-general.php' ) );
1433 + $_imgopt_stats_refresh_url = add_query_arg(
1434 + array(
1435 + 'page' => 'autoptimize_imgopt',
1436 + 'refreshImgProvStats' => '1',
1437 + ),
1438 + admin_url( 'options-general.php' )
1439 + );
1173 1440 if ( $_stat && array_key_exists( 'timestamp', $_stat ) && ! empty( $_stat['timestamp'] ) ) {
1174 1441 $_imgopt_stats_last_run = __( 'based on status at ', 'autoptimize' ) . date_i18n( autoptimizeOptionWrapper::get_option( 'time_format' ), $_stat['timestamp'] );
1175 1442 } else {
1176 1443 $_imgopt_stats_last_run = __( 'based on previously fetched data', 'autoptimize' );
@@ -1176,9 +1443,9 @@
1176 1443 $_imgopt_stats_last_run = __( 'based on previously fetched data', 'autoptimize' );
1177 1444 }
1178 1445 $_imgopt_notice .= ' (' . $_imgopt_stats_last_run . ', ';
1179 1446 // translators: "here to refresh" links to the Autoptimize Extra page and forces a refresh of the img opt stats.
1180 - $_imgopt_notice .= sprintf( __( 'click %1$shere to refresh%2$s', 'autoptimize' ), '<a href="' . $_imgopt_stats_refresh_url . '">', '</a>).' );
1447 + $_imgopt_notice .= sprintf( __( 'you can click %1$shere to refresh your quota status%2$s', 'autoptimize' ), '<a href="' . $_imgopt_stats_refresh_url . '">', '</a>).' );
1181 1448 }
1182 1449
1183 1450 // and make the full notice filterable.
1184 1451 $_imgopt_notice = apply_filters( 'autoptimize_filter_imgopt_notice', $_imgopt_notice );
@@ -1199,18 +1466,24 @@
1199 1466 }
1200 1467
1201 1468 /**
1202 1469 * Get img provider stats (used to display notice).
1470 + *
1471 + * @param bool $_refresh Should the stats be forcefully refreshed or not.
1203 1472 */
1204 - public function query_img_provider_stats() {
1205 - if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_1'] ) ) {
1473 + public function query_img_provider_stats( $_refresh = false ) {
1474 + if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_1'] ) && apply_filters( 'autoptimize_filter_imgopt_status_shortpixel', true ) ) {
1206 1475 $url = '';
1207 - $endpoint = $this->get_imgopt_host() . 'read-domain/';
1476 + $stat_dom = 'https://no-cdn.shortpixel.ai/';
1477 + $endpoint = $stat_dom . 'read-domain/';
1208 1478 $domain = AUTOPTIMIZE_SITE_DOMAIN;
1209 1479
1210 1480 // make sure parse_url result makes sense, keeping $url empty if not.
1211 1481 if ( $domain && ! empty( $domain ) ) {
1212 1482 $url = $endpoint . $domain;
1483 + if ( true === $_refresh ) {
1484 + $url = $url . '/refresh';
1485 + }
1213 1486 }
1214 1487
1215 1488 $url = apply_filters(
1216 1489 'autoptimize_filter_imgopt_stat_url',
@@ -1247,9 +1520,13 @@
1247 1520 {
1248 1521 static $launch_status = null;
1249 1522
1250 1523 if ( null === $launch_status ) {
1251 - $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
1524 + $avail_imgopt = '';
1525 + if ( is_array( $this->options ) && array_key_exists( 'availabilities', $this->options ) && is_array( $this->options['availabilities'] ) && array_key_exists( 'extra_imgopt', $this->options['availabilities'] ) ) {
1526 + $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
1527 + }
1528 +
1252 1529 $magic_number = intval( substr( md5( parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ), 0, 3 ), 16 );
1253 1530 $has_launched = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_launched', '' );
1254 1531 $launch_status = false;
1255 1532 if ( $has_launched || ( is_array( $avail_imgopt ) && array_key_exists( 'launch-threshold', $avail_imgopt ) && $magic_number < $avail_imgopt['launch-threshold'] ) ) {