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 +305 -97 2.6.03.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 }
@@ -111,8 +122,14 @@
111 122 public function run_on_frontend() {
112 123 if ( ! $this->should_run() ) {
113 124 if ( $this->should_lazyload() ) {
114 125 add_filter(
126 + 'wp_lazy_loading_enabled',
127 + array( $this, 'should_disable_core_lazyload' ),
128 + 10,
129 + 3
130 + );
131 + add_filter(
115 132 'autoptimize_html_after_minify',
116 133 array( $this, 'filter_lazyload_images' ),
117 134 10,
118 135 1
@@ -158,8 +175,14 @@
158 175 );
159 176 }
160 177
161 178 if ( $this->should_lazyload() ) {
179 + add_filter(
180 + 'wp_lazy_loading_enabled',
181 + array( $this, 'should_disable_core_lazyload' ),
182 + 10,
183 + 3
184 + );
162 185 add_action(
163 186 'wp_footer',
164 187 array( $this, 'add_lazyload_js_footer' ),
165 188 10,
@@ -168,8 +191,20 @@
168 191 }
169 192 }
170 193
171 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 + /**
172 207 * Basic checks before we can run.
173 208 *
174 209 * @return bool
175 210 */
@@ -201,9 +236,9 @@
201 236 {
202 237 static $imgopt_host = null;
203 238
204 239 if ( null === $imgopt_host ) {
205 - $imgopt_host = 'https://cdn.shortpixel.ai/';
240 + $imgopt_host = 'https://sp-ao.shortpixel.ai/';
206 241 $avail_imgopt = $this->options['availabilities']['extra_imgopt'];
207 242 if ( ! empty( $avail_imgopt ) && array_key_exists( 'hosts', $avail_imgopt ) && is_array( $avail_imgopt['hosts'] ) ) {
208 243 $imgopt_host = array_rand( array_flip( $avail_imgopt['hosts'] ) );
209 244 }
@@ -221,9 +256,9 @@
221 256 }
222 257
223 258 public static function get_service_url_suffix()
224 259 {
225 - $suffix = '/af/GWRGFLW109483/' . AUTOPTIMIZE_SITE_DOMAIN;
260 + $suffix = '/af/SPZURYE109483/' . AUTOPTIMIZE_SITE_DOMAIN;
226 261
227 262 return $suffix;
228 263 }
229 264
@@ -336,11 +371,9 @@
336 371 // Default to (the trimmed version of) what was given to us.
337 372 $result = trim( $in );
338 373
339 374 // 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 - }
375 + $result = $this->fix_silly_bgimg_quotes( $result );
343 376
344 377 if ( autoptimizeUtils::is_protocol_relative( $result ) ) {
345 378 $result = $parsed_site_url['scheme'] . ':' . $result;
346 379 } elseif ( 0 === strpos( $result, '/' ) ) {
@@ -345,12 +378,18 @@
345 378 $result = $parsed_site_url['scheme'] . ':' . $result;
346 379 } elseif ( 0 === strpos( $result, '/' ) ) {
347 380 // Root-relative...
348 381 $result = $parsed_site_url['scheme'] . '://' . $parsed_site_url['host'] . $result;
349 - } 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.
350 384 $result = str_replace( $cdn_domain, $parsed_site_url['host'], $result );
351 385 }
352 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 +
353 392 $result = apply_filters( 'autoptimize_filter_imgopt_normalized_url', $result );
354 393
355 394 // Store in cache.
356 395 $cache[ $in ] = $result;
@@ -362,9 +401,9 @@
362 401 public function filter_optimize_css_images( $in )
363 402 {
364 403 $in = $this->normalize_img_url( $in );
365 404
366 - if ( $this->can_optimize_image( $in ) ) {
405 + if ( $this->can_optimize_image( $in ) && false === strpos( $in, $this->get_imgopt_host() ) ) {
367 406 return $this->build_imgopt_url( $in, '', '' );
368 407 } else {
369 408 return $in;
370 409 }
@@ -377,9 +416,15 @@
377 416 if ( null === $imgopt_base_url ) {
378 417 $imgopt_host = $this->get_imgopt_host();
379 418 $quality = $this->get_img_quality_string();
380 419 $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;
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;
382 427 $imgopt_base_url = apply_filters( 'autoptimize_filter_imgopt_base_url', $imgopt_base_url );
383 428 }
384 429
385 430 return $imgopt_base_url;
@@ -384,9 +429,9 @@
384 429
385 430 return $imgopt_base_url;
386 431 }
387 432
388 - private function can_optimize_image( $url )
433 + private function can_optimize_image( $url, $tag = '', $testing = false )
389 434 {
390 435 static $cdn_url = null;
391 436 static $nopti_images = null;
392 437
@@ -396,10 +441,13 @@
396 441 autoptimizeOptionWrapper::get_option( 'autoptimize_cdn_url', '' )
397 442 );
398 443 }
399 444
400 - if ( null === $nopti_images ) {
401 - $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 );
402 450 }
403 451
404 452 $site_host = AUTOPTIMIZE_SITE_DOMAIN;
405 453 $url = $this->normalize_img_url( $url );
@@ -410,15 +458,15 @@
410 458 } elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host ) {
411 459 return false;
412 460 } elseif ( strpos( $url, '.php' ) !== false ) {
413 461 return false;
414 - } 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'] ) {
415 463 // fixme: better check against end of string.
416 464 return false;
417 465 } elseif ( ! empty( $nopti_images ) ) {
418 466 $nopti_images_array = array_filter( array_map( 'trim', explode( ',', $nopti_images ) ) );
419 467 foreach ( $nopti_images_array as $nopti_image ) {
420 - if ( strpos( $url, $nopti_image ) !== false ) {
468 + if ( strpos( $url, $nopti_image ) !== false || ( ( '' !== $tag && strpos( $tag, $nopti_image ) !== false ) ) ) {
421 469 return false;
422 470 }
423 471 }
424 472 }
@@ -448,9 +496,15 @@
448 496 if ( $filtered_url !== $orig_url ) {
449 497 return $filtered_url;
450 498 }
451 499
452 - $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 +
453 507 $imgopt_base_url = $this->get_imgopt_base_url();
454 508 $imgopt_size = '';
455 509
456 510 if ( $width && 0 !== $width ) {
@@ -460,9 +514,9 @@
460 514 if ( $height && 0 !== $height ) {
461 515 $imgopt_size .= ',h_' . $height;
462 516 }
463 517
464 - $url = $imgopt_base_url . $imgopt_size . '/' . $orig_url;
518 + $url = $imgopt_base_url . $imgopt_size . '/' . $normalized_url;
465 519
466 520 return $url;
467 521 }
468 522
@@ -473,9 +527,9 @@
473 527
474 528 public function replace_img_callback( $matches, $width = 0, $height = 0 )
475 529 {
476 530 $_normalized_img_url = $this->normalize_img_url( $matches[1] );
477 - if ( $this->can_optimize_image( $matches[1] ) ) {
531 + if ( $this->can_optimize_image( $matches[1], $matches[0] ) ) {
478 532 return str_replace( $matches[1], $this->build_imgopt_url( $_normalized_img_url, $width, $height ), $matches[0] );
479 533 } else {
480 534 return $matches[0];
481 535 }
@@ -480,10 +534,29 @@
480 534 return $matches[0];
481 535 }
482 536 }
483 537
484 - public function filter_optimize_images( $in )
538 + public function replace_icon_callback( $matches )
485 539 {
540 + if ( array_key_exists( '2', $matches ) ) {
541 + $sizes = explode( 'x', $matches[2] );
542 + $width = $sizes[0];
543 + $height = $sizes[1];
544 + } else {
545 + $width = 180;
546 + $height = 180;
547 + }
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 + }
555 + }
556 +
557 + public function filter_optimize_images( $in, $testing = false )
558 + {
486 559 /*
487 560 * potential future functional improvements:
488 561 *
489 562 * filter for critical CSS.
@@ -488,8 +561,9 @@
488 561 *
489 562 * filter for critical CSS.
490 563 */
491 564 $to_replace = array();
565 + $to_preload = '';
492 566
493 567 // hide noscript tags to avoid nesting noscript tags (as lazyloaded images add noscript).
494 568 if ( $this->should_lazyload() ) {
495 569 $in = autoptimizeBase::replace_contents_with_marker_if_exists(
@@ -499,11 +573,16 @@
499 573 $in
500 574 );
501 575 }
502 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 +
503 580 // extract img tags.
504 581 if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
505 582 foreach ( $matches[0] as $tag ) {
583 + $tag = apply_filters( 'autoptimize_filter_imgopt_tag_preopt' , $tag );
584 +
506 585 $orig_tag = $tag;
507 586 $imgopt_w = '';
508 587 $imgopt_h = '';
509 588
@@ -509,20 +588,22 @@
509 588
510 589 // first do (data-)srcsets.
511 590 if ( preg_match_all( '#srcset=("|\')(.*)("|\')#Usmi', $tag, $allsrcsets, PREG_SET_ORDER ) ) {
512 591 foreach ( $allsrcsets as $srcset ) {
513 - $srcset = $srcset[2];
514 - $srcsets = explode( ',', $srcset );
592 + $srcset = $srcset[2];
593 + $orig_srcset = $srcset;
594 + $srcsets = explode( ',', $srcset );
515 595 foreach ( $srcsets as $indiv_srcset ) {
516 596 $indiv_srcset_parts = explode( ' ', trim( $indiv_srcset ) );
517 597 if ( isset( $indiv_srcset_parts[1] ) && rtrim( $indiv_srcset_parts[1], 'w' ) !== $indiv_srcset_parts[1] ) {
518 598 $imgopt_w = rtrim( $indiv_srcset_parts[1], 'w' );
519 599 }
520 - if ( $this->can_optimize_image( $indiv_srcset_parts[0] ) ) {
600 + if ( $this->can_optimize_image( $indiv_srcset_parts[0], $tag, $testing ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
521 601 $imgopt_url = $this->build_imgopt_url( $indiv_srcset_parts[0], $imgopt_w, '' );
522 - $tag = str_replace( $indiv_srcset_parts[0], $imgopt_url, $tag );
602 + $srcset = str_replace( $indiv_srcset_parts[0], $imgopt_url, $srcset );
523 603 }
524 604 }
605 + $tag = str_replace( $orig_srcset, $srcset, $tag );
525 606 }
526 607 }
527 608
528 609 // proceed with img src.
@@ -535,9 +616,9 @@
535 616 if ( preg_match_all( '#src=(?:"|\')(?!data)(.*)(?:"|\')#Usmi', $tag, $urls, PREG_SET_ORDER ) ) {
536 617 foreach ( $urls as $url ) {
537 618 $full_src_orig = $url[0];
538 619 $url = $url[1];
539 - if ( $this->can_optimize_image( $url ) ) {
620 + if ( $this->can_optimize_image( $url, $tag, $testing ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
540 621 $imgopt_url = $this->build_imgopt_url( $url, $imgopt_w, $imgopt_h );
541 622 $full_imgopt_src = str_replace( $url, $imgopt_url, $full_src_orig );
542 623 $tag = str_replace( $full_src_orig, $full_imgopt_src, $tag );
543 624 }
@@ -544,9 +625,9 @@
544 625 }
545 626 }
546 627
547 628 // do lazyload stuff.
548 - if ( $this->should_lazyload( $in ) ) {
629 + if ( $this->should_lazyload( $in ) && ! empty( $url ) ) {
549 630 // first do lpiq placeholder logic.
550 631 if ( strpos( $url, $this->get_imgopt_host() ) === 0 ) {
551 632 // if all img src have been replaced during srcset, we have to extract the
552 633 // origin url from the imgopt one to be able to set a lqip placeholder.
@@ -554,10 +635,12 @@
554 635 } else {
555 636 $_url = $url;
556 637 }
557 638
639 + $_url = $this->normalize_img_url( $_url );
640 +
558 641 $placeholder = '';
559 - if ( $this->can_optimize_image( $_url ) && 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 ) ) {
560 643 $lqip_w = '';
561 644 $lqip_h = '';
562 645 if ( isset( $imgopt_w ) && ! empty( $imgopt_w ) ) {
563 646 $lqip_w = ',w_' . $imgopt_w;
@@ -569,13 +652,25 @@
569 652 }
570 653 // then call add_lazyload-function with lpiq placeholder if set.
571 654 $tag = $this->add_lazyload( $tag, $placeholder );
572 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 + }
573 661
662 + $tag = apply_filters( 'autoptimize_filter_imgopt_tag_postopt' , $tag );
663 +
574 664 // and add tag to array for later replacement.
575 665 if ( $tag !== $orig_tag ) {
576 666 $to_replace[ $orig_tag ] = $tag;
577 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 + }
578 673 }
579 674 }
580 675
581 676 // and replace all.
@@ -592,14 +687,23 @@
592 687
593 688 // background-image in inline style.
594 689 if ( strpos( $out, 'background-image:' ) !== false && apply_filters( 'autoptimize_filter_imgopt_backgroundimages', true ) ) {
595 690 $out = preg_replace_callback(
596 - '/style=(?:"|\').*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)/',
691 + '/style=(?:"|\')[^<>]*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)/',
597 692 array( $this, 'replace_img_callback' ),
598 693 $out
599 694 );
600 695 }
601 696
697 + // act on icon links.
698 + if ( ( strpos( $out, '<link rel="icon"' ) !== false || ( strpos( $out, "<link rel='icon'" ) !== false ) ) && apply_filters( 'autoptimize_filter_imgopt_linkicon', true ) ) {
699 + $out = preg_replace_callback(
700 + '/<link\srel=(?:"|\')(?:apple-touch-)?icon(?:"|\').*\shref=(?:"|\')(.*)(?:"|\')(?:\ssizes=(?:"|\')(\d*x\d*)(?:"|\'))?\s\/>/Um',
701 + array( $this, 'replace_icon_callback' ),
702 + $out
703 + );
704 + }
705 +
602 706 // lazyload: restore noscript tags + lazyload picture source tags and bgimage.
603 707 if ( $this->should_lazyload() ) {
604 708 $out = autoptimizeBase::restore_marked_content(
605 709 'SCRIPT',
@@ -611,12 +715,23 @@
611 715 } else {
612 716 $out = $this->process_picture_tag( $out, true, false );
613 717 }
614 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 +
615 730 return $out;
616 731 }
617 732
618 - public function get_size_from_tag( $tag ) {
733 + public static function get_size_from_tag( $tag ) {
619 734 // reusable function to extract widht and height from an image tag
620 735 // enforcing a filterable maximum width and height (default 4999X4999).
621 736 $width = '';
622 737 $height = '';
@@ -635,15 +750,19 @@
635 750 // check for and enforce (filterable) max sizes.
636 751 $_max_width = apply_filters( 'autoptimize_filter_imgopt_max_width', 4999 );
637 752 if ( $width > $_max_width ) {
638 753 $_width = $_max_width;
639 - $height = $_width / $width * $height;
754 + if ( ! empty( $height ) && is_int( $height ) ) {
755 + $height = $_width / $width * $height;
756 + }
640 757 $width = $_width;
641 758 }
642 759 $_max_height = apply_filters( 'autoptimize_filter_imgopt_max_height', 4999 );
643 760 if ( $height > $_max_height ) {
644 761 $_height = $_max_height;
645 - $width = $_height / $height * $width;
762 + if ( ! empty( $width ) && is_int( $width ) ) {
763 + $width = $_height / $height * $width;
764 + }
646 765 $height = $_height;
647 766 }
648 767
649 768 return array(
@@ -666,14 +785,20 @@
666 785 $lazyload_return = true;
667 786 } else {
668 787 $lazyload_return = false;
669 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 +
670 795 $lazyload_return = apply_filters( 'autoptimize_filter_imgopt_should_lazyload', $lazyload_return, $context );
671 796
672 797 return $lazyload_return;
673 798 }
674 799
675 - public function check_nolazy() {
800 + public static function check_nolazy() {
676 801 if ( array_key_exists( 'ao_nolazy', $_GET ) && '1' === $_GET['ao_nolazy'] ) {
677 802 return true;
678 803 } else {
679 804 return false;
@@ -683,8 +808,9 @@
683 808 public function filter_lazyload_images( $in )
684 809 {
685 810 // only used is image optimization is NOT active but lazyload is.
686 811 $to_replace = array();
812 + $to_preload = '';
687 813
688 814 // hide (no)script tags to avoid nesting noscript tags (as lazyloaded images add noscript).
689 815 $out = autoptimizeBase::replace_contents_with_marker_if_exists(
690 816 'SCRIPT',
@@ -692,14 +818,22 @@
692 818 '#<(?:no)?script.*?<\/(?:no)?script>#is',
693 819 $in
694 820 );
695 821
696 - // 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.
697 826 if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $out, $matches ) ) {
698 827 foreach ( $matches[0] as $tag ) {
699 828 if ( $this->should_lazyload( $out ) ) {
700 829 $to_replace[ $tag ] = $this->add_lazyload( $tag );
701 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 + }
702 836 }
703 837 $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $out );
704 838 }
705 839
@@ -714,14 +848,33 @@
714 848 'SCRIPT',
715 849 $out
716 850 );
717 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 +
718 863 return $out;
719 864 }
720 865
721 866 public function add_lazyload( $tag, $placeholder = '' ) {
722 867 // adds actual lazyload-attributes to an image node.
723 - 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 ) {
724 877 $tag = $this->maybe_fix_missing_quotes( $tag );
725 878
726 879 // store original tag for use in noscript version.
727 880 $noscript_tag = '<noscript>' . autoptimizeUtils::remove_id_from_node( $tag ) . '</noscript>';
@@ -735,13 +888,13 @@
735 888 // get image width & heigth for placeholder fun (and to prevent content reflow).
736 889 $_get_size = $this->get_size_from_tag( $tag );
737 890 $width = $_get_size['width'];
738 891 $height = $_get_size['height'];
739 - if ( false === $width ) {
740 - $widht = 210; // default width for SVG placeholder.
892 + if ( false === $width || empty( $width ) ) {
893 + $width = 210; // default width for SVG placeholder.
741 894 }
742 - if ( false === $height ) {
743 - $heigth = $width / 3 * 2; // if no height, base it on width using the 3/2 aspect ratio.
895 + if ( false === $height || empty( $height ) ) {
896 + $height = $width / 3 * 2; // if no height, base it on width using the 3/2 aspect ratio.
744 897 }
745 898
746 899 // insert the actual lazyload stuff.
747 900 // see https://css-tricks.com/preventing-content-reflow-from-lazy-loaded-images/ for great read on why we're using empty svg's.
@@ -764,9 +917,9 @@
764 917 return $tag;
765 918 }
766 919
767 920 public function add_lazyload_js_footer() {
768 - if ( false === autoptimizeMain::should_buffer() ) {
921 + if ( false === autoptimizeMain::should_buffer() || autoptimizeMain::is_amp_markup('') ) {
769 922 return;
770 923 }
771 924
772 925 // The JS will by default be excluded form autoptimization but this can be changed with a filter.
@@ -774,28 +927,57 @@
774 927 if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_js_noptimize', true ) ) {
775 928 $noptimize_flag = ' data-noptimize="1"';
776 929 }
777 930
778 - $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js', __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 +
779 939 $cdn_url = $this->get_cdn_url();
780 940 if ( ! empty( $cdn_url ) ) {
941 + $cdn_url = rtrim( $cdn_url, '/' );
781 942 $lazysizes_js = str_replace( AUTOPTIMIZE_WP_SITE_URL, $cdn_url, $lazysizes_js );
782 943 }
783 944
945 + $type_js = '';
946 + if ( apply_filters( 'autoptimize_filter_cssjs_addtype', false ) ) {
947 + $type_js = ' type="text/javascript"';
948 + }
949 +
784 950 // Adds lazyload CSS & JS to footer, using echo because wp_enqueue_script seems not to support pushing attributes (async).
785 - 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>' );
786 - echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' );
787 - echo apply_filters( 'autoptimize_filter_imgopt_lazyload_js', '<script async' . $noptimize_flag . ' src=\'' . $lazysizes_js . '\'></script>' );
951 + echo apply_filters( 'autoptimize_filter_imgopt_lazyload_cssoutput', '<noscript><style>.lazyload{display:none;}</style></noscript>' );
952 + echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $type_js . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' );
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 + }
788 960
789 - // And add webp detection and loading JS.
790 - if ( $this->should_webp() ) {
791 - $_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);";
792 - $_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,'))})});";
793 - echo apply_filters( 'autoptimize_filter_imgopt_webp_js', '<script' . $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 );
794 974 }
975 +
976 + return $tag;
795 977 }
796 978
797 - public function get_cdn_url() {
979 + public static function get_cdn_url() {
798 980 // getting CDN url here to avoid having to make bigger changes to autoptimizeBase.
799 981 static $cdn_url = null;
800 982
801 983 if ( null === $cdn_url ) {
@@ -814,9 +996,9 @@
814 996 if ( null === $exclude_lazyload_array ) {
815 997 $options = $this->options;
816 998
817 999 // set default exclusions.
818 - $exclude_lazyload_array = array( 'skip-lazy', 'data-no-lazy', 'notlazy', 'data-src', 'data-srcset', 'data:image/', 'data-lazyload', 'rev-slidebg' );
1000 + $exclude_lazyload_array = array( 'skip-lazy', 'data-no-lazy', 'notlazy', 'data-src', 'data-srcset', 'data:image/', 'data-lazyload', 'rev-slidebg', 'loading="eager"' );
819 1001
820 1002 // add from setting.
821 1003 if ( array_key_exists( 'autoptimize_imgopt_text_field_5', $options ) ) {
822 1004 $exclude_lazyload_option = $options['autoptimize_imgopt_text_field_5'];
@@ -835,9 +1017,9 @@
835 1017 public function inject_classes_in_tag( $tag, $target_class ) {
836 1018 if ( strpos( $tag, 'class=' ) !== false ) {
837 1019 $tag = preg_replace( '/(\sclass\s?=\s?("|\'))/', '$1' . $target_class, $tag );
838 1020 } else {
839 - $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 );
840 1022 }
841 1023
842 1024 return $tag;
843 1025 }
@@ -845,21 +1027,21 @@
845 1027 public function get_default_lazyload_placeholder( $imgopt_w, $imgopt_h ) {
846 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';
847 1029 }
848 1030
849 - public function should_webp() {
850 - static $webp_return = null;
1031 + public function should_ngimg() {
1032 + static $ngimg_return = null;
851 1033
852 - if ( is_null( $webp_return ) ) {
853 - // webp only works if imgopt and lazyload are also active.
854 - if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) && $this->imgopt_active() ) {
855 - $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;
856 1038 } else {
857 - $webp_return = false;
1039 + $ngimg_return = false;
858 1040 }
859 1041 }
860 1042
861 - return $webp_return;
1043 + return $ngimg_return;
862 1044 }
863 1045
864 1046 public function process_picture_tag( $in, $imgopt = false, $lazy = false ) {
865 1047 // check if "<picture" is present and if filter allows us to process <picture>.
@@ -878,9 +1060,9 @@
878 1060 foreach ( $_sources as $_source ) {
879 1061 $_picture_replacement = $_source[0];
880 1062
881 1063 // should we optimize the image?
882 - if ( $imgopt && $this->can_optimize_image( $_source[1] ) ) {
1064 + if ( $imgopt && $this->can_optimize_image( $_source[1], $_picture[0] ) ) {
883 1065 $_picture_replacement = str_replace( $_source[1], $this->build_imgopt_url( $_source[1] ), $_picture_replacement );
884 1066 }
885 1067 // should we lazy-load?
886 1068 if ( $lazy && $this->should_lazyload() && str_ireplace( $_exclusions, '', $_picture_replacement ) === $_picture_replacement ) {
@@ -899,9 +1081,9 @@
899 1081
900 1082 public function process_bgimage( $in ) {
901 1083 if ( strpos( $in, 'background-image:' ) !== false && apply_filters( 'autoptimize_filter_imgopt_lazyload_backgroundimages', true ) ) {
902 1084 $out = preg_replace_callback(
903 - '/(<(?: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\((?:"|\')?([^"\')]*)(?:"|\')?\)[^>]*/',
904 1086 array( $this, 'lazyload_bgimg_callback' ),
905 1087 $in
906 1088 );
907 1089 return $out;
@@ -913,23 +1095,34 @@
913 1095 if ( str_ireplace( $this->get_lazyload_exclusions(), '', $matches[0] ) === $matches[0] ) {
914 1096 // get placeholder & lazyload class strings.
915 1097 $placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( 500, 300 ) );
916 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] );
917 1101 // replace background-image URL with SVG placeholder.
918 - $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] );
919 1105 // add data-bg attribute with real background-image URL for lazyload to pick up.
920 - $out = str_replace( $matches[1], $matches[1] . ' data-bg="' . $matches[2] . '"', $out );
921 - // 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.
922 1108 $out = $this->inject_classes_in_tag( $out, "$lazyload_class " );
923 1109 return $out;
924 1110 }
925 1111 return $matches[0];
926 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 + }
927 1118
928 1119 public function maybe_fix_missing_quotes( $tag_in ) {
929 - // 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.
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.
930 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 ) ) {
931 - return preg_replace( '/class\s?=([^("|\')]*)(\s|>)/U', 'class=\'$1\'$2', $tag_in );
1122 + $tag_out = preg_replace( '/class\s?=([^("|\')]*)(\s|>)/U', 'class=\'$1\'$2', $tag_in );
1123 + $tag_out = preg_replace( '/\s(width|height)=(?:"|\')?([^\s"\'>]*)(?:"|\')?/', ' $1=\'$2\'', $tag_out );
1124 + return $tag_out;
932 1125 } else {
933 1126 return $tag_in;
934 1127 }
935 1128 }
@@ -948,10 +1141,10 @@
948 1141 'manage_options',
949 1142 'autoptimize_imgopt',
950 1143 array( $this, 'imgopt_options_page' )
951 1144 );
952 - register_setting( 'autoptimize_imgopt_settings', 'autoptimize_imgopt_settings' );
953 1145 }
1146 + register_setting( 'autoptimize_imgopt_settings', 'autoptimize_imgopt_settings' );
954 1147 }
955 1148
956 1149 public function add_imgopt_tab( $in )
957 1150 {
@@ -965,9 +1158,9 @@
965 1158 public function imgopt_options_page()
966 1159 {
967 1160 // Check querystring for "refreshCacheChecker" and call cachechecker if so.
968 1161 if ( array_key_exists( 'refreshImgProvStats', $_GET ) && 1 == $_GET['refreshImgProvStats'] ) {
969 - $this->query_img_provider_stats();
1162 + $this->query_img_provider_stats( true );
970 1163 }
971 1164
972 1165 $options = $this->fetch_options();
973 1166 $sp_url_suffix = $this->get_service_url_suffix();
@@ -978,9 +1171,9 @@
978 1171 #autoptimize_imgopt_descr{font-size: 120%;}
979 1172 </style>
980 1173 <script>document.title = "Autoptimize: <?php _e( 'Images', 'autoptimize' ); ?> " + document.title;</script>
981 1174 <div class="wrap">
982 - <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>
983 1176 <?php echo autoptimizeConfig::ao_admin_tabs(); ?>
984 1177 <?php if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) { ?>
985 1178 <div class="notice-warning notice"><p>
986 1179 <?php
@@ -1006,9 +1199,9 @@
1006 1199 <?php } ?>
1007 1200 <form id='ao_settings_form' action='<?php echo admin_url( 'options.php' ); ?>' method='post'>
1008 1201 <?php settings_fields( 'autoptimize_imgopt_settings' ); ?>
1009 1202 <h2><?php _e( 'Image optimization', 'autoptimize' ); ?></h2>
1010 - <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>
1011 1204 <table class="form-table">
1012 1205 <tr>
1013 1206 <th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th>
1014 1207 <td>
@@ -1034,20 +1227,20 @@
1034 1227 }
1035 1228 echo apply_filters( 'autoptimize_filter_imgopt_settings_status', '<p><strong><span style="color:' . $_notice_color . ';">' . __( 'Shortpixel status: ', 'autoptimize' ) . '</span></strong>' . $_notice['notice'] . '</p>' );
1036 1229 } else {
1037 1230 // translators: link points to shortpixel.
1038 - $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">' );
1039 1232 if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] ) {
1040 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' );
1041 1234 } else {
1042 1235 // translators: link points to shortpixel.
1043 - $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>' );
1044 1237 }
1045 1238 echo apply_filters( 'autoptimize_imgopt_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
1046 1239 }
1047 1240 // translators: link points to shortpixel FAQ.
1048 - $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>' );
1049 - $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' );
1050 1243 // translators: links points to shortpixel TOS & Privacy Policy.
1051 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>' );
1052 1245 echo apply_filters( 'autoptimize_imgopt_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
1053 1246 ?>
@@ -1052,8 +1245,14 @@
1052 1245 echo apply_filters( 'autoptimize_imgopt_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
1053 1246 ?>
1054 1247 </td>
1055 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>
1056 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"'; } ?>>
1057 1256 <th scope="row"><?php _e( 'Image Optimization quality', 'autoptimize' ); ?></th>
1058 1257 <td>
1059 1258 <label>
@@ -1080,12 +1279,12 @@
1080 1279 ?>
1081 1280 </p>
1082 1281 </td>
1083 1282 </tr>
1084 - <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"'; } ?>>
1085 - <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>
1086 1285 <td>
1087 - <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>
1088 1287 </td>
1089 1288 </tr>
1090 1289 <tr>
1091 1290 <th scope="row"><?php _e( 'Lazy-load images?', 'autoptimize' ); ?></th>
@@ -1092,14 +1291,20 @@
1092 1291 <td>
1093 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>
1094 1293 </td>
1095 1294 </tr>
1096 - <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"'; } ?>>
1097 1296 <th scope="row"><?php _e( 'Lazy-load exclusions', 'autoptimize' ); ?></th>
1098 1297 <td>
1099 - <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>
1100 1299 </td>
1101 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>
1102 1307 </table>
1103 1308 <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" /></p>
1104 1309 </form>
1105 1310 <script>
@@ -1106,26 +1311,21 @@
1106 1311 jQuery(document).ready(function() {
1107 1312 jQuery("#autoptimize_imgopt_checkbox").change(function() {
1108 1313 if (this.checked) {
1109 1314 jQuery("#autoptimize_imgopt_quality").show("slow");
1110 - jQuery("#autoptimize_imgopt_webp").show("slow");
1315 + jQuery("#autoptimize_imgopt_ngimg").show("slow");
1316 + jQuery("#autoptimize_imgopt_optimization_exclusions").show("slow");
1111 1317 } else {
1112 1318 jQuery("#autoptimize_imgopt_quality").hide("slow");
1113 - jQuery("#autoptimize_imgopt_webp").hide("slow");
1319 + jQuery("#autoptimize_imgopt_ngimg").hide("slow");
1320 + jQuery("#autoptimize_imgopt_optimization_exclusions").hide("slow");
1114 1321 }
1115 1322 });
1116 - jQuery("#autoptimize_imgopt_webp_checkbox").change(function() {
1117 - if (this.checked) {
1118 - jQuery("#autoptimize_imgopt_lazyload_checkbox")[0].checked = true;
1119 - jQuery("#autoptimize_imgopt_lazyload_exclusions").show("slow");
1120 - }
1121 - });
1122 1323 jQuery("#autoptimize_imgopt_lazyload_checkbox").change(function() {
1123 1324 if (this.checked) {
1124 - jQuery("#autoptimize_imgopt_lazyload_exclusions").show("slow");
1325 + jQuery(".autoptimize_lazyload_child").show("slow");
1125 1326 } else {
1126 - jQuery("#autoptimize_imgopt_lazyload_exclusions").hide("slow");
1127 - jQuery("#autoptimize_imgopt_webp_checkbox")[0].checked = false;
1327 + jQuery(".autoptimize_lazyload_child").hide("slow");
1128 1328 }
1129 1329 });
1130 1330 });
1131 1331 </script>
@@ -1139,9 +1339,9 @@
1139 1339 if ( $this->imgopt_active() ) {
1140 1340 $_imgopt_notice = '';
1141 1341 $_stat = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' );
1142 1342 $_site_host = AUTOPTIMIZE_SITE_DOMAIN;
1143 - $_imgopt_upsell = 'https://shortpixel.com/aospai/af/GWRGFLW109483/' . $_site_host;
1343 + $_imgopt_upsell = 'https://shortpixel.com/aospai/af/SPZURYE109483/' . $_site_host;
1144 1344 $_imgopt_assoc = 'https://shortpixel.helpscoutdocs.com/article/94-how-to-associate-a-domain-to-my-account';
1145 1345 $_imgopt_unreach = 'https://shortpixel.helpscoutdocs.com/article/148-why-are-my-images-redirected-from-cdn-shortpixel-ai';
1146 1346
1147 1347 if ( is_array( $_stat ) ) {
@@ -1151,14 +1351,14 @@
1151 1351 } elseif ( -1 == $_stat['Status'] || -2 == $_stat['Status'] ) {
1152 1352 // translators: "add more credits" will appear in a "a href".
1153 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>' );
1154 1354 // translators: "associate your domain" will appear in a "a href".
1155 - $_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>' );
1156 1356 } elseif ( -3 == $_stat['Status'] ) {
1157 - // translators: "add more credits" will appear in a "a href".
1357 + // translators: "check the documentation here" will appear in a "a href".
1158 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>' );
1159 1359 } else {
1160 - $_imgopt_upsell = 'https://shortpixel.com/g/af/GWRGFLW109483';
1360 + $_imgopt_upsell = 'https://shortpixel.com/g/af/SPZURYE109483';
1161 1361 // translators: "log in to check your account" will appear in a "a href".
1162 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>' );
1163 1363 }
1164 1364
@@ -1174,9 +1374,9 @@
1174 1374 $_imgopt_stats_last_run = __( 'based on previously fetched data', 'autoptimize' );
1175 1375 }
1176 1376 $_imgopt_notice .= ' (' . $_imgopt_stats_last_run . ', ';
1177 1377 // translators: "here to refresh" links to the Autoptimize Extra page and forces a refresh of the img opt stats.
1178 - $_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>).' );
1179 1379 }
1180 1380
1181 1381 // and make the full notice filterable.
1182 1382 $_imgopt_notice = apply_filters( 'autoptimize_filter_imgopt_notice', $_imgopt_notice );
@@ -1198,17 +1398,21 @@
1198 1398
1199 1399 /**
1200 1400 * Get img provider stats (used to display notice).
1201 1401 */
1202 - public function query_img_provider_stats() {
1402 + public function query_img_provider_stats( $_refresh = false ) {
1203 1403 if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_1'] ) ) {
1204 1404 $url = '';
1205 - $endpoint = $this->get_imgopt_host() . 'read-domain/';
1405 + $stat_dom = 'https://no-cdn.shortpixel.ai/';
1406 + $endpoint = $stat_dom . 'read-domain/';
1206 1407 $domain = AUTOPTIMIZE_SITE_DOMAIN;
1207 1408
1208 1409 // make sure parse_url result makes sense, keeping $url empty if not.
1209 1410 if ( $domain && ! empty( $domain ) ) {
1210 1411 $url = $endpoint . $domain;
1412 + if ( true === $_refresh ) {
1413 + $url = $url . '/refresh';
1414 + }
1211 1415 }
1212 1416
1213 1417 $url = apply_filters(
1214 1418 'autoptimize_filter_imgopt_stat_url',
@@ -1245,9 +1449,13 @@
1245 1449 {
1246 1450 static $launch_status = null;
1247 1451
1248 1452 if ( null === $launch_status ) {
1249 - $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 +
1250 1458 $magic_number = intval( substr( md5( parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ), 0, 3 ), 16 );
1251 1459 $has_launched = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_launched', '' );
1252 1460 $launch_status = false;
1253 1461 if ( $has_launched || ( is_array( $avail_imgopt ) && array_key_exists( 'launch-threshold', $avail_imgopt ) && $magic_number < $avail_imgopt['launch-threshold'] ) ) {