PluginProbe
Autoptimize / 3.0.3
Autoptimize v3.0.3
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 +251 -83 2.7.73.0.3 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,20 @@
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( 'extra_imgopt' => array( 'status' => 'up', 'hosts' => array( '1' => 'https://sp-ao.shortpixel.ai/' ) ), 'critcss' => array( 'status' => 'up' ) );
65 + $value['availabilities'] = $_mock_settings;
66 + }
56 67 }
57 68
58 69 return $value;
59 70 }
@@ -112,9 +123,11 @@
112 123 if ( ! $this->should_run() ) {
113 124 if ( $this->should_lazyload() ) {
114 125 add_filter(
115 126 'wp_lazy_loading_enabled',
116 - '__return_false'
127 + array( $this, 'should_disable_core_lazyload' ),
128 + 10,
129 + 3
117 130 );
118 131 add_filter(
119 132 'autoptimize_html_after_minify',
120 133 array( $this, 'filter_lazyload_images' ),
@@ -164,9 +177,11 @@
164 177
165 178 if ( $this->should_lazyload() ) {
166 179 add_filter(
167 180 'wp_lazy_loading_enabled',
168 - '__return_false'
181 + array( $this, 'should_disable_core_lazyload' ),
182 + 10,
183 + 3
169 184 );
170 185 add_action(
171 186 'wp_footer',
172 187 array( $this, 'add_lazyload_js_footer' ),
@@ -176,8 +191,20 @@
176 191 }
177 192 }
178 193
179 194 /**
195 + * Disables core's native lazyload for images, not for iframes.
196 + *
197 + * @return bool
198 + */
199 + public function should_disable_core_lazyload( $flag = true, $tag = '', $context = '' ) {
200 + if ( 'img' === $tag ) {
201 + return false;
202 + }
203 + return $flag;
204 + }
205 +
206 + /**
180 207 * Basic checks before we can run.
181 208 *
182 209 * @return bool
183 210 */
@@ -209,9 +236,9 @@
209 236 {
210 237 static $imgopt_host = null;
211 238
212 239 if ( null === $imgopt_host ) {
213 - $imgopt_host = 'https://cdn.shortpixel.ai/';
240 + $imgopt_host = 'https://sp-ao.shortpixel.ai/';
214 241 $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
215 242 if ( ! empty( $avail_imgopt ) && array_key_exists( 'hosts', $avail_imgopt ) && is_array( $avail_imgopt['hosts'] ) ) {
216 243 $imgopt_host = array_rand( array_flip( $avail_imgopt['hosts'] ) );
217 244 }
@@ -229,9 +256,9 @@
229 256 }
230 257
231 258 public static function get_service_url_suffix()
232 259 {
233 - $suffix = '/af/GWRGFLW109483/' . AUTOPTIMIZE_SITE_DOMAIN;
260 + $suffix = '/af/SPZURYE109483/' . AUTOPTIMIZE_SITE_DOMAIN;
234 261
235 262 return $suffix;
236 263 }
237 264
@@ -344,11 +371,9 @@
344 371 // Default to (the trimmed version of) what was given to us.
345 372 $result = trim( $in );
346 373
347 374 // Some silly plugins wrap background images in html-encoded quotes, so remove those from the img url.
348 - if ( strpos( $result, '"' ) !== false ) {
349 - $result = str_replace( '"', '', $result );
350 - }
375 + $result = $this->fix_silly_bgimg_quotes( $result );
351 376
352 377 if ( autoptimizeUtils::is_protocol_relative( $result ) ) {
353 378 $result = $parsed_site_url['scheme'] . ':' . $result;
354 379 } elseif ( 0 === strpos( $result, '/' ) ) {
@@ -353,12 +378,18 @@
353 378 $result = $parsed_site_url['scheme'] . ':' . $result;
354 379 } elseif ( 0 === strpos( $result, '/' ) ) {
355 380 // Root-relative...
356 381 $result = $parsed_site_url['scheme'] . '://' . $parsed_site_url['host'] . $result;
357 - } elseif ( ! empty( $cdn_domain ) && strpos( $result, $cdn_domain ) !== 0 ) {
382 + } elseif ( ! empty( $cdn_domain ) && false === strpos( $this->get_imgopt_host(), $cdn_domain ) && strpos( $result, $cdn_domain ) !== 0 ) {
383 + // remove CDN except if it is the image optimization one.
358 384 $result = str_replace( $cdn_domain, $parsed_site_url['host'], $result );
359 385 }
360 386
387 + // filter (default off) to remove QS from image URL's to avoid eating away optimization credits.
388 + if ( apply_filters( 'autoptimize_filter_imgopt_no_querystring', false ) && strpos( $result, '?' ) !== false ) {
389 + $result = strtok( $result, '?' );
390 + }
391 +
361 392 $result = apply_filters( 'autoptimize_filter_imgopt_normalized_url', $result );
362 393
363 394 // Store in cache.
364 395 $cache[ $in ] = $result;
@@ -370,9 +401,9 @@
370 401 public function filter_optimize_css_images( $in )
371 402 {
372 403 $in = $this->normalize_img_url( $in );
373 404
374 - if ( $this->can_optimize_image( $in ) ) {
405 + if ( $this->can_optimize_image( $in ) && false === strpos( $in, $this->get_imgopt_host() ) ) {
375 406 return $this->build_imgopt_url( $in, '', '' );
376 407 } else {
377 408 return $in;
378 409 }
@@ -385,9 +416,15 @@
385 416 if ( null === $imgopt_base_url ) {
386 417 $imgopt_host = $this->get_imgopt_host();
387 418 $quality = $this->get_img_quality_string();
388 419 $ret_val = apply_filters( 'autoptimize_filter_imgopt_wait', 'ret_img' ); // values: ret_wait, ret_img, ret_json, ret_blank.
389 - $imgopt_base_url = $imgopt_host . 'client/' . $quality . ',' . $ret_val;
420 + if ( $this->should_ngimg() ) {
421 + $sp_to_string = 'to_auto';
422 + } else {
423 + $sp_to_string = 'to_webp';
424 + }
425 + $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).
426 + $imgopt_base_url = $imgopt_host . 'client/' . $sp_to_string . ',' . $quality . ',' . $ret_val;
390 427 $imgopt_base_url = apply_filters( 'autoptimize_filter_imgopt_base_url', $imgopt_base_url );
391 428 }
392 429
393 430 return $imgopt_base_url;
@@ -392,9 +429,9 @@
392 429
393 430 return $imgopt_base_url;
394 431 }
395 432
396 - private function can_optimize_image( $url, $tag = '' )
433 + private function can_optimize_image( $url, $tag = '', $testing = false )
397 434 {
398 435 static $cdn_url = null;
399 436 static $nopti_images = null;
400 437
@@ -404,10 +441,13 @@
404 441 autoptimizeOptionWrapper::get_option( 'autoptimize_cdn_url', '' )
405 442 );
406 443 }
407 444
408 - if ( null === $nopti_images ) {
409 - $nopti_images = apply_filters( 'autoptimize_filter_imgopt_noptimize', '' );
445 + if ( null === $nopti_images || $testing ) {
446 + if ( is_array( $this->options ) && array_key_exists( 'autoptimize_imgopt_text_field_6', $this->options ) ) {
447 + $nopti_images = $this->options['autoptimize_imgopt_text_field_6'];
448 + }
449 + $nopti_images = apply_filters( 'autoptimize_filter_imgopt_noptimize', $nopti_images );
410 450 }
411 451
412 452 $site_host = AUTOPTIMIZE_SITE_DOMAIN;
413 453 $url = $this->normalize_img_url( $url );
@@ -418,9 +458,9 @@
418 458 } elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host ) {
419 459 return false;
420 460 } elseif ( strpos( $url, '.php' ) !== false ) {
421 461 return false;
422 - } elseif ( str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg', '.webp' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) {
462 + } elseif ( str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg', '.webp', '.avif' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) {
423 463 // fixme: better check against end of string.
424 464 return false;
425 465 } elseif ( ! empty( $nopti_images ) ) {
426 466 $nopti_images_array = array_filter( array_map( 'trim', explode( ',', $nopti_images ) ) );
@@ -456,9 +496,15 @@
456 496 if ( $filtered_url !== $orig_url ) {
457 497 return $filtered_url;
458 498 }
459 499
460 - $orig_url = $this->normalize_img_url( $orig_url );
500 + $normalized_url = $this->normalize_img_url( $orig_url );
501 +
502 + // 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.
503 + if ( apply_filters( 'autoptimize_filter_imgopt_check_normalized_url', true ) && ! preg_match( '/[^\x20-\x7e]/', $normalized_url ) && false === filter_var( $normalized_url, FILTER_VALIDATE_URL ) ) {
504 + return $orig_url;
505 + }
506 +
461 507 $imgopt_base_url = $this->get_imgopt_base_url();
462 508 $imgopt_size = '';
463 509
464 510 if ( $width && 0 !== $width ) {
@@ -468,9 +514,9 @@
468 514 if ( $height && 0 !== $height ) {
469 515 $imgopt_size .= ',h_' . $height;
470 516 }
471 517
472 - $url = $imgopt_base_url . $imgopt_size . '/' . $orig_url;
518 + $url = $imgopt_base_url . $imgopt_size . '/' . $normalized_url;
473 519
474 520 return $url;
475 521 }
476 522
@@ -498,12 +544,18 @@
498 544 } else {
499 545 $width = 180;
500 546 $height = 180;
501 547 }
502 - return $this->replace_img_callback( $matches, $width, $height );
548 +
549 + // make sure we're not trying to optimize a *.ico file
550 + if ( strpos( $matches[1], '.ico' ) === false ) {
551 + return $this->replace_img_callback( $matches, $width, $height );
552 + } else {
553 + return $matches[0];
554 + }
503 555 }
504 556
505 - public function filter_optimize_images( $in )
557 + public function filter_optimize_images( $in, $testing = false )
506 558 {
507 559 /*
508 560 * potential future functional improvements:
509 561 *
@@ -509,8 +561,9 @@
509 561 *
510 562 * filter for critical CSS.
511 563 */
512 564 $to_replace = array();
565 + $to_preload = '';
513 566
514 567 // hide noscript tags to avoid nesting noscript tags (as lazyloaded images add noscript).
515 568 if ( $this->should_lazyload() ) {
516 569 $in = autoptimizeBase::replace_contents_with_marker_if_exists(
@@ -520,11 +573,16 @@
520 573 $in
521 574 );
522 575 }
523 576
577 + // get img preloads as set in post metabox.
578 + $metabox_preloads = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) );
579 +
524 580 // extract img tags.
525 581 if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
526 582 foreach ( $matches[0] as $tag ) {
583 + $tag = apply_filters( 'autoptimize_filter_imgopt_tag_preopt' , $tag );
584 +
527 585 $orig_tag = $tag;
528 586 $imgopt_w = '';
529 587 $imgopt_h = '';
530 588
@@ -530,20 +588,22 @@
530 588
531 589 // first do (data-)srcsets.
532 590 if ( preg_match_all( '#srcset=("|\')(.*)("|\')#Usmi', $tag, $allsrcsets, PREG_SET_ORDER ) ) {
533 591 foreach ( $allsrcsets as $srcset ) {
534 - $srcset = $srcset[2];
535 - $srcsets = explode( ',', $srcset );
592 + $srcset = $srcset[2];
593 + $orig_srcset = $srcset;
594 + $srcsets = explode( ',', $srcset );
536 595 foreach ( $srcsets as $indiv_srcset ) {
537 596 $indiv_srcset_parts = explode( ' ', trim( $indiv_srcset ) );
538 597 if ( isset( $indiv_srcset_parts[1] ) && rtrim( $indiv_srcset_parts[1], 'w' ) !== $indiv_srcset_parts[1] ) {
539 598 $imgopt_w = rtrim( $indiv_srcset_parts[1], 'w' );
540 599 }
541 - if ( $this->can_optimize_image( $indiv_srcset_parts[0], $tag ) ) {
600 + if ( $this->can_optimize_image( $indiv_srcset_parts[0], $tag, $testing ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
542 601 $imgopt_url = $this->build_imgopt_url( $indiv_srcset_parts[0], $imgopt_w, '' );
543 - $tag = str_replace( $indiv_srcset_parts[0], $imgopt_url, $tag );
602 + $srcset = str_replace( $indiv_srcset_parts[0], $imgopt_url, $srcset );
544 603 }
545 604 }
605 + $tag = str_replace( $orig_srcset, $srcset, $tag );
546 606 }
547 607 }
548 608
549 609 // proceed with img src.
@@ -556,9 +616,9 @@
556 616 if ( preg_match_all( '#src=(?:"|\')(?!data)(.*)(?:"|\')#Usmi', $tag, $urls, PREG_SET_ORDER ) ) {
557 617 foreach ( $urls as $url ) {
558 618 $full_src_orig = $url[0];
559 619 $url = $url[1];
560 - if ( $this->can_optimize_image( $url, $full_src_orig ) ) {
620 + if ( $this->can_optimize_image( $url, $tag, $testing ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
561 621 $imgopt_url = $this->build_imgopt_url( $url, $imgopt_w, $imgopt_h );
562 622 $full_imgopt_src = str_replace( $url, $imgopt_url, $full_src_orig );
563 623 $tag = str_replace( $full_src_orig, $full_imgopt_src, $tag );
564 624 }
@@ -578,9 +638,9 @@
578 638
579 639 $_url = $this->normalize_img_url( $_url );
580 640
581 641 $placeholder = '';
582 - if ( $this->can_optimize_image( $_url, $tag ) && apply_filters( 'autoptimize_filter_imgopt_lazyload_dolqip', true ) ) {
642 + if ( $this->can_optimize_image( $_url, $tag ) && apply_filters( 'autoptimize_filter_imgopt_lazyload_dolqip', true, $_url ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
583 643 $lqip_w = '';
584 644 $lqip_h = '';
585 645 if ( isset( $imgopt_w ) && ! empty( $imgopt_w ) ) {
586 646 $lqip_w = ',w_' . $imgopt_w;
@@ -592,13 +652,25 @@
592 652 }
593 653 // then call add_lazyload-function with lpiq placeholder if set.
594 654 $tag = $this->add_lazyload( $tag, $placeholder );
595 655 }
656 +
657 + // add decoding="async" behind filter, not sure if I'll make it default true yet.
658 + if ( true === apply_filters( 'autoptimize_filter_imgopt_add_decoding', true ) && false === strpos( $tag, ' decoding=' ) ) {
659 + $tag = str_replace( '<img ', '<img decoding="async" ', $tag );
660 + }
596 661
662 + $tag = apply_filters( 'autoptimize_filter_imgopt_tag_postopt' , $tag );
663 +
597 664 // and add tag to array for later replacement.
598 665 if ( $tag !== $orig_tag ) {
599 666 $to_replace[ $orig_tag ] = $tag;
600 667 }
668 +
669 + // and check if image needs to be prelaoded.
670 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) {
671 + $to_preload .= $this->create_img_preload_tag( $tag );
672 + }
601 673 }
602 674 }
603 675
604 676 // and replace all.
@@ -643,12 +715,23 @@
643 715 } else {
644 716 $out = $this->process_picture_tag( $out, true, false );
645 717 }
646 718
719 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
720 + // the preload was not in an img tag, so adding a non-responsive preload instead.
721 + foreach( $metabox_preloads as $img_preload ) {
722 + $to_preload .= '<link rel="preload" href="' . $img_preload . '" as="image">' ;
723 + }
724 + }
725 +
726 + if ( ! empty( $to_preload ) ) {
727 + $out = autoptimizeExtra::inject_preloads( $to_preload, $out );
728 + }
729 +
647 730 return $out;
648 731 }
649 732
650 - public function get_size_from_tag( $tag ) {
733 + public static function get_size_from_tag( $tag ) {
651 734 // reusable function to extract widht and height from an image tag
652 735 // enforcing a filterable maximum width and height (default 4999X4999).
653 736 $width = '';
654 737 $height = '';
@@ -667,15 +750,19 @@
667 750 // check for and enforce (filterable) max sizes.
668 751 $_max_width = apply_filters( 'autoptimize_filter_imgopt_max_width', 4999 );
669 752 if ( $width > $_max_width ) {
670 753 $_width = $_max_width;
671 - $height = $_width / $width * $height;
754 + if ( ! empty( $height ) && is_int( $height ) ) {
755 + $height = $_width / $width * $height;
756 + }
672 757 $width = $_width;
673 758 }
674 759 $_max_height = apply_filters( 'autoptimize_filter_imgopt_max_height', 4999 );
675 760 if ( $height > $_max_height ) {
676 761 $_height = $_max_height;
677 - $width = $_height / $height * $width;
762 + if ( ! empty( $width ) && is_int( $width ) ) {
763 + $width = $_height / $height * $width;
764 + }
678 765 $height = $_height;
679 766 }
680 767
681 768 return array(
@@ -698,14 +785,20 @@
698 785 $lazyload_return = true;
699 786 } else {
700 787 $lazyload_return = false;
701 788 }
789 +
790 + // If page/ post check post_meta to see if lazyload is off for page.
791 + if ( false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_lazyload' ) ) {
792 + $lazyload_return = false;
793 + }
794 +
702 795 $lazyload_return = apply_filters( 'autoptimize_filter_imgopt_should_lazyload', $lazyload_return, $context );
703 796
704 797 return $lazyload_return;
705 798 }
706 799
707 - public function check_nolazy() {
800 + public static function check_nolazy() {
708 801 if ( array_key_exists( 'ao_nolazy', $_GET ) && '1' === $_GET['ao_nolazy'] ) {
709 802 return true;
710 803 } else {
711 804 return false;
@@ -715,8 +808,9 @@
715 808 public function filter_lazyload_images( $in )
716 809 {
717 810 // only used is image optimization is NOT active but lazyload is.
718 811 $to_replace = array();
812 + $to_preload = '';
719 813
720 814 // hide (no)script tags to avoid nesting noscript tags (as lazyloaded images add noscript).
721 815 $out = autoptimizeBase::replace_contents_with_marker_if_exists(
722 816 'SCRIPT',
@@ -724,14 +818,22 @@
724 818 '#<(?:no)?script.*?<\/(?:no)?script>#is',
725 819 $in
726 820 );
727 821
728 - // extract img tags and add lazyload attribs.
822 + // get img preloads as set in post metabox.
823 + $metabox_preloads = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) );
824 +
825 + // extract img tags and add lazyload attribs/ add preloads.
729 826 if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $out, $matches ) ) {
730 827 foreach ( $matches[0] as $tag ) {
731 828 if ( $this->should_lazyload( $out ) ) {
732 829 $to_replace[ $tag ] = $this->add_lazyload( $tag );
733 830 }
831 +
832 + // and check if image needs to be prelaoded.
833 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) {
834 + $to_preload .= $this->create_img_preload_tag( $tag );
835 + }
734 836 }
735 837 $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $out );
736 838 }
737 839
@@ -746,14 +848,33 @@
746 848 'SCRIPT',
747 849 $out
748 850 );
749 851
852 + if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
853 + // the preload was not in an img tag, so adding a non-responsive preload instead.
854 + foreach( $metabox_preloads as $img_preload ) {
855 + $to_preload .= '<link rel="preload" href="' . $img_preload . '" as="image">' ;
856 + }
857 + }
858 +
859 + if ( ! empty( $to_preload ) ) {
860 + $out = autoptimizeExtra::inject_preloads( $to_preload, $out );
861 + }
862 +
750 863 return $out;
751 864 }
752 865
753 866 public function add_lazyload( $tag, $placeholder = '' ) {
754 867 // adds actual lazyload-attributes to an image node.
755 - if ( str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag ) {
868 + $this->lazyload_counter++;
869 +
870 + $_lazyload_from_nth = '';
871 + if ( array_key_exists( 'autoptimize_imgopt_number_field_7', $this->options ) ) {
872 + $_lazyload_from_nth = $this->options['autoptimize_imgopt_number_field_7'];
873 + }
874 + $_lazyload_from_nth = apply_filters( 'autoptimize_filter_imgopt_lazyload_from_nth', $_lazyload_from_nth );
875 +
876 + if ( str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag && $this->lazyload_counter >= $_lazyload_from_nth ) {
756 877 $tag = $this->maybe_fix_missing_quotes( $tag );
757 878
758 879 // store original tag for use in noscript version.
759 880 $noscript_tag = '<noscript>' . autoptimizeUtils::remove_id_from_node( $tag ) . '</noscript>';
@@ -796,9 +917,9 @@
796 917 return $tag;
797 918 }
798 919
799 920 public function add_lazyload_js_footer() {
800 - if ( false === autoptimizeMain::should_buffer() ) {
921 + if ( false === autoptimizeMain::should_buffer() || autoptimizeMain::is_amp_markup('') ) {
801 922 return;
802 923 }
803 924
804 925 // The JS will by default be excluded form autoptimization but this can be changed with a filter.
@@ -806,9 +927,16 @@
806 927 if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_js_noptimize', true ) ) {
807 928 $noptimize_flag = ' data-noptimize="1"';
808 929 }
809 930
810 - $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js?ao_version=' . AUTOPTIMIZE_PLUGIN_VERSION, __FILE__ );
931 + $_extra = autoptimizeOptionWrapper::get_option( 'autoptimize_extra_settings', '' );
932 + if ( is_array( $_extra ) && array_key_exists( 'autoptimize_extra_checkbox_field_0', $_extra ) && ! empty( $_extra['autoptimize_extra_checkbox_field_0'] ) ) {
933 + // if "remove query strings" is active in "extra", then let's be consistant and not add one ourselves? :)
934 + $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js', __FILE__ );
935 + } else {
936 + $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js?ao_version=' . AUTOPTIMIZE_PLUGIN_VERSION, __FILE__ );
937 + }
938 +
811 939 $cdn_url = $this->get_cdn_url();
812 940 if ( ! empty( $cdn_url ) ) {
813 941 $cdn_url = rtrim( $cdn_url, '/' );
814 942 $lazysizes_js = str_replace( AUTOPTIMIZE_WP_SITE_URL, $cdn_url, $lazysizes_js );
@@ -822,18 +950,34 @@
822 950 // Adds lazyload CSS & JS to footer, using echo because wp_enqueue_script seems not to support pushing attributes (async).
823 951 echo apply_filters( 'autoptimize_filter_imgopt_lazyload_cssoutput', '<noscript><style>.lazyload{display:none;}</style></noscript>' );
824 952 echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $type_js . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' );
825 953 echo apply_filters( 'autoptimize_filter_imgopt_lazyload_js', '<script async' . $type_js . $noptimize_flag . ' src=\'' . $lazysizes_js . '\'></script>' );
954 + }
955 +
956 + public static function create_img_preload_tag( $tag ) {
957 + if ( false === apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
958 + return '';
959 + }
826 960
827 - // And add webp detection and loading JS.
828 - if ( $this->should_webp() ) {
829 - $_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);";
830 - $_webp_load = "document.addEventListener('lazybeforeunveil',function({target:b}){window.supportsWebP&&['data-src','data-srcset'].forEach(function(c){attr=b.getAttribute(c),null!==attr&&-1==attr.indexOf('/client/to_webp')&&b.setAttribute(c,attr.replace(/\/client\//,'/client/to_webp,'))})});";
831 - echo apply_filters( 'autoptimize_filter_imgopt_webp_js', '<script' . $type_js . $noptimize_flag . '>' . $_webp_detect . $_webp_load . '</script>' );
961 + // clean up; remove tabs/ linebreaks/ spaces.
962 + $tag = preg_replace( '/\s+/', ' ', $tag );
963 +
964 + // rewrite img tag to link preload img.
965 + $_from = array( '<img ', ' src=', ' sizes=', ' srcset=' );
966 + $_to = array( '<link rel="preload" as="image" ', ' href=', ' imagesizes=', ' imagesrcset=' );
967 + $tag = str_replace( $_from, $_to, $tag );
968 +
969 + // and remove title, alt, class and id.
970 + $tag = preg_replace( '/ ((?:title|alt|class|id|loading)=".*")/Um', '', $tag );
971 + if ( $tag !== str_replace( array(' title=', ' class=', ' alt=', ' id=' ), '', $tag ) ) {
972 + // 2nd regex pass if still title/ class/ alt in case single quotes were used iso doubles.
973 + $tag = preg_replace( '/ ((?:title|alt|class|id|loading)=\'.*\')/Um', '', $tag );
832 974 }
975 +
976 + return $tag;
833 977 }
834 978
835 - public function get_cdn_url() {
979 + public static function get_cdn_url() {
836 980 // getting CDN url here to avoid having to make bigger changes to autoptimizeBase.
837 981 static $cdn_url = null;
838 982
839 983 if ( null === $cdn_url ) {
@@ -873,9 +1017,9 @@
873 1017 public function inject_classes_in_tag( $tag, $target_class ) {
874 1018 if ( strpos( $tag, 'class=' ) !== false ) {
875 1019 $tag = preg_replace( '/(\sclass\s?=\s?("|\'))/', '$1' . $target_class, $tag );
876 1020 } else {
877 - $tag = preg_replace( '/(<img)\s/', '$1 class="' . trim( $target_class ) . '" ', $tag );
1021 + $tag = preg_replace( '/(<[a-zA-Z]*)\s/', '$1 class="' . trim( $target_class ) . '" ', $tag );
878 1022 }
879 1023
880 1024 return $tag;
881 1025 }
@@ -883,21 +1027,21 @@
883 1027 public function get_default_lazyload_placeholder( $imgopt_w, $imgopt_h ) {
884 1028 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';
885 1029 }
886 1030
887 - public function should_webp() {
888 - static $webp_return = null;
1031 + public function should_ngimg() {
1032 + static $ngimg_return = null;
889 1033
890 - if ( is_null( $webp_return ) ) {
891 - // webp only works if imgopt and lazyload are also active.
892 - if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) && $this->imgopt_active() ) {
893 - $webp_return = true;
1034 + if ( is_null( $ngimg_return ) ) {
1035 + // nextgen img only works if imgopt is active.
1036 + if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && $this->imgopt_active() ) {
1037 + $ngimg_return = true;
894 1038 } else {
895 - $webp_return = false;
1039 + $ngimg_return = false;
896 1040 }
897 1041 }
898 1042
899 - return $webp_return;
1043 + return $ngimg_return;
900 1044 }
901 1045
902 1046 public function process_picture_tag( $in, $imgopt = false, $lazy = false ) {
903 1047 // check if "<picture" is present and if filter allows us to process <picture>.
@@ -937,9 +1081,9 @@
937 1081
938 1082 public function process_bgimage( $in ) {
939 1083 if ( strpos( $in, 'background-image:' ) !== false && apply_filters( 'autoptimize_filter_imgopt_lazyload_backgroundimages', true ) ) {
940 1084 $out = preg_replace_callback(
941 - '/(<(?:article|aside|body|div|footer|header|p|section|table)[^>]*)\sstyle=(?:"|\')[^<>]*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)[^>]*/',
1085 + '/(<(?:article|aside|body|div|footer|header|p|section|span|table)[^>]*)\sstyle=(?:"|\')[^<>]*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)[^>]*/',
942 1086 array( $this, 'lazyload_bgimg_callback' ),
943 1087 $in
944 1088 );
945 1089 return $out;
@@ -951,18 +1095,27 @@
951 1095 if ( str_ireplace( $this->get_lazyload_exclusions(), '', $matches[0] ) === $matches[0] ) {
952 1096 // get placeholder & lazyload class strings.
953 1097 $placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( 500, 300 ) );
954 1098 $lazyload_class = apply_filters( 'autoptimize_filter_imgopt_lazyload_class', 'lazyload' );
1099 + // remove quotes from url() to be able to replace in next step.
1100 + $out = str_replace( array( "url('" . $matches[2] . "')", 'url("' . $matches[2] . '")' ), 'url(' . $matches[2] . ')', $matches[0] );
955 1101 // replace background-image URL with SVG placeholder.
956 - $out = str_replace( $matches[2], $placeholder, $matches[0] );
1102 + $out = str_replace( 'url(' . $matches[2], 'url(' . $placeholder, $out );
1103 + // sanitize bgimg src for quote sillyness.
1104 + $bgimg_src = $this->fix_silly_bgimg_quotes( $matches[2] );
957 1105 // add data-bg attribute with real background-image URL for lazyload to pick up.
958 - $out = str_replace( $matches[1], $matches[1] . ' data-bg="' . trim( str_replace( array( "\r\n", '&quot;' ), '', $matches[2] ) ) . '"', $out );
959 - // add lazyload class to tag.
1106 + $out = str_replace( $matches[1], $matches[1] . ' data-bg="' . $bgimg_src . '"', $out );
1107 + // and finally add lazyload class to tag.
960 1108 $out = $this->inject_classes_in_tag( $out, "$lazyload_class " );
961 1109 return $out;
962 1110 }
963 1111 return $matches[0];
964 1112 }
1113 +
1114 + public function fix_silly_bgimg_quotes( $tag_in ) {
1115 + // some themes/ pagebuilders wrap backgroundimages in HTML-encoded quotes (or linebreaks) which breaks imgopt/ lazyloading, this removes them.
1116 + return trim( str_replace( array( "\r\n", '&quot;', '&#034;', '&apos;', '&#039;' ), '', $tag_in ) );
1117 + }
965 1118
966 1119 public function maybe_fix_missing_quotes( $tag_in ) {
967 1120 // 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.
968 1121 if ( file_exists( WP_PLUGIN_DIR . '/w3-total-cache/w3-total-cache.php' ) && class_exists( 'Minify_HTML' ) && apply_filters( 'autoptimize_filter_imgopt_fixquotes', true ) ) {
@@ -1005,9 +1158,9 @@
1005 1158 public function imgopt_options_page()
1006 1159 {
1007 1160 // Check querystring for "refreshCacheChecker" and call cachechecker if so.
1008 1161 if ( array_key_exists( 'refreshImgProvStats', $_GET ) && 1 == $_GET['refreshImgProvStats'] ) {
1009 - $this->query_img_provider_stats();
1162 + $this->query_img_provider_stats( true );
1010 1163 }
1011 1164
1012 1165 $options = $this->fetch_options();
1013 1166 $sp_url_suffix = $this->get_service_url_suffix();
@@ -1018,9 +1171,9 @@
1018 1171 #autoptimize_imgopt_descr{font-size: 120%;}
1019 1172 </style>
1020 1173 <script>document.title = "Autoptimize: <?php _e( 'Images', 'autoptimize' ); ?> " + document.title;</script>
1021 1174 <div class="wrap">
1022 - <h1><?php _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
1175 + <h1><?php apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? _e( 'Autoptimize Pro Settings', 'autoptimize' ) : _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
1023 1176 <?php echo autoptimizeConfig::ao_admin_tabs(); ?>
1024 1177 <?php if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) { ?>
1025 1178 <div class="notice-warning notice"><p>
1026 1179 <?php
@@ -1046,9 +1199,9 @@
1046 1199 <?php } ?>
1047 1200 <form id='ao_settings_form' action='<?php echo admin_url( 'options.php' ); ?>' method='post'>
1048 1201 <?php settings_fields( 'autoptimize_imgopt_settings' ); ?>
1049 1202 <h2><?php _e( 'Image optimization', 'autoptimize' ); ?></h2>
1050 - <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>
1203 + <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 and AVIF support included!', 'autoptimize' ); ?></span>
1051 1204 <table class="form-table">
1052 1205 <tr>
1053 1206 <th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th>
1054 1207 <td>
@@ -1074,20 +1227,20 @@
1074 1227 }
1075 1228 echo apply_filters( 'autoptimize_filter_imgopt_settings_status', '<p><strong><span style="color:' . $_notice_color . ';">' . __( 'Shortpixel status: ', 'autoptimize' ) . '</span></strong>' . $_notice['notice'] . '</p>' );
1076 1229 } else {
1077 1230 // translators: link points to shortpixel.
1078 - $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>' );
1231 + $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://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>', '<a href="https://help.shortpixel.com/article/62-where-does-the-cdn-has-pops" target="_blank">' );
1079 1232 if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] ) {
1080 1233 $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' );
1081 1234 } else {
1082 1235 // translators: link points to shortpixel.
1083 - $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>' );
1236 + $upsell_msg_2 = sprintf( __( '%1$sSign-up now%2$s to receive x2 more CDN traffic or image optimization credits for free! This offer also applies to any future plan that you\'ll choose to purchase.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>' );
1084 1237 }
1085 1238 echo apply_filters( 'autoptimize_imgopt_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
1086 1239 }
1087 1240 // translators: link points to shortpixel FAQ.
1088 - $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>' );
1089 - $faqcopy = $faqcopy . ' ' . __( 'Only works for sites/ images that are publicly available.', 'autoptimize' );
1241 + $faqcopy = sprintf( __( '<strong>Questions</strong>? Have 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>' );
1242 + $faqcopy = $faqcopy . ' ' . __( 'Only works for websites and images that are publicly available.', 'autoptimize' );
1090 1243 // translators: links points to shortpixel TOS & Privacy Policy.
1091 1244 $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>' );
1092 1245 echo apply_filters( 'autoptimize_imgopt_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
1093 1246 ?>
@@ -1092,8 +1245,14 @@
1092 1245 echo apply_filters( 'autoptimize_imgopt_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
1093 1246 ?>
1094 1247 </td>
1095 1248 </tr>
1249 + <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"'; } ?>>
1250 + <th scope="row"><?php _e( 'Optimization exclusions', 'autoptimize' ); ?></th>
1251 + <td>
1252 + <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>
1253 + </td>
1254 + </tr>
1096 1255 <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"'; } ?>>
1097 1256 <th scope="row"><?php _e( 'Image Optimization quality', 'autoptimize' ); ?></th>
1098 1257 <td>
1099 1258 <label>
@@ -1120,12 +1279,12 @@
1120 1279 ?>
1121 1280 </p>
1122 1281 </td>
1123 1282 </tr>
1124 - <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"'; } ?>>
1125 - <th scope="row"><?php _e( 'Load WebP in supported browsers?', 'autoptimize' ); ?></th>
1283 + <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"'; } ?>>
1284 + <th scope="row"><?php _e( 'Load AVIF in supported browsers?', 'autoptimize' ); ?></th>
1126 1285 <td>
1127 - <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>
1286 + <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>
1128 1287 </td>
1129 1288 </tr>
1130 1289 <tr>
1131 1290 <th scope="row"><?php _e( 'Lazy-load images?', 'autoptimize' ); ?></th>
@@ -1132,14 +1291,20 @@
1132 1291 <td>
1133 1292 <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>
1134 1293 </td>
1135 1294 </tr>
1136 - <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"'; } ?>>
1295 + <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"'; } ?>>
1137 1296 <th scope="row"><?php _e( 'Lazy-load exclusions', 'autoptimize' ); ?></th>
1138 1297 <td>
1139 - <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>
1298 + <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>
1140 1299 </td>
1141 1300 </tr>
1301 + <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"'; } ?>>
1302 + <th scope="row"><?php _e( 'Lazy-load from nth image', 'autoptimize' ); ?></th>
1303 + <td>
1304 + <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>
1305 + </td>
1306 + </tr>
1142 1307 </table>
1143 1308 <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" /></p>
1144 1309 </form>
1145 1310 <script>
@@ -1146,26 +1311,21 @@
1146 1311 jQuery(document).ready(function() {
1147 1312 jQuery("#autoptimize_imgopt_checkbox").change(function() {
1148 1313 if (this.checked) {
1149 1314 jQuery("#autoptimize_imgopt_quality").show("slow");
1150 - jQuery("#autoptimize_imgopt_webp").show("slow");
1315 + jQuery("#autoptimize_imgopt_ngimg").show("slow");
1316 + jQuery("#autoptimize_imgopt_optimization_exclusions").show("slow");
1151 1317 } else {
1152 1318 jQuery("#autoptimize_imgopt_quality").hide("slow");
1153 - jQuery("#autoptimize_imgopt_webp").hide("slow");
1319 + jQuery("#autoptimize_imgopt_ngimg").hide("slow");
1320 + jQuery("#autoptimize_imgopt_optimization_exclusions").hide("slow");
1154 1321 }
1155 1322 });
1156 - jQuery("#autoptimize_imgopt_webp_checkbox").change(function() {
1157 - if (this.checked) {
1158 - jQuery("#autoptimize_imgopt_lazyload_checkbox")[0].checked = true;
1159 - jQuery("#autoptimize_imgopt_lazyload_exclusions").show("slow");
1160 - }
1161 - });
1162 1323 jQuery("#autoptimize_imgopt_lazyload_checkbox").change(function() {
1163 1324 if (this.checked) {
1164 - jQuery("#autoptimize_imgopt_lazyload_exclusions").show("slow");
1325 + jQuery(".autoptimize_lazyload_child").show("slow");
1165 1326 } else {
1166 - jQuery("#autoptimize_imgopt_lazyload_exclusions").hide("slow");
1167 - jQuery("#autoptimize_imgopt_webp_checkbox")[0].checked = false;
1327 + jQuery(".autoptimize_lazyload_child").hide("slow");
1168 1328 }
1169 1329 });
1170 1330 });
1171 1331 </script>
@@ -1179,9 +1339,9 @@
1179 1339 if ( $this->imgopt_active() ) {
1180 1340 $_imgopt_notice = '';
1181 1341 $_stat = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' );
1182 1342 $_site_host = AUTOPTIMIZE_SITE_DOMAIN;
1183 - $_imgopt_upsell = 'https://shortpixel.com/aospai/af/GWRGFLW109483/' . $_site_host;
1343 + $_imgopt_upsell = 'https://shortpixel.com/aospai/af/SPZURYE109483/' . $_site_host;
1184 1344 $_imgopt_assoc = 'https://shortpixel.helpscoutdocs.com/article/94-how-to-associate-a-domain-to-my-account';
1185 1345 $_imgopt_unreach = 'https://shortpixel.helpscoutdocs.com/article/148-why-are-my-images-redirected-from-cdn-shortpixel-ai';
1186 1346
1187 1347 if ( is_array( $_stat ) ) {
@@ -1191,14 +1351,14 @@
1191 1351 } elseif ( -1 == $_stat['Status'] || -2 == $_stat['Status'] ) {
1192 1352 // translators: "add more credits" will appear in a "a href".
1193 1353 $_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>' );
1194 1354 // translators: "associate your domain" will appear in a "a href".
1195 - $_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>' );
1355 + $_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>' );
1196 1356 } elseif ( -3 == $_stat['Status'] ) {
1197 1357 // translators: "check the documentation here" will appear in a "a href".
1198 1358 $_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>' );
1199 1359 } else {
1200 - $_imgopt_upsell = 'https://shortpixel.com/g/af/GWRGFLW109483';
1360 + $_imgopt_upsell = 'https://shortpixel.com/g/af/SPZURYE109483';
1201 1361 // translators: "log in to check your account" will appear in a "a href".
1202 1362 $_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>' );
1203 1363 }
1204 1364
@@ -1214,9 +1374,9 @@
1214 1374 $_imgopt_stats_last_run = __( 'based on previously fetched data', 'autoptimize' );
1215 1375 }
1216 1376 $_imgopt_notice .= ' (' . $_imgopt_stats_last_run . ', ';
1217 1377 // translators: "here to refresh" links to the Autoptimize Extra page and forces a refresh of the img opt stats.
1218 - $_imgopt_notice .= sprintf( __( 'click %1$shere to refresh%2$s', 'autoptimize' ), '<a href="' . $_imgopt_stats_refresh_url . '">', '</a>).' );
1378 + $_imgopt_notice .= sprintf( __( 'you can click %1$shere to refresh your quota status%2$s', 'autoptimize' ), '<a href="' . $_imgopt_stats_refresh_url . '">', '</a>).' );
1219 1379 }
1220 1380
1221 1381 // and make the full notice filterable.
1222 1382 $_imgopt_notice = apply_filters( 'autoptimize_filter_imgopt_notice', $_imgopt_notice );
@@ -1238,17 +1398,21 @@
1238 1398
1239 1399 /**
1240 1400 * Get img provider stats (used to display notice).
1241 1401 */
1242 - public function query_img_provider_stats() {
1402 + public function query_img_provider_stats( $_refresh = false ) {
1243 1403 if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_1'] ) ) {
1244 1404 $url = '';
1245 - $endpoint = $this->get_imgopt_host() . 'read-domain/';
1405 + $stat_dom = 'https://no-cdn.shortpixel.ai/';
1406 + $endpoint = $stat_dom . 'read-domain/';
1246 1407 $domain = AUTOPTIMIZE_SITE_DOMAIN;
1247 1408
1248 1409 // make sure parse_url result makes sense, keeping $url empty if not.
1249 1410 if ( $domain && ! empty( $domain ) ) {
1250 1411 $url = $endpoint . $domain;
1412 + if ( true === $_refresh ) {
1413 + $url = $url . '/refresh';
1414 + }
1251 1415 }
1252 1416
1253 1417 $url = apply_filters(
1254 1418 'autoptimize_filter_imgopt_stat_url',
@@ -1285,9 +1449,13 @@
1285 1449 {
1286 1450 static $launch_status = null;
1287 1451
1288 1452 if ( null === $launch_status ) {
1289 - $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
1453 + $avail_imgopt = '';
1454 + if ( is_array( $this->options ) && array_key_exists( 'availabilities', $this->options ) && is_array( $this->options['availabilities'] ) && array_key_exists( 'extra_imgopt', $this->options['availabilities'] ) ) {
1455 + $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
1456 + }
1457 +
1290 1458 $magic_number = intval( substr( md5( parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ), 0, 3 ), 16 );
1291 1459 $has_launched = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_launched', '' );
1292 1460 $launch_status = false;
1293 1461 if ( $has_launched || ( is_array( $avail_imgopt ) && array_key_exists( 'launch-threshold', $avail_imgopt ) && $magic_number < $avail_imgopt['launch-threshold'] ) ) {