EWWW Image Optimizer - Version 6.1.0

Version Description

  • added: ability to use SVG placeholders for more efficient lazy load
  • added: Easy IO and Lazy Load add missing width and height to image elements
  • added: Lazy Load - right-sized placeholders can be generated for full-sized images
  • added: configure Lazy Load pre-load threshold via EIO_LL_THRESHOLD constant
  • changed: Lazy Load for external (non-inline) CSS images must be configured for specific elements
  • changed: Easy IO's Include All Resources unlocked for all plans
  • changed: native lazy loading is now disabled when using EWWW IO lazy load, override with EIO_ENABLE_NATIVE_LAZY constant
  • changed: Lazy Load pre-load threshold increased from 500px to 1000px
  • changed: Lazy Load picture elements use right-sized img placeholder instead of 1x1 inline GIF
  • changed: system-installed binary detection improved
  • fixed: native iframe lazy load disabled in WP 5.7+
  • fixed: detection for Shield Security plugin lock to location
  • fixed: relative path migration showing errors in site tools
  • fixed: WebP rewriters not handling relative image urls
  • fixed: existing elements ignored by WebP Rewriting
  • fixed: elements inside elements incorrectly handled by JS WebP Rewriting
  • fixed: removing metadata clobbers APNG animations
  • fixed: some JSON elements still being altered by Lazy Load
  • fixed: Easy IO throws warnings when WP content is not in a sub-directory
  • updated: jpegtran to version 9d
  • updated: cwebp to version 1.2.0
  • updated: pngquant to version 2.13.1
Download this release

Release Info

Developer nosilver4u
Plugin Icon 128x128 EWWW Image Optimizer
Version 6.1.0
Comparing to
See all releases

Code changes from version 6.0.3 to 6.1.0

.travis.yml CHANGED
@@ -14,7 +14,7 @@ branches:
14
  - master
15
 
16
  php:
17
- - 5.6
18
  - 7.4
19
 
20
  services:
@@ -22,14 +22,12 @@ services:
22
 
23
  env:
24
  - WP_VERSION=latest WP_MULTISITE=0
25
- - WP_VERSION=5.3 WP_MULTISITE=0
26
 
27
  jobs:
28
  include:
29
- - php: 5.6
30
  env: WP_VERSION=latest WP_MULTISITE=1 WPSNIFF=1
31
- - php: 7.3
32
- env: WP_VERSION=5.2
33
  - php: 7.4
34
  env: WP_VERSION=latest WP_MULTISITE=1 WPSNIFF=1
35
 
14
  - master
15
 
16
  php:
17
+ - 7.1
18
  - 7.4
19
 
20
  services:
22
 
23
  env:
24
  - WP_VERSION=latest WP_MULTISITE=0
25
+ - WP_VERSION=5.4 WP_MULTISITE=0
26
 
27
  jobs:
28
  include:
29
+ - php: 7.1
30
  env: WP_VERSION=latest WP_MULTISITE=1 WPSNIFF=1
 
 
31
  - php: 7.4
32
  env: WP_VERSION=latest WP_MULTISITE=1 WPSNIFF=1
33
 
binaries/cwebp-fbsd CHANGED
Binary file
binaries/cwebp-linux CHANGED
Binary file
binaries/cwebp-mac14 DELETED
Binary file
binaries/cwebp-mac15 ADDED
Binary file
binaries/cwebp-sol CHANGED
Binary file
binaries/cwebp.exe CHANGED
Binary file
binaries/gifsicle.exe CHANGED
Binary file
binaries/jpegtran-fbsd CHANGED
Binary file
binaries/jpegtran-linux CHANGED
Binary file
binaries/jpegtran-mac CHANGED
Binary file
binaries/jpegtran-sol CHANGED
Binary file
binaries/jpegtran.exe CHANGED
Binary file
binaries/pngquant-fbsd CHANGED
Binary file
binaries/pngquant-linux CHANGED
Binary file
binaries/pngquant-mac CHANGED
Binary file
binaries/pngquant-sol CHANGED
Binary file
binaries/pngquant.exe CHANGED
Binary file
changelog.txt CHANGED
@@ -1,3 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = 6.0.3 =
2
  * fixed: syntax error on PHP 7.2 or less
3
 
1
+ = 6.1.0 =
2
+ * added: ability to use SVG placeholders for more efficient lazy load
3
+ * added: Easy IO and Lazy Load add missing width and height to image elements
4
+ * added: Lazy Load - right-sized placeholders can be generated for full-sized images
5
+ * added: configure Lazy Load pre-load threshold via EIO_LL_THRESHOLD constant
6
+ * changed: Lazy Load for external (non-inline) CSS images must be configured for specific elements
7
+ * changed: Easy IO's Include All Resources unlocked for all plans
8
+ * changed: native lazy loading is now disabled when using EWWW IO lazy load, override with EIO_ENABLE_NATIVE_LAZY constant
9
+ * changed: Lazy Load pre-load threshold increased from 500px to 1000px
10
+ * changed: Lazy Load picture elements use right-sized img placeholder instead of 1x1 inline GIF
11
+ * changed: system-installed binary detection improved
12
+ * fixed: native iframe lazy load disabled in WP 5.7+
13
+ * fixed: detection for Shield Security plugin lock to location
14
+ * fixed: relative path migration showing errors in site tools
15
+ * fixed: WebP rewriters not handling relative image urls
16
+ * fixed: existing <picture> elements ignored by <picture> WebP Rewriting
17
+ * fixed: <img> elements inside <picture> elements incorrectly handled by JS WebP Rewriting
18
+ * fixed: removing metadata clobbers APNG animations
19
+ * fixed: some JSON elements still being altered by Lazy Load
20
+ * fixed: Easy IO throws warnings when WP content is not in a sub-directory
21
+ * updated: jpegtran to version 9d
22
+ * updated: cwebp to version 1.2.0
23
+ * updated: pngquant to version 2.13.1
24
+
25
  = 6.0.3 =
26
  * fixed: syntax error on PHP 7.2 or less
27
 
classes/class-eio-alt-webp.php CHANGED
@@ -39,30 +39,6 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
39
  */
40
  private $inline_script = '';
41
 
42
- /**
43
- * Indicates if we are filtering ExactDN urls.
44
- *
45
- * @access protected
46
- * @var bool $parsing_exactdn
47
- */
48
- protected $parsing_exactdn = false;
49
-
50
- /**
51
- * Allowed paths for JS WebP.
52
- *
53
- * @access protected
54
- * @var array $webp_paths
55
- */
56
- protected $webp_paths = array();
57
-
58
- /**
59
- * Allowed domains for JS WebP.
60
- *
61
- * @access protected
62
- * @var array $webp_domains
63
- */
64
- protected $webp_domains = array();
65
-
66
  /**
67
  * Register (once) actions and filters for Alt WebP.
68
  */
@@ -75,6 +51,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
75
  return false;
76
  }
77
  parent::__construct();
 
78
  // Start an output buffer before any output starts.
79
  /* add_action( 'template_redirect', array( $this, 'buffer_start' ), 0 ); */
80
  add_filter( 'ewww_image_optimizer_filter_page_output', array( $this, 'filter_page_output' ), 20 );
@@ -86,96 +63,17 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
86
  // Load up the minified script so we can inline it.
87
  $this->inline_script = file_get_contents( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'includes/load_webp.min.js' );
88
 
89
- $upload_dir = wp_get_upload_dir();
90
- $this->content_url = trailingslashit( ! empty( $upload_dir['baseurl'] ) ? $upload_dir['baseurl'] : content_url( 'uploads' ) );
91
- ewwwio_debug_message( "content_url: $this->content_url" );
92
- $this->home_domain = $this->parse_url( $this->home_url, PHP_URL_HOST );
93
- ewwwio_debug_message( "home domain: $this->home_domain" );
94
-
95
- $this->webp_paths = ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_paths' );
96
- if ( ! is_array( $this->webp_paths ) ) {
97
- $this->webp_paths = array();
98
  }
99
 
100
- // Find the WP Offload Media domain/path.
101
- if ( class_exists( 'Amazon_S3_And_CloudFront' ) ) {
102
- global $as3cf;
103
- $s3_scheme = $as3cf->get_url_scheme();
104
- $s3_bucket = $as3cf->get_setting( 'bucket' );
105
- $s3_region = $as3cf->get_setting( 'region' );
106
- if ( is_wp_error( $s3_region ) ) {
107
- $s3_region = '';
108
- }
109
- if ( ! empty( $s3_bucket ) && ! is_wp_error( $s3_bucket ) && method_exists( $as3cf, 'get_provider' ) ) {
110
- $s3_domain = $as3cf->get_provider()->get_url_domain( $s3_bucket, $s3_region, null, array(), true );
111
- } elseif ( ! empty( $s3_bucket ) && ! is_wp_error( $s3_bucket ) && method_exists( $as3cf, 'get_storage_provider' ) ) {
112
- $s3_domain = $as3cf->get_storage_provider()->get_url_domain( $s3_bucket, $s3_region );
113
- }
114
- if ( ! empty( $s3_domain ) && $as3cf->get_setting( 'serve-from-s3' ) ) {
115
- ewwwio_debug_message( "found S3 domain of $s3_domain with bucket $s3_bucket and region $s3_region" );
116
- $this->webp_paths[] = $s3_scheme . '://' . $s3_domain . '/';
117
- if ( $as3cf->get_setting( 'enable-delivery-domain' ) && $as3cf->get_setting( 'delivery-domain' ) ) {
118
- $delivery_domain = $as3cf->get_setting( 'delivery-domain' );
119
- $this->webp_paths[] = $s3_scheme . '://' . $delivery_domain . '/';
120
- $this->debug_message( "found WOM delivery domain of $delivery_domain" );
121
- }
122
- $this->s3_active = $s3_domain;
123
- if ( $as3cf->get_setting( 'enable-object-prefix' ) ) {
124
- $this->s3_object_prefix = $as3cf->get_setting( 'object-prefix' );
125
- $this->debug_message( $as3cf->get_setting( 'object-prefix' ) );
126
- } else {
127
- $this->debug_message( 'no WOM prefix' );
128
- }
129
- if ( $as3cf->get_setting( 'object-versioning' ) ) {
130
- $this->s3_object_version = true;
131
- $this->debug_message( 'object versioning enabled' );
132
- }
133
- }
134
- }
135
-
136
- if (
137
- class_exists( 'S3_Uploads' ) &&
138
- function_exists( 's3_uploads_enabled' ) && s3_uploads_enabled() &&
139
- method_exists( 'S3_Uploads', 'get_instance' ) && method_exists( 'S3_Uploads', 'get_s3_url' )
140
- ) {
141
- $s3_uploads_instance = \S3_Uploads::get_instance();
142
- $s3_uploads_url = $s3_uploads_instance->get_s3_url();
143
- $this->webp_paths[] = $s3_uploads_url;
144
- $this->debug_message( "found S3 URL from S3_Uploads: $s3_uploads_url" );
145
- }
146
 
147
- if ( class_exists( 'wpCloud\StatelessMedia\EWWW' ) && function_exists( 'ud_get_stateless_media' ) ) {
148
- $sm = ud_get_stateless_media();
149
- if ( method_exists( $sm, 'get' ) && method_exists( $sm, 'get_gs_host' ) ) {
150
- $sm_mode = $sm->get( 'sm.mode' );
151
- if ( 'disabled' !== $sm_mode ) {
152
- $sm_host = $sm->get_gs_host();
153
- $this->debug_message( $sm_host );
154
- $this->webp_paths[] = $sm_host;
155
- }
156
- }
157
- }
158
-
159
- if ( function_exists( 'swis' ) && swis()->settings->get_option( 'cdn_domain' ) ) {
160
- $this->webp_paths[] = swis()->settings->get_option( 'cdn_domain' );
161
- }
162
-
163
- foreach ( $this->webp_paths as $webp_path ) {
164
- $webp_domain = $this->parse_url( $webp_path, PHP_URL_HOST );
165
- if ( $webp_domain ) {
166
- $this->webp_domains[] = $webp_domain;
167
- }
168
- }
169
- $this->debug_message( 'checking any images matching these patterns for webp: ' . implode( ',', $this->webp_paths ) );
170
- $this->debug_message( 'rewriting any images matching these domains to webp: ' . implode( ',', $this->webp_domains ) );
171
- if ( class_exists( 'ExactDN' ) && $this->get_option( 'ewww_image_optimizer_exactdn' ) ) {
172
- global $exactdn;
173
- $this->exactdn_domain = $exactdn->get_exactdn_domain();
174
- if ( $this->exactdn_domain ) {
175
- $this->parsing_exactdn = true;
176
- $this->debug_message( 'parsing an exactdn page' );
177
- }
178
- }
179
 
180
  // Load the appropriate JS.
181
  if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
@@ -196,7 +94,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
196
  * @return array A list of WebP domains.
197
  */
198
  function get_webp_domains() {
199
- return $this->webp_domains;
200
  }
201
 
202
  /**
@@ -309,7 +207,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
309
  function srcset_replace( $srcset ) {
310
  $srcset_urls = explode( ' ', $srcset );
311
  $found_webp = false;
312
- if ( ewww_image_optimizer_iterable( $srcset_urls ) && count( $srcset_urls ) > 1 ) {
313
  ewwwio_debug_message( 'parsing srcset urls' );
314
  foreach ( $srcset_urls as $srcurl ) {
315
  if ( is_numeric( substr( $srcurl, 0, 1 ) ) ) {
@@ -445,11 +343,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
445
  return $buffer;
446
  }
447
 
448
- if ( in_array( 'picture', $this->user_element_exclusions, true ) ) {
449
- $images = $this->get_images_from_html( preg_replace( '/<(picture|noscript).*?\/\1>/s', '', $buffer ), false );
450
- } else {
451
- $images = $this->get_images_from_html( preg_replace( '/<noscript.*?\/noscript>/s', '', $buffer ), false );
452
- }
453
  if ( ! empty( $images[0] ) && $this->is_iterable( $images[0] ) ) {
454
  foreach ( $images[0] as $index => $image ) {
455
  // Ignore 0-size Pinterest schema images.
@@ -576,7 +470,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
576
  } // End foreach().
577
  } // End if().
578
  // Now we will look for any lazy images that don't have a src attribute (this search returns ALL img elements though).
579
- $images = $this->get_images_from_html( preg_replace( '/<noscript.*?\/noscript>/s', '', $buffer ), false, false );
580
  if ( ! empty( $images[0] ) && $this->is_iterable( $images[0] ) ) {
581
  ewwwio_debug_message( 'parsing images without requiring src' );
582
  foreach ( $images[0] as $index => $image ) {
@@ -613,7 +507,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
613
  // Look for images to parse WP Retina Lazy Load.
614
  if ( class_exists( 'Meow_WR2X_Core' ) && strpos( $buffer, ' lazyload' ) ) {
615
  $images = $this->get_elements_from_html( $buffer, 'img' );
616
- if ( ewww_image_optimizer_iterable( $images ) ) {
617
  foreach ( $images as $index => $image ) {
618
  if ( ! $this->validate_tag( $image ) ) {
619
  continue;
@@ -637,9 +531,9 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
637
  }
638
  }
639
  }
640
- // Images listed as picture/source elements. Mostly for NextGEN, but should work anywhere.
641
  $pictures = $this->get_picture_tags_from_html( $buffer );
642
- if ( ewww_image_optimizer_iterable( $pictures ) ) {
643
  foreach ( $pictures as $index => $picture ) {
644
  if ( strpos( $picture, 'image/webp' ) ) {
645
  continue;
@@ -648,9 +542,9 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
648
  continue;
649
  }
650
  $sources = $this->get_elements_from_html( $picture, 'source' );
651
- if ( ewww_image_optimizer_iterable( $sources ) ) {
652
  foreach ( $sources as $source ) {
653
- ewwwio_debug_message( "parsing a picture source: $source" );
654
  $srcset_attr_name = 'srcset';
655
  if ( false !== strpos( $source, 'base64,R0lGOD' ) && false !== strpos( $source, 'data-srcset=' ) ) {
656
  $srcset_attr_name = 'data-srcset';
@@ -666,7 +560,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
666
  }
667
  }
668
  if ( $picture !== $pictures[ $index ] ) {
669
- ewwwio_debug_message( 'found webp for picture element' );
670
  $buffer = str_replace( $pictures[ $index ], $picture, $buffer );
671
  }
672
  }
@@ -674,7 +568,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
674
  }
675
  // NextGEN slides listed as 'a' elements and LL 'a' background images.
676
  $links = $this->get_elements_from_html( $buffer, 'a' );
677
- if ( ewww_image_optimizer_iterable( $links ) ) {
678
  foreach ( $links as $index => $link ) {
679
  ewwwio_debug_message( "parsing a link $link" );
680
  if ( ! $this->validate_tag( $link ) ) {
@@ -710,7 +604,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
710
  }
711
  // Revolution Slider 'li' elements and LL li backgrounds.
712
  $listitems = $this->get_elements_from_html( $buffer, 'li' );
713
- if ( ewww_image_optimizer_iterable( $listitems ) ) {
714
  foreach ( $listitems as $index => $listitem ) {
715
  ewwwio_debug_message( 'parsing a listitem' );
716
  if ( ! $this->validate_tag( $listitem ) ) {
@@ -756,7 +650,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
756
  } // End if().
757
  // WooCommerce thumbs listed as 'div' elements and LL div backgrounds.
758
  $divs = $this->get_elements_from_html( $buffer, 'div' );
759
- if ( ewww_image_optimizer_iterable( $divs ) ) {
760
  foreach ( $divs as $index => $div ) {
761
  ewwwio_debug_message( 'parsing a div' );
762
  if ( ! $this->validate_tag( $div ) ) {
@@ -785,7 +679,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
785
  }
786
  // Look for LL 'section' elements.
787
  $sections = $this->get_elements_from_html( $buffer, 'section' );
788
- if ( ewww_image_optimizer_iterable( $sections ) ) {
789
  foreach ( $sections as $index => $section ) {
790
  ewwwio_debug_message( 'parsing a section' );
791
  if ( ! $this->validate_tag( $section ) ) {
@@ -805,7 +699,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
805
  }
806
  // Look for LL 'span' elements.
807
  $spans = $this->get_elements_from_html( $buffer, 'span' );
808
- if ( ewww_image_optimizer_iterable( $spans ) ) {
809
  foreach ( $spans as $index => $span ) {
810
  ewwwio_debug_message( 'parsing a span' );
811
  if ( ! $this->validate_tag( $span ) ) {
@@ -825,7 +719,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
825
  }
826
  // Video elements, looking for poster attributes that are images.
827
  $videos = $this->get_elements_from_html( $buffer, 'video' );
828
- if ( ewww_image_optimizer_iterable( $videos ) ) {
829
  foreach ( $videos as $index => $video ) {
830
  ewwwio_debug_message( 'parsing a video element' );
831
  if ( ! $this->validate_tag( $video ) ) {
@@ -844,7 +738,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
844
  }
845
  }
846
  }
847
- ewwwio_debug_message( 'all done parsing page for alt webp' );
848
  return $buffer;
849
  }
850
 
@@ -924,101 +818,6 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
924
  return $variations;
925
  }
926
 
927
- /**
928
- * Attempts to reverse a CDN URL to a local path to test for file existence.
929
- *
930
- * Used for supporting pull-mode CDNs without forcing everything to WebP.
931
- *
932
- * @param string $url The image URL to mangle.
933
- * @return bool True if a local file exists correlating to the CDN URL, false otherwise.
934
- */
935
- function cdn_to_local( $url ) {
936
- ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
937
- if ( ! is_array( $this->webp_domains ) || ! count( $this->webp_domains ) ) {
938
- return false;
939
- }
940
- foreach ( $this->webp_domains as $webp_domain ) {
941
- if ( $webp_domain === $this->home_domain ) {
942
- continue;
943
- }
944
- ewwwio_debug_message( "looking for domain $webp_domain in $url" );
945
- if (
946
- ! empty( $this->s3_active ) &&
947
- false !== strpos( $url, $this->s3_active ) &&
948
- (
949
- ( false !== strpos( $this->s3_active, '/' ) ) ||
950
- ( ! empty( $this->s3_object_prefix ) && false !== strpos( $url, $this->s3_object_prefix ) )
951
- )
952
- ) {
953
- // We will wait until the paths loop to fix this one.
954
- continue;
955
- }
956
- if ( false !== strpos( $url, $webp_domain ) ) {
957
- $local_url = str_replace( $webp_domain, $this->home_domain, $url );
958
- ewwwio_debug_message( "found $webp_domain, replaced with $this->home_domain to get $local_url" );
959
- if ( $this->url_to_path_exists( $local_url ) ) {
960
- return true;
961
- }
962
- }
963
- }
964
- foreach ( $this->webp_paths as $webp_path ) {
965
- if ( false === strpos( $webp_path, 'http' ) ) {
966
- continue;
967
- }
968
- ewwwio_debug_message( "looking for path $webp_path in $url" );
969
- if (
970
- ! empty( $this->s3_active ) &&
971
- false !== strpos( $url, $this->s3_active ) &&
972
- ! empty( $this->s3_object_prefix ) &&
973
- 0 === strpos( $url, $webp_path . $this->s3_object_prefix )
974
- ) {
975
- $local_url = str_replace( $webp_path . $this->s3_object_prefix, $this->content_url, $url );
976
- ewwwio_debug_message( "found $webp_path (and $this->s3_object_prefix), replaced with $this->content_url to get $local_url" );
977
- if ( $this->url_to_path_exists( $local_url ) ) {
978
- return true;
979
- }
980
- }
981
- if ( false !== strpos( $url, $webp_path ) ) {
982
- $local_url = str_replace( $webp_path, $this->content_url, $url );
983
- ewwwio_debug_message( "found $webp_path, replaced with $this->content_url to get $local_url" );
984
- if ( $this->url_to_path_exists( $local_url ) ) {
985
- return true;
986
- }
987
- }
988
- }
989
- return false;
990
- }
991
-
992
- /**
993
- * Remove S3 object versioning from URL.
994
- *
995
- * @param string $url The image URL with a potential version string embedded.
996
- * @return string The URL without a version string.
997
- */
998
- function maybe_strip_object_version( $url ) {
999
- if ( ! empty( $this->s3_object_version ) ) {
1000
- $possible_version = basename( dirname( $url ) );
1001
- if (
1002
- ! empty( $possible_version ) &&
1003
- 8 === strlen( $possible_version ) &&
1004
- ctype_digit( $possible_version )
1005
- ) {
1006
- $url = str_replace( '/' . $possible_version . '/', '/', $url );
1007
- ewwwio_debug_message( "removed version $possible_version from $url" );
1008
- } elseif (
1009
- ! empty( $possible_version ) &&
1010
- 14 === strlen( $possible_version ) &&
1011
- ctype_digit( $possible_version )
1012
- ) {
1013
- $year = substr( $possible_version, 0, 4 );
1014
- $month = substr( $possible_version, 4, 2 );
1015
- $url = str_replace( '/' . $possible_version . '/', "/$year/$month/", $url );
1016
- ewwwio_debug_message( "removed version $possible_version from $url" );
1017
- }
1018
- }
1019
- return $url;
1020
- }
1021
-
1022
  /**
1023
  * Converts a URL to a file-system path and checks if the resulting path exists.
1024
  *
@@ -1027,7 +826,6 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
1027
  * @return bool True if a local file exists correlating to the URL, false otherwise.
1028
  */
1029
  function url_to_path_exists( $url, $extension = '' ) {
1030
- $url = $this->maybe_strip_object_version( $url );
1031
  return parent::url_to_path_exists( $url, '.webp' );
1032
  }
1033
 
@@ -1071,7 +869,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
1071
  * @return bool False if it flags a filter or exclusion, true otherwise.
1072
  */
1073
  function validate_tag( $image ) {
1074
- ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
1075
  // Ignore 0-size Pinterest schema images.
1076
  if ( strpos( $image, 'data-pin-description=' ) && strpos( $image, 'width="0" height="0"' ) ) {
1077
  $this->debug_message( 'data-pin-description img skipped' );
@@ -1127,7 +925,7 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
1127
  if ( ! is_null( $image_path ) && $image_path ) {
1128
  $extension = strtolower( pathinfo( $image_path, PATHINFO_EXTENSION ) );
1129
  }
1130
- if ( $extension && 'gif' === $extension && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_force_gif2webp' ) ) {
1131
  return false;
1132
  }
1133
  if ( $extension && 'svg' === $extension ) {
@@ -1139,15 +937,15 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
1139
  if ( apply_filters( 'ewww_image_optimizer_skip_webp_rewrite', false, $image ) ) {
1140
  return false;
1141
  }
1142
- if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_force' ) && $this->webp_paths ) {
1143
  // Check the image for configured CDN paths.
1144
- foreach ( $this->webp_paths as $webp_path ) {
1145
- if ( strpos( $image, $webp_path ) !== false ) {
1146
- ewwwio_debug_message( 'forced cdn image' );
1147
  return true;
1148
  }
1149
  }
1150
- } elseif ( $this->webp_paths && $this->webp_domains ) {
1151
  if ( $this->cdn_to_local( $image ) ) {
1152
  return true;
1153
  }
@@ -1164,13 +962,8 @@ class EIO_Alt_Webp extends EIO_Page_Parser {
1164
  * @return string The WebP version of the image url.
1165
  */
1166
  function generate_url( $url ) {
1167
- if ( $this->parsing_exactdn && false !== strpos( $url, $this->exactdn_domain ) ) {
1168
- return add_query_arg( 'webp', 1, $url );
1169
- } else {
1170
- $path_parts = explode( '?', $url );
1171
- return $path_parts[0] . '.webp' . ( ! empty( $path_parts[1] ) && 'is-pending-load=1' !== $path_parts[1] ? '?' . $path_parts[1] : '' );
1172
- }
1173
- return $url;
1174
  }
1175
 
1176
  /**
39
  */
40
  private $inline_script = '';
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  /**
43
  * Register (once) actions and filters for Alt WebP.
44
  */
51
  return false;
52
  }
53
  parent::__construct();
54
+ $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
55
  // Start an output buffer before any output starts.
56
  /* add_action( 'template_redirect', array( $this, 'buffer_start' ), 0 ); */
57
  add_filter( 'ewww_image_optimizer_filter_page_output', array( $this, 'filter_page_output' ), 20 );
63
  // Load up the minified script so we can inline it.
64
  $this->inline_script = file_get_contents( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'includes/load_webp.min.js' );
65
 
66
+ $allowed_urls = ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_paths' );
67
+ if ( $this->is_iterable( $allowed_urls ) ) {
68
+ $this->allowed_urls = array_merge( $this->allowed_urls, $allowed_urls );
 
 
 
 
 
 
69
  }
70
 
71
+ $this->get_allowed_domains();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
+ $this->allowed_urls = apply_filters( 'webp_allowed_urls', $this->allowed_urls );
74
+ $this->allowed_domains = apply_filters( 'webp_allowed_domains', $this->allowed_domains );
75
+ $this->debug_message( 'checking any images matching these URLs/patterns for webp: ' . implode( ',', $this->allowed_urls ) );
76
+ $this->debug_message( 'rewriting any images matching these domains to webp: ' . implode( ',', $this->allowed_domains ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
  // Load the appropriate JS.
79
  if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
94
  * @return array A list of WebP domains.
95
  */
96
  function get_webp_domains() {
97
+ return $this->allowed_domains;
98
  }
99
 
100
  /**
207
  function srcset_replace( $srcset ) {
208
  $srcset_urls = explode( ' ', $srcset );
209
  $found_webp = false;
210
+ if ( $this->is_iterable( $srcset_urls ) && count( $srcset_urls ) > 1 ) {
211
  ewwwio_debug_message( 'parsing srcset urls' );
212
  foreach ( $srcset_urls as $srcurl ) {
213
  if ( is_numeric( substr( $srcurl, 0, 1 ) ) ) {
343
  return $buffer;
344
  }
345
 
346
+ $images = $this->get_images_from_html( preg_replace( '/<(picture|noscript).*?\/\1>/s', '', $buffer ), false );
 
 
 
 
347
  if ( ! empty( $images[0] ) && $this->is_iterable( $images[0] ) ) {
348
  foreach ( $images[0] as $index => $image ) {
349
  // Ignore 0-size Pinterest schema images.
470
  } // End foreach().
471
  } // End if().
472
  // Now we will look for any lazy images that don't have a src attribute (this search returns ALL img elements though).
473
+ $images = $this->get_images_from_html( preg_replace( '/<(picture|noscript).*?\/\1>/s', '', $buffer ), false, false );
474
  if ( ! empty( $images[0] ) && $this->is_iterable( $images[0] ) ) {
475
  ewwwio_debug_message( 'parsing images without requiring src' );
476
  foreach ( $images[0] as $index => $image ) {
507
  // Look for images to parse WP Retina Lazy Load.
508
  if ( class_exists( 'Meow_WR2X_Core' ) && strpos( $buffer, ' lazyload' ) ) {
509
  $images = $this->get_elements_from_html( $buffer, 'img' );
510
+ if ( $this->is_iterable( $images ) ) {
511
  foreach ( $images as $index => $image ) {
512
  if ( ! $this->validate_tag( $image ) ) {
513
  continue;
531
  }
532
  }
533
  }
534
+ // Images listed as picture/source elements.
535
  $pictures = $this->get_picture_tags_from_html( $buffer );
536
+ if ( $this->is_iterable( $pictures ) ) {
537
  foreach ( $pictures as $index => $picture ) {
538
  if ( strpos( $picture, 'image/webp' ) ) {
539
  continue;
542
  continue;
543
  }
544
  $sources = $this->get_elements_from_html( $picture, 'source' );
545
+ if ( $this->is_iterable( $sources ) ) {
546
  foreach ( $sources as $source ) {
547
+ $this->debug_message( "parsing a picture source: $source" );
548
  $srcset_attr_name = 'srcset';
549
  if ( false !== strpos( $source, 'base64,R0lGOD' ) && false !== strpos( $source, 'data-srcset=' ) ) {
550
  $srcset_attr_name = 'data-srcset';
560
  }
561
  }
562
  if ( $picture !== $pictures[ $index ] ) {
563
+ $this->debug_message( 'found webp for picture element' );
564
  $buffer = str_replace( $pictures[ $index ], $picture, $buffer );
565
  }
566
  }
568
  }
569
  // NextGEN slides listed as 'a' elements and LL 'a' background images.
570
  $links = $this->get_elements_from_html( $buffer, 'a' );
571
+ if ( $this->is_iterable( $links ) ) {
572
  foreach ( $links as $index => $link ) {
573
  ewwwio_debug_message( "parsing a link $link" );
574
  if ( ! $this->validate_tag( $link ) ) {
604
  }
605
  // Revolution Slider 'li' elements and LL li backgrounds.
606
  $listitems = $this->get_elements_from_html( $buffer, 'li' );
607
+ if ( $this->is_iterable( $listitems ) ) {
608
  foreach ( $listitems as $index => $listitem ) {
609
  ewwwio_debug_message( 'parsing a listitem' );
610
  if ( ! $this->validate_tag( $listitem ) ) {
650
  } // End if().
651
  // WooCommerce thumbs listed as 'div' elements and LL div backgrounds.
652
  $divs = $this->get_elements_from_html( $buffer, 'div' );
653
+ if ( $this->is_iterable( $divs ) ) {
654
  foreach ( $divs as $index => $div ) {
655
  ewwwio_debug_message( 'parsing a div' );
656
  if ( ! $this->validate_tag( $div ) ) {
679
  }
680
  // Look for LL 'section' elements.
681
  $sections = $this->get_elements_from_html( $buffer, 'section' );
682
+ if ( $this->is_iterable( $sections ) ) {
683
  foreach ( $sections as $index => $section ) {
684
  ewwwio_debug_message( 'parsing a section' );
685
  if ( ! $this->validate_tag( $section ) ) {
699
  }
700
  // Look for LL 'span' elements.
701
  $spans = $this->get_elements_from_html( $buffer, 'span' );
702
+ if ( $this->is_iterable( $spans ) ) {
703
  foreach ( $spans as $index => $span ) {
704
  ewwwio_debug_message( 'parsing a span' );
705
  if ( ! $this->validate_tag( $span ) ) {
719
  }
720
  // Video elements, looking for poster attributes that are images.
721
  $videos = $this->get_elements_from_html( $buffer, 'video' );
722
+ if ( $this->is_iterable( $videos ) ) {
723
  foreach ( $videos as $index => $video ) {
724
  ewwwio_debug_message( 'parsing a video element' );
725
  if ( ! $this->validate_tag( $video ) ) {
738
  }
739
  }
740
  }
741
+ $this->debug_message( 'all done parsing page for alt webp' );
742
  return $buffer;
743
  }
744
 
818
  return $variations;
819
  }
820
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
821
  /**
822
  * Converts a URL to a file-system path and checks if the resulting path exists.
823
  *
826
  * @return bool True if a local file exists correlating to the URL, false otherwise.
827
  */
828
  function url_to_path_exists( $url, $extension = '' ) {
 
829
  return parent::url_to_path_exists( $url, '.webp' );
830
  }
831
 
869
  * @return bool False if it flags a filter or exclusion, true otherwise.
870
  */
871
  function validate_tag( $image ) {
872
+ $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
873
  // Ignore 0-size Pinterest schema images.
874
  if ( strpos( $image, 'data-pin-description=' ) && strpos( $image, 'width="0" height="0"' ) ) {
875
  $this->debug_message( 'data-pin-description img skipped' );
925
  if ( ! is_null( $image_path ) && $image_path ) {
926
  $extension = strtolower( pathinfo( $image_path, PATHINFO_EXTENSION ) );
927
  }
928
+ if ( $extension && 'gif' === $extension && ! $this->get_option( 'ewww_image_optimizer_force_gif2webp' ) ) {
929
  return false;
930
  }
931
  if ( $extension && 'svg' === $extension ) {
937
  if ( apply_filters( 'ewww_image_optimizer_skip_webp_rewrite', false, $image ) ) {
938
  return false;
939
  }
940
+ if ( $this->get_option( 'ewww_image_optimizer_webp_force' ) && $this->is_iterable( $this->allowed_urls ) ) {
941
  // Check the image for configured CDN paths.
942
+ foreach ( $this->allowed_urls as $allowed_url ) {
943
+ if ( strpos( $image, $allowed_url ) !== false ) {
944
+ $this->debug_message( 'forced cdn image' );
945
  return true;
946
  }
947
  }
948
+ } elseif ( $this->allowed_urls && $this->allowed_domains ) {
949
  if ( $this->cdn_to_local( $image ) ) {
950
  return true;
951
  }
962
  * @return string The WebP version of the image url.
963
  */
964
  function generate_url( $url ) {
965
+ $path_parts = explode( '?', $url );
966
+ return $path_parts[0] . '.webp' . ( ! empty( $path_parts[1] ) && 'is-pending-load=1' !== $path_parts[1] ? '?' . $path_parts[1] : '' );
 
 
 
 
 
967
  }
968
 
969
  /**
classes/class-eio-base.php CHANGED
@@ -48,6 +48,22 @@ if ( ! class_exists( 'EIO_Base' ) ) {
48
  */
49
  public $home_url = '';
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  /**
52
  * Plugin version for the plugin.
53
  *
@@ -80,6 +96,7 @@ if ( ! class_exists( 'EIO_Base' ) ) {
80
  function __construct( $child_class_path = '' ) {
81
  $this->home_url = trailingslashit( get_site_url() );
82
  $this->relative_home_url = preg_replace( '/https?:/', '', $this->home_url );
 
83
  if ( strpos( $child_class_path, 'plugins/ewww' ) ) {
84
  $this->content_url = content_url( 'ewww/' );
85
  $this->content_dir = WP_CONTENT_DIR . '/ewww/';
@@ -89,17 +106,28 @@ if ( ! class_exists( 'EIO_Base' ) ) {
89
  $this->content_dir = WP_CONTENT_DIR . '/easyio/';
90
  $this->version = EASYIO_VERSION;
91
  $this->prefix = 'easyio_';
92
- } elseif ( strpos( $child_class_path, 'plugins/swis' ) ) {
93
- $this->content_url = content_url( 'swis/' );
94
- $this->content_dir = WP_CONTENT_DIR . '/swis/';
95
- $this->version = SWIS_PLUGIN_VERSION;
96
- $this->prefix = 'swis_';
97
  } else {
98
  $this->content_url = content_url( 'ewww/' );
99
  }
 
 
 
 
 
 
 
 
 
 
 
 
100
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
 
101
  $this->debug_message( "home url: $this->home_url" );
102
  $this->debug_message( "relative home url: $this->relative_home_url" );
 
 
 
103
  }
104
 
105
  /**
@@ -111,7 +139,6 @@ if ( ! class_exists( 'EIO_Base' ) ) {
111
  global $eio_debug;
112
  global $ewwwio_temp_debug;
113
  global $easyio_temp_debug;
114
- global $swis_temp_debug;
115
  $debug_log = $this->content_dir . 'debug.log';
116
  if ( ! is_dir( $this->content_dir ) && is_writable( WP_CONTENT_DIR ) ) {
117
  wp_mkdir_p( $this->content_dir );
@@ -120,7 +147,6 @@ if ( ! class_exists( 'EIO_Base' ) ) {
120
  if (
121
  ! empty( $eio_debug ) &&
122
  empty( $easyio_temp_debug ) &&
123
- empty( $swis_temp_debug ) &&
124
  $debug_enabled &&
125
  is_dir( $this->content_dir ) &&
126
  is_writable( $this->content_dir )
@@ -163,8 +189,7 @@ if ( ! class_exists( 'EIO_Base' ) ) {
163
  }
164
  global $ewwwio_temp_debug;
165
  global $easyio_temp_debug;
166
- global $swis_temp_debug;
167
- if ( $swis_temp_debug || $easyio_temp_debug || $ewwwio_temp_debug || $this->get_option( $this->prefix . 'debug' ) ) {
168
  $memory_limit = $this->memory_limit();
169
  if ( strlen( $message ) + 4000000 + memory_get_usage( true ) <= $memory_limit ) {
170
  global $eio_debug;
@@ -458,6 +483,78 @@ if ( ! class_exists( 'EIO_Base' ) ) {
458
  return $success;
459
  }
460
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
  /**
462
  * Converts a URL to a file-system path and checks if the resulting path exists.
463
  *
@@ -467,12 +564,21 @@ if ( ! class_exists( 'EIO_Base' ) ) {
467
  */
468
  function url_to_path_exists( $url, $extension = '' ) {
469
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
 
 
 
 
 
 
470
  if ( 0 === strpos( $url, WP_CONTENT_URL ) ) {
471
  $path = str_replace( WP_CONTENT_URL, WP_CONTENT_DIR, $url );
 
472
  } elseif ( 0 === strpos( $url, $this->relative_home_url ) ) {
473
  $path = str_replace( $this->relative_home_url, ABSPATH, $url );
 
474
  } elseif ( 0 === strpos( $url, $this->home_url ) ) {
475
  $path = str_replace( $this->home_url, ABSPATH, $url );
 
476
  } else {
477
  $this->debug_message( 'not a valid local image' );
478
  return false;
@@ -485,6 +591,36 @@ if ( ! class_exists( 'EIO_Base' ) ) {
485
  return false;
486
  }
487
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
  /**
489
  * A wrapper for PHP's parse_url, prepending assumed scheme for network path
490
  * URLs. PHP versions 5.4.6 and earlier do not correctly parse without scheme.
@@ -531,9 +667,62 @@ if ( ! class_exists( 'EIO_Base' ) ) {
531
  $s3_domain = $as3cf->get_storage_provider()->get_url_domain( $s3_bucket, $s3_region );
532
  }
533
  if ( ! empty( $s3_domain ) && $as3cf->get_setting( 'serve-from-s3' ) ) {
534
- $this->s3_active = true;
535
  $this->debug_message( "found S3 domain of $s3_domain with bucket $s3_bucket and region $s3_region" );
 
 
 
 
 
 
 
 
 
 
 
 
 
536
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  }
538
 
539
  if ( $this->s3_active ) {
@@ -552,7 +741,46 @@ if ( ! class_exists( 'EIO_Base' ) ) {
552
  }
553
  $this->site_url = defined( 'EXACTDN_LOCAL_DOMAIN' ) && EXACTDN_LOCAL_DOMAIN ? EXACTDN_LOCAL_DOMAIN : $home_url;
554
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
555
  return $this->site_url;
556
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
557
  }
558
  }
48
  */
49
  public $home_url = '';
50
 
51
+ /**
52
+ * Allowed paths for URL mangling.
53
+ *
54
+ * @access protected
55
+ * @var array $allowed_urls
56
+ */
57
+ protected $allowed_urls = array();
58
+
59
+ /**
60
+ * Allowed domains for URL mangling.
61
+ *
62
+ * @access protected
63
+ * @var array $allowed_domains
64
+ */
65
+ protected $allowed_domains = array();
66
+
67
  /**
68
  * Plugin version for the plugin.
69
  *
96
  function __construct( $child_class_path = '' ) {
97
  $this->home_url = trailingslashit( get_site_url() );
98
  $this->relative_home_url = preg_replace( '/https?:/', '', $this->home_url );
99
+ $this->home_domain = $this->parse_url( $this->home_url, PHP_URL_HOST );
100
  if ( strpos( $child_class_path, 'plugins/ewww' ) ) {
101
  $this->content_url = content_url( 'ewww/' );
102
  $this->content_dir = WP_CONTENT_DIR . '/ewww/';
106
  $this->content_dir = WP_CONTENT_DIR . '/easyio/';
107
  $this->version = EASYIO_VERSION;
108
  $this->prefix = 'easyio_';
 
 
 
 
 
109
  } else {
110
  $this->content_url = content_url( 'ewww/' );
111
  }
112
+ /**
113
+ * NOTE: there might, maybe, be cases where the upload URL does not match the detected site URL.
114
+ * If that happens, we'll want to extend $this->content_url() to compensate using the URL from wp_get_site_url().
115
+ *
116
+ * Also, home_url is intended to be a "local" content URL, simply using get_site_url().
117
+ * It is NOT the actual home URL value/setting, which would normally point to the "home" page.
118
+ * The site_url, on the other hand, is intended to be the shortest version of the content/upload URL.
119
+ * Thus it might be different than home_url for a sub-directory install:
120
+ * site_url = https://example.com/ vs. home_url = https://example.com/wordpress/
121
+ * It would also be different if the site is using cloud storage: https://example.s3.amazonaws.com
122
+ */
123
+ $this->content_url();
124
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
125
+ $this->debug_message( "plugin content_url: $this->content_url" );
126
  $this->debug_message( "home url: $this->home_url" );
127
  $this->debug_message( "relative home url: $this->relative_home_url" );
128
+ $this->debug_message( "home domain: $this->home_domain" );
129
+ $this->debug_message( "site/upload url: $this->site_url" );
130
+ $this->debug_message( "site/upload domain: $this->upload_domain" );
131
  }
132
 
133
  /**
139
  global $eio_debug;
140
  global $ewwwio_temp_debug;
141
  global $easyio_temp_debug;
 
142
  $debug_log = $this->content_dir . 'debug.log';
143
  if ( ! is_dir( $this->content_dir ) && is_writable( WP_CONTENT_DIR ) ) {
144
  wp_mkdir_p( $this->content_dir );
147
  if (
148
  ! empty( $eio_debug ) &&
149
  empty( $easyio_temp_debug ) &&
 
150
  $debug_enabled &&
151
  is_dir( $this->content_dir ) &&
152
  is_writable( $this->content_dir )
189
  }
190
  global $ewwwio_temp_debug;
191
  global $easyio_temp_debug;
192
+ if ( $easyio_temp_debug || $ewwwio_temp_debug || $this->get_option( $this->prefix . 'debug' ) ) {
 
193
  $memory_limit = $this->memory_limit();
194
  if ( strlen( $message ) + 4000000 + memory_get_usage( true ) <= $memory_limit ) {
195
  global $eio_debug;
483
  return $success;
484
  }
485
 
486
+ /**
487
+ * Attempts to reverse a CDN (or multi-lingual) URL to a local path to test for file existence.
488
+ *
489
+ * Used for supporting pull-mode CDNs mostly, or push-mode if local copies exist.
490
+ *
491
+ * @param string $url The image URL to mangle.
492
+ * @return string The path to a local file correlating to the CDN URL, an empty string otherwise.
493
+ */
494
+ function cdn_to_local( $url ) {
495
+ $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
496
+ if ( ! $this->is_iterable( $this->allowed_domains ) ) {
497
+ return false;
498
+ }
499
+ if ( 0 === strpos( $url, $this->home_url ) ) {
500
+ $this->debug_message( "$url contains $this->home_url, short-circuiting" );
501
+ return $this->url_to_path_exists( $url );
502
+ }
503
+ foreach ( $this->allowed_domains as $allowed_domain ) {
504
+ if ( $allowed_domain === $this->home_domain ) {
505
+ continue;
506
+ }
507
+ $this->debug_message( "looking for domain $allowed_domain in $url" );
508
+ if (
509
+ ! empty( $this->s3_active ) &&
510
+ false !== strpos( $url, $this->s3_active ) &&
511
+ (
512
+ ( false !== strpos( $this->s3_active, '/' ) ) ||
513
+ ( ! empty( $this->s3_object_prefix ) && false !== strpos( $url, $this->s3_object_prefix ) )
514
+ )
515
+ ) {
516
+ // We will wait until the paths loop to fix this one.
517
+ continue;
518
+ }
519
+ if ( false !== strpos( $url, $allowed_domain ) ) {
520
+ $local_url = str_replace( $allowed_domain, $this->home_domain, $url );
521
+ $this->debug_message( "found $allowed_domain, replaced with $this->home_domain to get $local_url" );
522
+ $path = $this->url_to_path_exists( $local_url );
523
+ if ( $path ) {
524
+ return $path;
525
+ }
526
+ }
527
+ }
528
+ foreach ( $this->allowed_urls as $allowed_url ) {
529
+ if ( false === strpos( $allowed_url, 'http' ) ) {
530
+ continue;
531
+ }
532
+ $this->debug_message( "looking for path $allowed_url in $url" );
533
+ if (
534
+ ! empty( $this->s3_active ) && // We've got an S3 configuration, and...
535
+ false !== strpos( $url, $this->s3_active ) && // the S3 domain is present in the URL, and...
536
+ ! empty( $this->s3_object_prefix ) && // there could be an S3 object prefix to contend with, and...
537
+ 0 === strpos( $url, $allowed_url . $this->s3_object_prefix ) // "allowed_url" + the object prefix matches the URL.
538
+ ) {
539
+ $local_url = str_replace( $allowed_url . $this->s3_object_prefix, $this->upload_url, $url );
540
+ $this->debug_message( "found $allowed_url (and $this->s3_object_prefix), replaced with $this->upload_url to get $local_url" );
541
+ $path = $this->url_to_path_exists( $local_url );
542
+ if ( $path ) {
543
+ return $path;
544
+ }
545
+ }
546
+ if ( false !== strpos( $url, $allowed_url ) ) {
547
+ $local_url = str_replace( $allowed_url, $this->upload_url, $url );
548
+ $this->debug_message( "found $allowed_url, replaced with $this->upload_url to get $local_url" );
549
+ $path = $this->url_to_path_exists( $local_url );
550
+ if ( $path ) {
551
+ return $path;
552
+ }
553
+ }
554
+ }
555
+ return false;
556
+ }
557
+
558
  /**
559
  * Converts a URL to a file-system path and checks if the resulting path exists.
560
  *
564
  */
565
  function url_to_path_exists( $url, $extension = '' ) {
566
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
567
+ $url = $this->maybe_strip_object_version( $url );
568
+ if ( '/' === substr( $url, 0, 1 ) && '/' !== substr( $url, 1, 1 ) ) {
569
+ $this->debug_message( "found relative URL: $url" );
570
+ $url = '//' . $this->upload_domain . $url;
571
+ $this->debug_message( "and changed to $url for path checking" );
572
+ }
573
  if ( 0 === strpos( $url, WP_CONTENT_URL ) ) {
574
  $path = str_replace( WP_CONTENT_URL, WP_CONTENT_DIR, $url );
575
+ $this->debug_message( "trying $path based on " . WP_CONTENT_URL );
576
  } elseif ( 0 === strpos( $url, $this->relative_home_url ) ) {
577
  $path = str_replace( $this->relative_home_url, ABSPATH, $url );
578
+ $this->debug_message( "trying $path based on " . $this->relative_home_url );
579
  } elseif ( 0 === strpos( $url, $this->home_url ) ) {
580
  $path = str_replace( $this->home_url, ABSPATH, $url );
581
+ $this->debug_message( "trying $path based on " . $this->home_url );
582
  } else {
583
  $this->debug_message( 'not a valid local image' );
584
  return false;
591
  return false;
592
  }
593
 
594
+ /**
595
+ * Remove S3 object versioning from URL.
596
+ *
597
+ * @param string $url The image URL with a potential version string embedded.
598
+ * @return string The URL without a version string.
599
+ */
600
+ function maybe_strip_object_version( $url ) {
601
+ if ( ! empty( $this->s3_object_version ) ) {
602
+ $possible_version = basename( dirname( $url ) );
603
+ if (
604
+ ! empty( $possible_version ) &&
605
+ 8 === strlen( $possible_version ) &&
606
+ ctype_digit( $possible_version )
607
+ ) {
608
+ $url = str_replace( '/' . $possible_version . '/', '/', $url );
609
+ $this->debug_message( "removed version $possible_version from $url" );
610
+ } elseif (
611
+ ! empty( $possible_version ) &&
612
+ 14 === strlen( $possible_version ) &&
613
+ ctype_digit( $possible_version )
614
+ ) {
615
+ $year = substr( $possible_version, 0, 4 );
616
+ $month = substr( $possible_version, 4, 2 );
617
+ $url = str_replace( '/' . $possible_version . '/', "/$year/$month/", $url );
618
+ $this->debug_message( "removed version $possible_version from $url" );
619
+ }
620
+ }
621
+ return $url;
622
+ }
623
+
624
  /**
625
  * A wrapper for PHP's parse_url, prepending assumed scheme for network path
626
  * URLs. PHP versions 5.4.6 and earlier do not correctly parse without scheme.
667
  $s3_domain = $as3cf->get_storage_provider()->get_url_domain( $s3_bucket, $s3_region );
668
  }
669
  if ( ! empty( $s3_domain ) && $as3cf->get_setting( 'serve-from-s3' ) ) {
670
+ $this->s3_active = $s3_domain;
671
  $this->debug_message( "found S3 domain of $s3_domain with bucket $s3_bucket and region $s3_region" );
672
+ $this->allowed_urls[] = $s3_scheme . '://' . $s3_domain . '/';
673
+ if ( $as3cf->get_setting( 'enable-delivery-domain' ) && $as3cf->get_setting( 'delivery-domain' ) ) {
674
+ $delivery_domain = $as3cf->get_setting( 'delivery-domain' );
675
+ $this->allowed_urls[] = $s3_scheme . '://' . $delivery_domain . '/';
676
+ $this->allowed_domains[] = $delivery_domain;
677
+ $this->debug_message( "found WOM delivery domain of $delivery_domain" );
678
+ }
679
+ }
680
+ if ( $as3cf->get_setting( 'enable-object-prefix' ) ) {
681
+ $this->s3_object_prefix = $as3cf->get_setting( 'object-prefix' );
682
+ $this->debug_message( $as3cf->get_setting( 'object-prefix' ) );
683
+ } else {
684
+ $this->debug_message( 'no WOM prefix' );
685
  }
686
+ if ( $as3cf->get_setting( 'object-versioning' ) ) {
687
+ $this->s3_object_version = true;
688
+ $this->debug_message( 'object versioning enabled' );
689
+ }
690
+ }
691
+
692
+ if (
693
+ class_exists( 'S3_Uploads' ) &&
694
+ function_exists( 's3_uploads_enabled' ) && s3_uploads_enabled() &&
695
+ method_exists( 'S3_Uploads', 'get_instance' ) && method_exists( 'S3_Uploads', 'get_s3_url' )
696
+ ) {
697
+ $s3_uploads_instance = \S3_Uploads::get_instance();
698
+ $s3_uploads_url = $s3_uploads_instance->get_s3_url();
699
+ $this->allowed_urls[] = $s3_uploads_url;
700
+ $this->debug_message( "found S3 URL from S3_Uploads: $s3_uploads_url" );
701
+ $s3_domain = $this->parse_url( $s3_uploads_url, PHP_URL_HOST );
702
+ $s3_scheme = $this->parse_url( $s3_uploads_url, PHP_URL_SCHEME );
703
+ $this->s3_active = $s3_domain;
704
+ }
705
+
706
+ if ( class_exists( 'wpCloud\StatelessMedia\EWWW' ) && function_exists( 'ud_get_stateless_media' ) ) {
707
+ $sm = ud_get_stateless_media();
708
+ if ( method_exists( $sm, 'get' ) && method_exists( $sm, 'get_gs_host' ) ) {
709
+ $sm_mode = $sm->get( 'sm.mode' );
710
+ if ( 'disabled' !== $sm_mode ) {
711
+ $sm_host = $sm->get_gs_host();
712
+ $this->allowed_urls[] = $sm_host;
713
+ $this->debug_message( "found cloud storage URL from WP Stateless: $sm_host" );
714
+ $s3_domain = $this->parse_url( $sm_host, PHP_URL_HOST );
715
+ $s3_scheme = $this->parse_url( $sm_host, PHP_URL_SCHEME );
716
+ $this->s3_active = $s3_domain;
717
+ }
718
+ }
719
+ }
720
+
721
+ // NOTE: we don't want this for Easy IO as they might be using SWIS to deliver
722
+ // JS/CSS from a different CDN domain, and that will break with Easy IO!
723
+ if ( 'ExactDN' !== get_class( $this ) && 'EIO_Base' !== get_class( $this ) && function_exists( 'swis' ) && swis()->settings->get_option( 'cdn_domain' ) ) {
724
+ $this->allowed_urls[] = swis()->settings->get_option( 'cdn_domain' );
725
+ $this->allowed_domains[] = $this->parse_url( swis()->settings->get_option( 'cdn_domain' ), PHP_URL_HOST );
726
  }
727
 
728
  if ( $this->s3_active ) {
741
  }
742
  $this->site_url = defined( 'EXACTDN_LOCAL_DOMAIN' ) && EXACTDN_LOCAL_DOMAIN ? EXACTDN_LOCAL_DOMAIN : $home_url;
743
  }
744
+ $this->upload_url = $this->site_url;
745
+ $this->upload_domain = $this->parse_url( $this->site_url, PHP_URL_HOST );
746
+ $this->allowed_domains[] = $this->upload_domain;
747
+ // Grab domain aliases that might point to the same place as the upload_domain.
748
+ if ( ! $this->s3_active && 0 !== strpos( $this->upload_domain, 'www' ) ) {
749
+ $this->allowed_domains[] = 'www.' . $this->upload_domain;
750
+ } elseif ( 0 === strpos( $this->upload_domain, 'www.' ) ) {
751
+ $nonwww = ltrim( ltrim( $this->upload_domain, 'w' ), '.' );
752
+ if ( $nonwww && $nonwww !== $this->upload_domain ) {
753
+ $this->allowed_domains[] = $nonwww;
754
+ }
755
+ }
756
+ if ( ! $this->s3_active || 'ExactDN' !== get_class( $this ) ) {
757
+ $wpml_domains = apply_filters( 'wpml_setting', array(), 'language_domains' );
758
+ if ( $this->is_iterable( $wpml_domains ) ) {
759
+ $this->debug_message( 'wpml domains: ' . implode( ',', $wpml_domains ) );
760
+ $this->allowed_domains[] = $this->parse_url( get_option( 'home' ), PHP_URL_HOST );
761
+ $wpml_scheme = $this->parse_url( $this->upload_url, PHP_URL_SCHEME );
762
+ foreach ( $wpml_domains as $wpml_domain ) {
763
+ $this->allowed_domains[] = $wpml_domain;
764
+ $this->allowed_urls[] = $wpml_scheme . '://' . $wpml_domain;
765
+ }
766
+ }
767
+ }
768
  return $this->site_url;
769
  }
770
+
771
+ /**
772
+ * Takes the list of allowed URLs and parses out the domain names.
773
+ */
774
+ function get_allowed_domains() {
775
+ if ( ! $this->is_iterable( $this->allowed_urls ) ) {
776
+ return;
777
+ }
778
+ foreach ( $this->allowed_urls as $allowed_url ) {
779
+ $allowed_domain = $this->parse_url( $allowed_url, PHP_URL_HOST );
780
+ if ( $allowed_domain && ! in_array( $allowed_domain, $this->allowed_domains, true ) ) {
781
+ $this->allowed_domains[] = $allowed_domain;
782
+ }
783
+ }
784
+ }
785
  }
786
  }
classes/class-eio-lazy-load.php CHANGED
@@ -32,6 +32,14 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
32
  */
33
  protected $user_element_exclusions = array();
34
 
 
 
 
 
 
 
 
 
35
  /**
36
  * Base64-encoded placeholder image.
37
  *
@@ -69,8 +77,22 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
69
  */
70
  function __construct() {
71
  parent::__construct( __FILE__ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  $this->piip_folder = $this->content_dir . 'lazy/';
73
- $this->debug_message( 'firing up lazy load' );
74
  global $eio_lazy_load;
75
  if ( is_object( $eio_lazy_load ) ) {
76
  $this->debug_message( 'you are doing it wrong' );
@@ -93,6 +115,9 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
93
  if ( $this->exactdn_domain ) {
94
  $this->parsing_exactdn = true;
95
  $this->debug_message( 'parsing an exactdn page' );
 
 
 
96
  }
97
  $this->allow_lqip = false;
98
  if ( $exactdn->get_plan_id() > 1 ) {
@@ -108,10 +133,11 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
108
  $this->allow_piip = is_writable( $this->piip_folder ) && $this->gd_support();
109
  }
110
 
111
- if ( ! apply_filters( 'wp_lazy_loading_enabled', true, 'img', '' ) ) {
112
- define( 'EWWWIO_DISABLE_NATIVE_LAZY', true );
 
 
113
  }
114
- add_filter( 'wp_lazy_loading_enabled', '__return_false' );
115
 
116
  // Filter early, so that others at the default priority take precendence.
117
  add_filter( 'eio_use_piip', array( $this, 'maybe_piip' ), 9 );
@@ -123,12 +149,14 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
123
  // Load the appropriate JS.
124
  if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
125
  // Load the non-minified and separate versions of the lazy load scripts.
126
- add_action( 'wp_enqueue_scripts', array( $this, 'debug_script' ) );
127
  } else {
128
  // Load the minified, combined version of the lazy load script.
129
- add_action( 'wp_enqueue_scripts', array( $this, 'min_script' ) );
130
  }
131
  $this->validate_user_exclusions();
 
 
132
  }
133
 
134
  /**
@@ -141,6 +169,23 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
141
  return $srcset;
142
  }
143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  /**
145
  * Search for img elements and rewrite them for Lazy Load with fallback to noscript elements.
146
  *
@@ -176,7 +221,6 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
176
  strpos( $uri, '?fl_builder' ) !== false ||
177
  strpos( $uri, 'tatsu=' ) !== false ||
178
  ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === sanitize_text_field( wp_unslash( $_POST['action'] ) ) ) || // phpcs:ignore WordPress.Security.NonceVerification
179
- ! apply_filters( 'eio_do_lazyload', true ) ||
180
  is_embed() ||
181
  is_feed() ||
182
  is_preview() ||
@@ -214,9 +258,6 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
214
  if ( strpos( $uri, 'tatsu=' ) !== false || ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === $_POST['action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
215
  $this->debug_message( 'tatsu' );
216
  }
217
- if ( ! apply_filters( 'eio_do_lazyload', true ) ) {
218
- $this->debug_message( 'do_lazyload short-circuit' );
219
- }
220
  if ( is_embed() ) {
221
  $this->debug_message( 'is_embed' );
222
  }
@@ -288,6 +329,24 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
288
  if ( ! $this->validate_image_tag( $picture ) ) {
289
  continue;
290
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
  $sources = $this->get_elements_from_html( $picture, 'source' );
292
  if ( $this->is_iterable( $sources ) ) {
293
  foreach ( $sources as $source ) {
@@ -300,29 +359,15 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
300
  $this->debug_message( 'found srcset in source' );
301
  $lazy_source = $source;
302
  $this->set_attribute( $lazy_source, 'data-srcset', $srcset );
303
- $this->set_attribute( $lazy_source, 'srcset', $this->placeholder_src, true );
 
 
304
  $picture = str_replace( $source, $lazy_source, $picture );
305
  }
306
  }
307
  if ( $picture !== $pictures[ $index ] ) {
308
- $pimages = $this->get_images_from_html( $picture, false );
309
- if ( ! empty( $pimages[0] ) && $this->is_iterable( $pimages[0] ) && ! empty( $pimages[0][0] ) ) {
310
- $image = $pimages[0][0];
311
- $file = $pimages['img_url'][0];
312
- $this->debug_message( "parsing an image: $file" );
313
- $this->debug_message( "the img tag: $image" );
314
- if ( $this->validate_image_tag( $image ) ) {
315
- $this->debug_message( 'found a valid image tag (inside picture)' );
316
- $orig_img = $image;
317
- $ns_img = $image;
318
- $image = $this->parse_img_tag( $image, $file );
319
- $this->set_attribute( $ns_img, 'data-eio', 'l', true );
320
- $noscript = '<noscript>' . $ns_img . '</noscript>';
321
- $picture = str_replace( $orig_img, $image . $noscript, $picture );
322
- $this->debug_message( 'lazified sources for picture element' );
323
- $buffer = str_replace( $pictures[ $index ], $picture, $buffer );
324
- }
325
- }
326
  }
327
  }
328
  }
@@ -381,76 +426,122 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
381
  return $image;
382
  }
383
 
 
 
384
  $width_attr = $this->get_attribute( $image, 'width' );
385
  $height_attr = $this->get_attribute( $image, 'height' );
 
 
 
 
 
386
  $placeholder_src = $this->placeholder_src;
387
 
388
- $disable_native_lazy = false;
389
- // Ignore native lazy loading images.
390
- $loading_attr = $this->get_attribute( $image, 'loading' );
391
- if ( $loading_attr && in_array( trim( $loading_attr ), array( 'auto', 'eager', 'lazy' ), true ) ) {
392
- $disable_native_lazy = true;
 
 
 
 
 
393
  }
394
- if (
395
- is_numeric( $width_attr ) && is_numeric( $height_attr ) &&
396
- ( ! defined( 'EWWWIO_DISABLE_NATIVE_LAZY' ) || ! EWWWIO_DISABLE_NATIVE_LAZY ) &&
397
- ( ! defined( 'EASYIO_DISABLE_NATIVE_LAZY' ) || ! EASYIO_DISABLE_NATIVE_LAZY ) &&
398
- ! $disable_native_lazy
399
- ) {
400
  $this->set_attribute( $image, 'loading', 'lazy' );
401
  }
402
 
403
- if ( false === strpos( $file, 'nggid' ) && ! preg_match( '#\.svg(\?|$)#', $file ) && $this->parsing_exactdn && strpos( $file, $this->exactdn_domain ) ) {
404
- $this->debug_message( 'using lqip' );
405
- list( $width, $height ) = $this->get_dimensions_from_filename( $file, true );
406
- if ( $width && $height && $width < 201 && $height < 201 ) {
407
- $placeholder_src = $exactdn->generate_url( $this->content_url . 'lazy/placeholder-' . $width . 'x' . $height . '.png' );
408
- } elseif ( $this->allow_lqip && apply_filters( 'eio_use_lqip', $this->get_option( $this->prefix . 'use_lqip' ), $file ) ) {
409
- $placeholder_src = add_query_arg( array( 'lazy' => 1 ), $file );
410
- } elseif ( $width && $height ) {
411
- $placeholder_src = $exactdn->generate_url( $this->content_url . 'lazy/placeholder-' . $width . 'x' . $height . '.png' );
412
- } else {
413
- $placeholder_src = add_query_arg( array( 'lazy' => 2 ), $file );
414
- }
415
- } elseif ( $this->allow_piip && $srcset && apply_filters( 'eio_use_piip', true, $file ) ) {
416
- $this->debug_message( 'trying piip' );
417
- // Get image dimensions for PNG placeholder.
418
- list( $width, $height ) = $this->get_dimensions_from_filename( $file, $this->parsing_exactdn );
419
 
420
- // Can't use a relative width or height, so unset the dimensions in favor of not breaking things.
421
- if ( false !== strpos( $width_attr, '%' ) || false !== strpos( $height_attr, '%' ) ) {
422
- $width_attr = false;
423
- $height_attr = false;
424
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
 
426
- if ( false === $width || false === $height ) {
427
- $width = $width_attr;
428
- $height = $height_attr;
429
- }
 
 
 
 
 
 
 
 
 
 
 
430
 
431
- // Falsify them if empty.
432
- $width = $width ? (int) $width : false;
433
- $height = $height ? (int) $height : false;
434
- if ( $width && $height ) {
435
- $this->debug_message( "creating piip of $width x $height" );
436
- $placeholder_src = $this->create_piip( $width, $height );
437
- }
438
- } elseif ( apply_filters( 'eio_use_siip', true, $file ) ) {
439
- $this->debug_message( 'trying siip' );
440
- $width = $width_attr;
441
- $height = $height_attr;
442
 
443
- // Can't use a relative width or height, so unset the dimensions in favor of not breaking things.
444
- if ( false !== strpos( $width, '%' ) || false !== strpos( $height, '%' ) ) {
445
- $width = false;
446
- $height = false;
447
- }
448
 
449
- // Falsify them if empty.
450
- $width = $width ? (int) $width : false;
451
- $height = $height ? (int) $height : false;
452
- if ( $width && $height ) {
453
- $placeholder_src = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 $width $height'%3E%3C/svg%3E";
 
 
 
 
 
 
 
 
 
454
  }
455
  }
456
  $this->debug_message( "current placeholder is $placeholder_src" );
@@ -461,7 +552,6 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
461
  $this->set_attribute( $image, 'srcset', $placeholder_src, true );
462
  $this->remove_attribute( $image, 'src' );
463
  } else {
464
- $placeholder_src = apply_filters( 'as3cf_get_asset', $placeholder_src );
465
  $this->set_attribute( $image, 'src', $placeholder_src, true );
466
  $this->remove_attribute( $image, 'srcset' );
467
  }
@@ -481,7 +571,20 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
481
  $this->set_attribute( $image, 'src', $placeholder_src, true );
482
  }
483
 
484
- $this->set_attribute( $image, 'class', $this->get_attribute( $image, 'class' ) . ' lazyload', true );
 
 
 
 
 
 
 
 
 
 
 
 
 
485
  return $image;
486
  }
487
 
@@ -497,14 +600,12 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
497
  if ( in_array( $tag_type, $this->user_element_exclusions, true ) ) {
498
  return $buffer;
499
  }
500
- $elements = $this->get_elements_from_html( $buffer, $tag_type );
501
  if ( $this->is_iterable( $elements ) ) {
502
  foreach ( $elements as $index => $element ) {
503
  $this->debug_message( "parsing a $tag_type" );
504
  if ( false === strpos( $element, 'background:' ) && false === strpos( $element, 'background-image:' ) ) {
505
- if ( 'div' === $tag_type ) {
506
- $element = $this->lazify_element( $element );
507
- }
508
  if ( $element !== $elements[ $index ] ) {
509
  $this->debug_message( "$tag_type lazified, replacing in html source" );
510
  $buffer = str_replace( $elements[ $index ], $element, $buffer );
@@ -553,8 +654,10 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
553
  }
554
  if ( false === strpos( $element, 'background:' ) && false === strpos( $element, 'background-image:' ) && false === strpos( $element, 'style=' ) ) {
555
  if ( false !== strpos( $element, 'id=' ) || false !== strpos( $element, 'class=' ) ) {
556
- if ( $this->validate_bgimage_tag( $element ) ) {
557
- $this->set_attribute( $element, 'class', $this->get_attribute( $element, 'class' ) . ' lazyload', true );
 
 
558
  }
559
  }
560
  }
@@ -593,6 +696,31 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
593
  }
594
  }
595
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
596
  /**
597
  * Checks if the tag is allowed to be lazy loaded.
598
  *
@@ -641,6 +769,7 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
641
  'data-lazy-srcset=',
642
  'data-lazyload=',
643
  'data-lazysrc=',
 
644
  'data-no-lazy=',
645
  'data-src=',
646
  'data-srcset=',
@@ -839,12 +968,14 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
839
  if ( defined( strtoupper( $this->prefix ) . 'LAZY_PRINT' ) && constant( strtoupper( $this->prefix ) . 'LAZY_PRINT' ) ) {
840
  wp_enqueue_script( 'eio-lazy-load-print', plugins_url( '/includes/ls.print.js', $plugin_file ), array(), $this->version );
841
  }
 
842
  wp_localize_script(
843
  'eio-lazy-load',
844
  'eio_lazy_vars',
845
  array(
846
  'exactdn_domain' => ( $this->parsing_exactdn ? $this->exactdn_domain : '' ),
847
- 'skip_autoscale' => ( defined( 'EIO_LL_AUTOSCALE' ) ? 1 : 0 ),
 
848
  )
849
  );
850
  }
@@ -867,7 +998,7 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
867
  'eio_lazy_vars',
868
  array(
869
  'exactdn_domain' => ( $this->parsing_exactdn ? $this->exactdn_domain : '' ),
870
- 'skip_autoscale' => ( defined( 'EIO_LL_AUTOSCALE' ) ? 1 : 0 ),
871
  )
872
  );
873
  }
32
  */
33
  protected $user_element_exclusions = array();
34
 
35
+ /**
36
+ * A list of user-defined inclusions to lazy load for "external" CSS background images.
37
+ *
38
+ * @access protected
39
+ * @var array $css_element_inclusions
40
+ */
41
+ protected $css_element_inclusions = array();
42
+
43
  /**
44
  * Base64-encoded placeholder image.
45
  *
77
  */
78
  function __construct() {
79
  parent::__construct( __FILE__ );
80
+ $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
81
+
82
+ $uri = add_query_arg( null, null );
83
+ $this->debug_message( "request uri is $uri" );
84
+
85
+ /**
86
+ * Allow pre-empting Lazy Load by page.
87
+ *
88
+ * @param bool Whether to parse the page for images to lazy load, default true.
89
+ * @param string $uri The URL of the page.
90
+ */
91
+ if ( ! apply_filters( 'eio_do_lazyload', true, $uri ) ) {
92
+ return;
93
+ }
94
+
95
  $this->piip_folder = $this->content_dir . 'lazy/';
 
96
  global $eio_lazy_load;
97
  if ( is_object( $eio_lazy_load ) ) {
98
  $this->debug_message( 'you are doing it wrong' );
115
  if ( $this->exactdn_domain ) {
116
  $this->parsing_exactdn = true;
117
  $this->debug_message( 'parsing an exactdn page' );
118
+ $this->allowed_urls[] = 'https://' . $this->exactdn_domain;
119
+ $this->allowed_urls[] = 'http://' . $this->exactdn_domain;
120
+ $this->allowed_urls[] = '//' . $this->exactdn_domain;
121
  }
122
  $this->allow_lqip = false;
123
  if ( $exactdn->get_plan_id() > 1 ) {
133
  $this->allow_piip = is_writable( $this->piip_folder ) && $this->gd_support();
134
  }
135
 
136
+ add_filter( 'wp_lazy_loading_enabled', array( $this, 'wp_lazy_loading_enabled' ), 10, 2 );
137
+
138
+ if ( ! defined( 'EIO_LL_AUTOSCALE' ) && ! $this->get_option( $this->prefix . 'll_autoscale' ) ) {
139
+ define( 'EIO_LL_AUTOSCALE', false );
140
  }
 
141
 
142
  // Filter early, so that others at the default priority take precendence.
143
  add_filter( 'eio_use_piip', array( $this, 'maybe_piip' ), 9 );
149
  // Load the appropriate JS.
150
  if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
151
  // Load the non-minified and separate versions of the lazy load scripts.
152
+ add_action( 'wp_enqueue_scripts', array( $this, 'debug_script' ), 1 );
153
  } else {
154
  // Load the minified, combined version of the lazy load script.
155
+ add_action( 'wp_enqueue_scripts', array( $this, 'min_script' ), 1 );
156
  }
157
  $this->validate_user_exclusions();
158
+ $this->validate_css_element_inclusions();
159
+ $this->get_allowed_domains();
160
  }
161
 
162
  /**
169
  return $srcset;
170
  }
171
 
172
+ /**
173
+ * Disable native lazy load for img elements.
174
+ *
175
+ * @param bool $default True if it is an img or iframe element. Should be false otherwise.
176
+ * @param string $tag_name The type of HTML tag/element being parsed.
177
+ * @return bool False for img elements, leave as-is for others.
178
+ */
179
+ function wp_lazy_loading_enabled( $default, $tag_name ) {
180
+ if ( 'img' === $tag_name ) {
181
+ if ( defined( 'EIO_ENABLE_NATIVE_LAZY' ) && EIO_ENABLE_NATIVE_LAZY ) {
182
+ return true;
183
+ }
184
+ return false;
185
+ }
186
+ return $default;
187
+ }
188
+
189
  /**
190
  * Search for img elements and rewrite them for Lazy Load with fallback to noscript elements.
191
  *
221
  strpos( $uri, '?fl_builder' ) !== false ||
222
  strpos( $uri, 'tatsu=' ) !== false ||
223
  ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === sanitize_text_field( wp_unslash( $_POST['action'] ) ) ) || // phpcs:ignore WordPress.Security.NonceVerification
 
224
  is_embed() ||
225
  is_feed() ||
226
  is_preview() ||
258
  if ( strpos( $uri, 'tatsu=' ) !== false || ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === $_POST['action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
259
  $this->debug_message( 'tatsu' );
260
  }
 
 
 
261
  if ( is_embed() ) {
262
  $this->debug_message( 'is_embed' );
263
  }
329
  if ( ! $this->validate_image_tag( $picture ) ) {
330
  continue;
331
  }
332
+ $pimages = $this->get_images_from_html( $picture, false );
333
+ if ( ! empty( $pimages[0] ) && $this->is_iterable( $pimages[0] ) && ! empty( $pimages[0][0] ) ) {
334
+ $image = $pimages[0][0];
335
+ $file = $pimages['img_url'][0];
336
+ $this->debug_message( "parsing an image (inside picture): $file" );
337
+ $this->debug_message( "the img tag: $image" );
338
+ if ( $this->validate_image_tag( $image ) ) {
339
+ $this->debug_message( 'found a valid image tag (inside picture)' );
340
+ $orig_img = $image;
341
+ $ns_img = $image;
342
+ $image = $this->parse_img_tag( $image, $file );
343
+ $this->set_attribute( $ns_img, 'data-eio', 'l', true );
344
+ $noscript = '<noscript>' . $ns_img . '</noscript>';
345
+ $picture = str_replace( $orig_img, $image . $noscript, $picture );
346
+ }
347
+ } else {
348
+ continue;
349
+ }
350
  $sources = $this->get_elements_from_html( $picture, 'source' );
351
  if ( $this->is_iterable( $sources ) ) {
352
  foreach ( $sources as $source ) {
359
  $this->debug_message( 'found srcset in source' );
360
  $lazy_source = $source;
361
  $this->set_attribute( $lazy_source, 'data-srcset', $srcset );
362
+ $this->remove_attribute( $lazy_source, 'srcset' );
363
+ // TODO: remove this after testing.
364
+ /* $this->set_attribute( $lazy_source, 'srcset', $this->placeholder_src, true ); */
365
  $picture = str_replace( $source, $lazy_source, $picture );
366
  }
367
  }
368
  if ( $picture !== $pictures[ $index ] ) {
369
+ $this->debug_message( 'lazified sources for picture element' );
370
+ $buffer = str_replace( $pictures[ $index ], $picture, $buffer );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371
  }
372
  }
373
  }
426
  return $image;
427
  }
428
 
429
+ $physical_width = false;
430
+ $physical_height = false;
431
  $width_attr = $this->get_attribute( $image, 'width' );
432
  $height_attr = $this->get_attribute( $image, 'height' );
433
+ // Can't use a relative width or height, so unset the dimensions in favor of not breaking things.
434
+ if ( false !== strpos( $width_attr, '%' ) || false !== strpos( $height_attr, '%' ) ) {
435
+ $width_attr = false;
436
+ $height_attr = false;
437
+ }
438
  $placeholder_src = $this->placeholder_src;
439
 
440
+ $insert_dimensions = false;
441
+ if ( apply_filters( 'eio_add_missing_width_height_attrs', true ) && ( empty( $width_attr ) || empty( $height_attr ) ) ) {
442
+ $this->debug_message( 'missing width attr or height attr' );
443
+ list( $width_attr, $height_attr ) = $this->get_image_dimensions_by_url( $file );
444
+ if ( $width_attr && is_numeric( $width_attr ) && $height_attr && is_numeric( $height_attr ) ) {
445
+ $this->debug_message( "found $width_attr and $height_attr to insert" );
446
+ $physical_width = $width_attr;
447
+ $physical_height = $height_attr;
448
+ $insert_dimensions = true;
449
+ }
450
  }
451
+ // Check for native lazy loading images.
452
+ $loading_attr = $this->get_attribute( $image, 'loading' );
453
+ if ( defined( 'EIO_ENABLE_NATIVE_LAZY' ) && EIO_ENABLE_NATIVE_LAZY && ! $loading_attr && is_numeric( $width_attr ) && is_numeric( $height_attr ) ) {
 
 
 
454
  $this->set_attribute( $image, 'loading', 'lazy' );
455
  }
456
 
457
+ $placeholder_types = array();
458
+ if ( $this->parsing_exactdn && $this->allow_lqip && apply_filters( 'eio_use_lqip', $this->get_option( $this->prefix . 'use_lqip' ), $file ) ) {
459
+ $placeholder_types[] = 'lqip';
460
+ }
461
+ if ( apply_filters( 'eio_use_siip', $this->get_option( $this->prefix . 'use_siip' ), $file ) ) {
462
+ $placeholder_types[] = 'siip';
463
+ }
464
+ if ( $this->parsing_exactdn && apply_filters( 'eio_use_piip', true, $file ) ) {
465
+ $placeholder_types[] = 'epip';
466
+ }
467
+ if ( $this->allow_piip && apply_filters( 'eio_use_piip', true, $file ) ) {
468
+ $placeholder_types[] = 'piip';
469
+ }
 
 
 
470
 
471
+ list( $filename_width, $filename_height ) = $this->get_dimensions_from_filename( $file, $this->parsing_exactdn );
472
+ if ( $filename_width && is_numeric( $filename_width ) && $filename_height && is_numeric( $filename_height ) ) {
473
+ $physical_width = $filename_width;
474
+ $physical_height = $filename_height;
475
+ } elseif (
476
+ ( ! $physical_width || ! $physical_height ) &&
477
+ $width_attr && is_numeric( $width_attr ) && $height_attr && is_numeric( $height_attr )
478
+ ) {
479
+ $physical_width = $width_attr;
480
+ $physical_height = $height_attr;
481
+ }
482
+ foreach ( $placeholder_types as $placeholder_type ) {
483
+ switch ( $placeholder_type ) {
484
+ case 'lqip':
485
+ $this->debug_message( 'using lqip, maybe' );
486
+ if ( false === strpos( $file, 'nggid' ) && ! preg_match( '#\.svg(\?|$)#', $file ) && strpos( $file, $this->exactdn_domain ) ) {
487
+ $placeholder_src = add_query_arg( array( 'lazy' => 1 ), $file );
488
+ break 2;
489
+ }
490
+ break;
491
+ case 'siip':
492
+ $this->debug_message( 'trying siip' );
493
+ // Can't use a relative width or height, so unset the dimensions in favor of not breaking things.
494
+ if ( false !== strpos( $width_attr, '%' ) || false !== strpos( $height_attr, '%' ) ) {
495
+ break;
496
+ }
497
 
498
+ // Falsify them if empty.
499
+ $width_attr = (int) $width_attr ? (int) $width_attr : false;
500
+ $height_attr = (int) $height_attr ? (int) $height_attr : false;
501
+ if ( $width_attr && $height_attr ) {
502
+ $placeholder_src = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 $width_attr $height_attr'%3E%3C/svg%3E";
503
+ break 2;
504
+ }
505
+ break;
506
+ case 'epip':
507
+ $this->debug_message( 'using epip, maybe' );
508
+ if ( false === strpos( $file, 'nggid' ) && ! preg_match( '#\.svg(\?|$)#', $file ) && strpos( $file, $this->exactdn_domain ) ) {
509
+ if ( false === $filename_width || false === $filename_height ) {
510
+ $filename_width = $width_attr;
511
+ $filename_height = $height_attr;
512
+ }
513
 
514
+ if ( $filename_width && $filename_height ) {
515
+ $placeholder_src = $exactdn->generate_url( $this->content_url . 'lazy/placeholder-' . $filename_width . 'x' . $filename_height . '.png' );
516
+ break 2;
517
+ } else {
518
+ $placeholder_src = add_query_arg( array( 'lazy' => 2 ), $file );
519
+ break 2;
520
+ }
521
+ }
522
+ break;
523
+ case 'piip':
524
+ $this->debug_message( 'trying piip' );
525
 
526
+ if ( false === $filename_width || false === $filename_height ) {
527
+ $filename_width = $width_attr;
528
+ $filename_height = $height_attr;
529
+ }
 
530
 
531
+ // Falsify them if empty.
532
+ $filename_width = (int) $filename_width ? (int) $filename_width : false;
533
+ $filename_height = (int) $filename_height ? (int) $filename_height : false;
534
+ if ( $filename_width && $filename_height ) {
535
+ $this->debug_message( "creating piip of $filename_width x $filename_height" );
536
+ $png_placeholder_src = $this->create_piip( $filename_width, $filename_height );
537
+ if ( $png_placeholder_src ) {
538
+ $placeholder_src = $png_placeholder_src;
539
+ break 2;
540
+ }
541
+ }
542
+ break;
543
+ default:
544
+ $this->debug_message( "what in the world is $placeholder_type?" );
545
  }
546
  }
547
  $this->debug_message( "current placeholder is $placeholder_src" );
552
  $this->set_attribute( $image, 'srcset', $placeholder_src, true );
553
  $this->remove_attribute( $image, 'src' );
554
  } else {
 
555
  $this->set_attribute( $image, 'src', $placeholder_src, true );
556
  $this->remove_attribute( $image, 'srcset' );
557
  }
571
  $this->set_attribute( $image, 'src', $placeholder_src, true );
572
  }
573
 
574
+ $existing_class = trim( $this->get_attribute( $image, 'class' ) );
575
+ if ( ! empty( $existing_class ) ) {
576
+ $this->set_attribute( $image, 'class', $existing_class . ' lazyload', true );
577
+ } else {
578
+ $this->set_attribute( $image, 'class', 'lazyload', true );
579
+ }
580
+ if ( $insert_dimensions ) {
581
+ $this->set_attribute( $image, 'width', $width_attr, true );
582
+ $this->set_attribute( $image, 'height', $height_attr, true );
583
+ }
584
+ if ( 0 === strpos( $placeholder_src, 'data:image/svg+xml' ) ) {
585
+ $this->set_attribute( $image, 'data-eio-rwidth', $physical_width, true );
586
+ $this->set_attribute( $image, 'data-eio-rheight', $physical_height, true );
587
+ }
588
  return $image;
589
  }
590
 
600
  if ( in_array( $tag_type, $this->user_element_exclusions, true ) ) {
601
  return $buffer;
602
  }
603
+ $elements = $this->get_elements_from_html( preg_replace( '/<(noscript|script).*?\/\1>/s', '', $buffer ), $tag_type );
604
  if ( $this->is_iterable( $elements ) ) {
605
  foreach ( $elements as $index => $element ) {
606
  $this->debug_message( "parsing a $tag_type" );
607
  if ( false === strpos( $element, 'background:' ) && false === strpos( $element, 'background-image:' ) ) {
608
+ $element = $this->lazify_element( $element );
 
 
609
  if ( $element !== $elements[ $index ] ) {
610
  $this->debug_message( "$tag_type lazified, replacing in html source" );
611
  $buffer = str_replace( $elements[ $index ], $element, $buffer );
654
  }
655
  if ( false === strpos( $element, 'background:' ) && false === strpos( $element, 'background-image:' ) && false === strpos( $element, 'style=' ) ) {
656
  if ( false !== strpos( $element, 'id=' ) || false !== strpos( $element, 'class=' ) ) {
657
+ foreach ( $this->css_element_inclusions as $inclusion ) {
658
+ if ( false !== strpos( $element, $inclusion ) && $this->validate_bgimage_tag( $element ) ) {
659
+ $this->set_attribute( $element, 'class', $this->get_attribute( $element, 'class' ) . ' lazyload', true );
660
+ }
661
  }
662
  }
663
  }
696
  }
697
  }
698
 
699
+ /**
700
+ * Validate the user-defined CSS element inclusions.
701
+ */
702
+ function validate_css_element_inclusions() {
703
+ $user_inclusions = $this->get_option( $this->prefix . 'll_all_things' );
704
+ if ( ! empty( $user_inclusions ) ) {
705
+ if ( ! is_string( $user_inclusions ) ) {
706
+ return;
707
+ }
708
+ $user_inclusions = explode( ',', $user_inclusions );
709
+ if ( is_array( $user_inclusions ) ) {
710
+ foreach ( $user_inclusions as $inclusion ) {
711
+ if ( ! is_string( $inclusion ) ) {
712
+ continue;
713
+ }
714
+ $inclusion = trim( $inclusion );
715
+ if ( empty( $inclusion ) ) {
716
+ continue;
717
+ }
718
+ $this->css_element_inclusions[] = $inclusion;
719
+ }
720
+ }
721
+ }
722
+ }
723
+
724
  /**
725
  * Checks if the tag is allowed to be lazy loaded.
726
  *
769
  'data-lazy-srcset=',
770
  'data-lazyload=',
771
  'data-lazysrc=',
772
+ 'data-mk-image-src',
773
  'data-no-lazy=',
774
  'data-src=',
775
  'data-srcset=',
968
  if ( defined( strtoupper( $this->prefix ) . 'LAZY_PRINT' ) && constant( strtoupper( $this->prefix ) . 'LAZY_PRINT' ) ) {
969
  wp_enqueue_script( 'eio-lazy-load-print', plugins_url( '/includes/ls.print.js', $plugin_file ), array(), $this->version );
970
  }
971
+ $threshold = defined( 'EIO_LL_THRESHOLD' ) && EIO_LL_THRESHOLD ? EIO_LL_THRESHOLD : 0;
972
  wp_localize_script(
973
  'eio-lazy-load',
974
  'eio_lazy_vars',
975
  array(
976
  'exactdn_domain' => ( $this->parsing_exactdn ? $this->exactdn_domain : '' ),
977
+ 'skip_autoscale' => ( defined( 'EIO_LL_AUTOSCALE' ) && ! EIO_LL_AUTOSCALE ? 1 : 0 ),
978
+ 'threshold' => (int) $threshold > 50 ? (int) $threshold : 0,
979
  )
980
  );
981
  }
998
  'eio_lazy_vars',
999
  array(
1000
  'exactdn_domain' => ( $this->parsing_exactdn ? $this->exactdn_domain : '' ),
1001
+ 'skip_autoscale' => ( defined( 'EIO_LL_AUTOSCALE' ) && ! EIO_LL_AUTOSCALE ? 1 : 0 ),
1002
  )
1003
  );
1004
  }
classes/class-eio-page-parser.php CHANGED
@@ -221,6 +221,36 @@ if ( ! class_exists( 'EIO_Page_Parser' ) ) {
221
  return array( $width_param, $height_param ); // These may be false, unless URL parameters were found.
222
  }
223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  /**
225
  * Get the width from an image element.
226
  *
221
  return array( $width_param, $height_param ); // These may be false, unless URL parameters were found.
222
  }
223
 
224
+ /**
225
+ * Get dimensions of a file from the URL.
226
+ *
227
+ * @param string $url The URL of the image.
228
+ * @return array The width and height, in pixels.
229
+ */
230
+ function get_image_dimensions_by_url( $url ) {
231
+ $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
232
+ $this->debug_message( "getting dimensions for $url" );
233
+
234
+ list( $width, $height ) = $this->get_dimensions_from_filename( $url );
235
+ if ( empty( $width ) || empty( $height ) ) {
236
+ // Couldn't get it from the URL directly, see if we can get the actual filename.
237
+ $file = false;
238
+ if ( $this->allowed_urls && $this->allowed_domains ) {
239
+ $file = $this->cdn_to_local( $url );
240
+ }
241
+ if ( ! $file ) {
242
+ $file = $this->url_to_path_exists( $url );
243
+ }
244
+ if ( $file && $this->is_file( $file ) ) {
245
+ list( $width, $height ) = getimagesize( $file );
246
+ }
247
+ }
248
+ $width = $width && is_numeric( $width ) ? (int) $width : false;
249
+ $height = $height && is_numeric( $height ) ? (int) $height : false;
250
+
251
+ return array( $width, $height );
252
+ }
253
+
254
  /**
255
  * Get the width from an image element.
256
  *
classes/class-eio-picture-webp.php CHANGED
@@ -31,22 +31,6 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
31
  */
32
  protected $user_element_exclusions = array();
33
 
34
- /**
35
- * Allowed paths for Picture WebP.
36
- *
37
- * @access protected
38
- * @var array $webp_paths
39
- */
40
- protected $webp_paths = array();
41
-
42
- /**
43
- * Allowed domains for Picture WebP.
44
- *
45
- * @access protected
46
- * @var array $webp_domains
47
- */
48
- protected $webp_domains = array();
49
-
50
  /**
51
  * Register (once) actions and filters for Picture WebP.
52
  */
@@ -58,6 +42,8 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
58
  if ( ewww_image_optimizer_ce_webp_enabled() ) {
59
  return false;
60
  }
 
 
61
 
62
  // Make sure gallery block images crop properly.
63
  add_action( 'wp_head', array( $this, 'gallery_block_css' ) );
@@ -68,92 +54,17 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
68
  add_filter( 'ewww_image_optimizer_filter_page_output', array( $this, 'filter_page_output' ), 10 );
69
  }
70
 
71
- $this->home_url = trailingslashit( get_site_url() );
72
- ewwwio_debug_message( "home url: $this->home_url" );
73
- $this->relative_home_url = preg_replace( '/https?:/', '', $this->home_url );
74
- ewwwio_debug_message( "relative home url: $this->relative_home_url" );
75
- $upload_dir = wp_get_upload_dir();
76
- $this->content_url = trailingslashit( ! empty( $upload_dir['baseurl'] ) ? $upload_dir['baseurl'] : content_url( 'uploads' ) );
77
- ewwwio_debug_message( "content_url: $this->content_url" );
78
- $this->home_domain = $this->parse_url( $this->home_url, PHP_URL_HOST );
79
- ewwwio_debug_message( "home domain: $this->home_domain" );
80
-
81
- $this->webp_paths = ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_paths' );
82
- if ( ! is_array( $this->webp_paths ) ) {
83
- $this->webp_paths = array();
84
  }
85
 
86
- // Find the WP Offload Media domain/path.
87
- if ( class_exists( 'Amazon_S3_And_CloudFront' ) ) {
88
- global $as3cf;
89
- $s3_scheme = $as3cf->get_url_scheme();
90
- $s3_bucket = $as3cf->get_setting( 'bucket' );
91
- $s3_region = $as3cf->get_setting( 'region' );
92
- if ( is_wp_error( $s3_region ) ) {
93
- $s3_region = '';
94
- }
95
- if ( ! empty( $s3_bucket ) && ! is_wp_error( $s3_bucket ) && method_exists( $as3cf, 'get_provider' ) ) {
96
- $s3_domain = $as3cf->get_provider()->get_url_domain( $s3_bucket, $s3_region, null, array(), true );
97
- } elseif ( ! empty( $s3_bucket ) && ! is_wp_error( $s3_bucket ) && method_exists( $as3cf, 'get_storage_provider' ) ) {
98
- $s3_domain = $as3cf->get_storage_provider()->get_url_domain( $s3_bucket, $s3_region );
99
- }
100
- if ( ! empty( $s3_domain ) && $as3cf->get_setting( 'serve-from-s3' ) ) {
101
- $this->debug_message( "found S3 domain of $s3_domain with bucket $s3_bucket and region $s3_region" );
102
- $this->webp_paths[] = $s3_scheme . '://' . $s3_domain . '/';
103
- if ( $as3cf->get_setting( 'enable-delivery-domain' ) && $as3cf->get_setting( 'delivery-domain' ) ) {
104
- $delivery_domain = $as3cf->get_setting( 'delivery-domain' );
105
- $this->webp_paths[] = $s3_scheme . '://' . $delivery_domain . '/';
106
- $this->debug_message( "found WOM delivery domain of $delivery_domain" );
107
- }
108
- $this->s3_active = $s3_domain;
109
- if ( $as3cf->get_setting( 'enable-object-prefix' ) ) {
110
- $this->s3_object_prefix = $as3cf->get_setting( 'object-prefix' );
111
- $this->debug_message( $as3cf->get_setting( 'object-prefix' ) );
112
- } else {
113
- $this->debug_message( 'no WOM prefix' );
114
- }
115
- if ( $as3cf->get_setting( 'object-versioning' ) ) {
116
- $this->s3_object_version = true;
117
- $this->debug_message( 'object versioning enabled' );
118
- }
119
- }
120
- }
121
 
122
- if (
123
- class_exists( 'S3_Uploads' ) &&
124
- function_exists( 's3_uploads_enabled' ) && s3_uploads_enabled() &&
125
- method_exists( 'S3_Uploads', 'get_instance' ) && method_exists( 'S3_Uploads', 'get_s3_url' )
126
- ) {
127
- $s3_uploads_instance = \S3_Uploads::get_instance();
128
- $s3_uploads_url = $s3_uploads_instance->get_s3_url();
129
- $this->webp_paths[] = $s3_uploads_url;
130
- $this->debug_message( "found S3 URL from S3_Uploads: $s3_uploads_url" );
131
- }
132
-
133
- if ( class_exists( 'wpCloud\StatelessMedia\EWWW' ) && function_exists( 'ud_get_stateless_media' ) ) {
134
- $sm = ud_get_stateless_media();
135
- if ( method_exists( $sm, 'get' ) && method_exists( $sm, 'get_gs_host' ) ) {
136
- $sm_mode = $sm->get( 'sm.mode' );
137
- if ( 'disabled' !== $sm_mode ) {
138
- $sm_host = $sm->get_gs_host();
139
- $this->debug_message( $sm_host );
140
- $this->webp_paths[] = $sm_host;
141
- }
142
- }
143
- }
144
-
145
- if ( function_exists( 'swis' ) && swis()->settings->get_option( 'cdn_domain' ) ) {
146
- $this->webp_paths[] = swis()->settings->get_option( 'cdn_domain' );
147
- }
148
-
149
- foreach ( $this->webp_paths as $webp_path ) {
150
- $webp_domain = $this->parse_url( $webp_path, PHP_URL_HOST );
151
- if ( $webp_domain ) {
152
- $this->webp_domains[] = $webp_domain;
153
- }
154
- }
155
- ewwwio_debug_message( 'checking any images matching these patterns for webp: ' . implode( ',', $this->webp_paths ) );
156
- ewwwio_debug_message( 'rewriting any images matching these domains to webp: ' . implode( ',', $this->webp_domains ) );
157
  $this->validate_user_exclusions();
158
  }
159
 
@@ -163,7 +74,7 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
163
  * @return array A list of WebP domains.
164
  */
165
  function get_webp_domains() {
166
- return $this->webp_domains;
167
  }
168
 
169
  /**
@@ -175,8 +86,8 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
175
  function srcset_replace( $srcset ) {
176
  $srcset_urls = explode( ' ', $srcset );
177
  $found_webp = false;
178
- if ( ewww_image_optimizer_iterable( $srcset_urls ) && count( $srcset_urls ) > 1 ) {
179
- ewwwio_debug_message( 'parsing srcset urls' );
180
  foreach ( $srcset_urls as $srcurl ) {
181
  if ( is_numeric( substr( $srcurl, 0, 1 ) ) ) {
182
  continue;
@@ -280,103 +191,43 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
280
  }
281
  } // End foreach().
282
  } // End if().
283
- ewwwio_debug_message( 'all done parsing page for picture webp' );
284
- return $buffer;
285
- }
286
-
287
- /**
288
- * Attempts to reverse a CDN URL to a local path to test for file existence.
289
- *
290
- * Used for supporting pull-mode CDNs without forcing everything to WebP.
291
- *
292
- * @param string $url The image URL to mangle.
293
- * @return bool True if a local file exists correlating to the CDN URL, false otherwise.
294
- */
295
- function cdn_to_local( $url ) {
296
- ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
297
- if ( ! is_array( $this->webp_domains ) || ! count( $this->webp_domains ) ) {
298
- return false;
299
- }
300
- foreach ( $this->webp_domains as $webp_domain ) {
301
- if ( $webp_domain === $this->home_domain ) {
302
- continue;
303
- }
304
- ewwwio_debug_message( "looking for $webp_domain in $url" );
305
- if (
306
- ! empty( $this->s3_active ) &&
307
- false !== strpos( $url, $this->s3_active ) &&
308
- (
309
- ( false !== strpos( $this->s3_active, '/' ) ) ||
310
- ( ! empty( $this->s3_object_prefix ) && false !== strpos( $url, $this->s3_object_prefix ) )
311
- )
312
- ) {
313
- // We will wait until the paths loop to fix this one.
314
- continue;
315
- }
316
- if ( false !== strpos( $url, $webp_domain ) ) {
317
- $local_url = str_replace( $webp_domain, $this->home_domain, $url );
318
- ewwwio_debug_message( "found $webp_domain, replaced with $this->home_domain to get $local_url" );
319
- if ( $this->url_to_path_exists( $local_url ) ) {
320
- return true;
321
  }
322
- }
323
- }
324
- foreach ( $this->webp_paths as $webp_path ) {
325
- if ( false === strpos( $webp_path, 'http' ) ) {
326
- continue;
327
- }
328
- ewwwio_debug_message( "looking for $webp_path in $url" );
329
- if (
330
- ! empty( $this->s3_active ) &&
331
- false !== strpos( $url, $this->s3_active ) &&
332
- ! empty( $this->s3_object_prefix ) &&
333
- 0 === strpos( $url, $webp_path . $this->s3_object_prefix )
334
- ) {
335
- $local_url = str_replace( $webp_path . $this->s3_object_prefix, $this->content_url, $url );
336
- ewwwio_debug_message( "found $webp_path (and $this->s3_object_prefix), replaced with $this->content_url to get $local_url" );
337
- if ( $this->url_to_path_exists( $local_url ) ) {
338
- return true;
339
  }
340
- }
341
- if ( false !== strpos( $url, $webp_path ) ) {
342
- $local_url = str_replace( $webp_path, $this->content_url, $url );
343
- ewwwio_debug_message( "found $webp_path, replaced with $this->content_url to get $local_url" );
344
- if ( $this->url_to_path_exists( $local_url ) ) {
345
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  }
347
  }
348
  }
349
- return false;
350
- }
351
-
352
- /**
353
- * Remove S3 object versioning from URL.
354
- *
355
- * @param string $url The image URL with a potential version string embedded.
356
- * @return string The URL without a version string.
357
- */
358
- function maybe_strip_object_version( $url ) {
359
- if ( ! empty( $this->s3_object_version ) ) {
360
- $possible_version = basename( dirname( $url ) );
361
- if (
362
- ! empty( $possible_version ) &&
363
- 8 === strlen( $possible_version ) &&
364
- ctype_digit( $possible_version )
365
- ) {
366
- $url = str_replace( '/' . $possible_version . '/', '/', $url );
367
- ewwwio_debug_message( "removed version $possible_version from $url" );
368
- } elseif (
369
- ! empty( $possible_version ) &&
370
- 14 === strlen( $possible_version ) &&
371
- ctype_digit( $possible_version )
372
- ) {
373
- $year = substr( $possible_version, 0, 4 );
374
- $month = substr( $possible_version, 4, 2 );
375
- $url = str_replace( '/' . $possible_version . '/', "/$year/$month/", $url );
376
- ewwwio_debug_message( "removed version $possible_version from $url" );
377
- }
378
- }
379
- return $url;
380
  }
381
 
382
  /**
@@ -387,7 +238,6 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
387
  * @return bool True if a local file exists correlating to the URL, false otherwise.
388
  */
389
  function url_to_path_exists( $url, $extension = '' ) {
390
- $url = $this->maybe_strip_object_version( $url );
391
  return parent::url_to_path_exists( $url, '.webp' );
392
  }
393
 
@@ -423,6 +273,18 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
423
  }
424
  }
425
 
 
 
 
 
 
 
 
 
 
 
 
 
426
  /**
427
  * Checks if the img tag is allowed to be rewritten.
428
  *
@@ -516,15 +378,15 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
516
  if ( apply_filters( 'ewww_image_optimizer_skip_webp_rewrite', false, $image ) ) {
517
  return false;
518
  }
519
- if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_force' ) && $this->webp_paths ) {
520
  // Check the image for configured CDN paths.
521
- foreach ( $this->webp_paths as $webp_path ) {
522
- if ( strpos( $image, $webp_path ) !== false ) {
523
- ewwwio_debug_message( 'forced cdn image' );
524
  return true;
525
  }
526
  }
527
- } elseif ( $this->webp_paths && $this->webp_domains ) {
528
  if ( $this->cdn_to_local( $image ) ) {
529
  return true;
530
  }
31
  */
32
  protected $user_element_exclusions = array();
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  /**
35
  * Register (once) actions and filters for Picture WebP.
36
  */
42
  if ( ewww_image_optimizer_ce_webp_enabled() ) {
43
  return false;
44
  }
45
+ parent::__construct();
46
+ $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
47
 
48
  // Make sure gallery block images crop properly.
49
  add_action( 'wp_head', array( $this, 'gallery_block_css' ) );
54
  add_filter( 'ewww_image_optimizer_filter_page_output', array( $this, 'filter_page_output' ), 10 );
55
  }
56
 
57
+ $allowed_urls = ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_paths' );
58
+ if ( $this->is_iterable( $allowed_urls ) ) {
59
+ $this->allowed_urls = array_merge( $this->allowed_urls, $allowed_urls );
 
 
 
 
 
 
 
 
 
 
60
  }
61
 
62
+ $this->get_allowed_domains();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
+ $this->allowed_urls = apply_filters( 'webp_allowed_urls', $this->allowed_urls );
65
+ $this->allowed_domains = apply_filters( 'webp_allowed_domains', $this->allowed_domains );
66
+ $this->debug_message( 'checking any images matching these URLs/patterns for webp: ' . implode( ',', $this->allowed_urls ) );
67
+ $this->debug_message( 'rewriting any images matching these domains to webp: ' . implode( ',', $this->allowed_domains ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  $this->validate_user_exclusions();
69
  }
70
 
74
  * @return array A list of WebP domains.
75
  */
76
  function get_webp_domains() {
77
+ return $this->allowed_domains;
78
  }
79
 
80
  /**
86
  function srcset_replace( $srcset ) {
87
  $srcset_urls = explode( ' ', $srcset );
88
  $found_webp = false;
89
+ if ( $this->is_iterable( $srcset_urls ) && count( $srcset_urls ) > 1 ) {
90
+ $this->debug_message( 'parsing srcset urls' );
91
  foreach ( $srcset_urls as $srcurl ) {
92
  if ( is_numeric( substr( $srcurl, 0, 1 ) ) ) {
93
  continue;
191
  }
192
  } // End foreach().
193
  } // End if().
194
+ // Images listed as picture/source elements.
195
+ $pictures = $this->get_picture_tags_from_html( $buffer );
196
+ if ( $this->is_iterable( $pictures ) ) {
197
+ foreach ( $pictures as $index => $picture ) {
198
+ if ( strpos( $picture, 'image/webp' ) ) {
199
+ continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  }
201
+ if ( ! $this->validate_tag( $picture ) ) {
202
+ continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  }
204
+ $sources = $this->get_elements_from_html( $picture, 'source' );
205
+ if ( $this->is_iterable( $sources ) ) {
206
+ foreach ( $sources as $source ) {
207
+ $this->debug_message( "parsing a picture source: $source" );
208
+ $srcset_attr_name = 'srcset';
209
+ if ( false !== strpos( $source, 'base64,R0lGOD' ) && false !== strpos( $source, 'data-srcset=' ) ) {
210
+ $srcset_attr_name = 'data-srcset';
211
+ }
212
+ $srcset = $this->get_attribute( $source, $srcset_attr_name );
213
+ if ( $srcset ) {
214
+ $srcset_webp = $this->srcset_replace( $srcset );
215
+ if ( $srcset_webp ) {
216
+ $source_webp = str_replace( $srcset, $srcset_webp, $source );
217
+ $this->set_attribute( $source_webp, 'type', 'image/webp' );
218
+ $picture = str_replace( $source, $source_webp . $source, $picture );
219
+ }
220
+ }
221
+ }
222
+ if ( $picture !== $pictures[ $index ] ) {
223
+ $this->debug_message( 'found webp for picture element' );
224
+ $buffer = str_replace( $pictures[ $index ], $picture, $buffer );
225
+ }
226
  }
227
  }
228
  }
229
+ $this->debug_message( 'all done parsing page for picture webp' );
230
+ return $buffer;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  }
232
 
233
  /**
238
  * @return bool True if a local file exists correlating to the URL, false otherwise.
239
  */
240
  function url_to_path_exists( $url, $extension = '' ) {
 
241
  return parent::url_to_path_exists( $url, '.webp' );
242
  }
243
 
273
  }
274
  }
275
 
276
+ /**
277
+ * Checks if the tag is allowed to be rewritten.
278
+ *
279
+ * @param string $image The HTML tag: img, span, etc.
280
+ * @return bool False if it flags a filter or exclusion, true otherwise.
281
+ */
282
+ function validate_tag( $image ) {
283
+ $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
284
+ // For now, only picture tags are allowed anyway, so just roll with it!
285
+ return true;
286
+ }
287
+
288
  /**
289
  * Checks if the img tag is allowed to be rewritten.
290
  *
378
  if ( apply_filters( 'ewww_image_optimizer_skip_webp_rewrite', false, $image ) ) {
379
  return false;
380
  }
381
+ if ( $this->get_option( 'ewww_image_optimizer_webp_force' ) && $this->is_iterable( $this->allowed_urls ) ) {
382
  // Check the image for configured CDN paths.
383
+ foreach ( $this->allowed_urls as $allowed_url ) {
384
+ if ( strpos( $image, $allowed_url ) !== false ) {
385
+ $this->debug_message( 'forced cdn image' );
386
  return true;
387
  }
388
  }
389
+ } elseif ( $this->allowed_urls && $this->allowed_domains ) {
390
  if ( $this->cdn_to_local( $image ) ) {
391
  return true;
392
  }
classes/class-ewwwio-background-process.php CHANGED
@@ -68,7 +68,6 @@ if ( ! class_exists( 'EWWWIO_Background_Process' ) ) {
68
  protected $cron_interval_identifier;
69
 
70
  /**
71
- * Either an 'a' or a 'b', depending on which one is currently running.
72
  * A unique identifier for each background class extension.
73
  *
74
  * @var string
@@ -142,7 +141,7 @@ if ( ! class_exists( 'EWWWIO_Background_Process' ) ) {
142
  }
143
 
144
  /**
145
- * Delete queue
146
  *
147
  * @param string $key Key.
148
  */
68
  protected $cron_interval_identifier;
69
 
70
  /**
 
71
  * A unique identifier for each background class extension.
72
  *
73
  * @var string
141
  }
142
 
143
  /**
144
+ * Delete queue item
145
  *
146
  * @param string $key Key.
147
  */
classes/class-ewwwio-media-background-process.php CHANGED
@@ -26,7 +26,7 @@ require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-backgroun
26
  /**
27
  * Processes media uploads in background/async mode.
28
  *
29
- * Uses a dual-queue system to track uploads to be optimized, handling them one at a time.
30
  *
31
  * @see EWWWIO_Background_Process
32
  */
26
  /**
27
  * Processes media uploads in background/async mode.
28
  *
29
+ * Uses a db queue system to track uploads to be optimized, handling them one at a time.
30
  *
31
  * @see EWWWIO_Background_Process
32
  */
classes/class-ewwwio-relative-migration.php CHANGED
@@ -39,12 +39,27 @@ class EWWWIO_Relative_Migration {
39
  if ( 'done' === get_option( 'ewww_image_optimizer_relative_migration_status' ) ) {
40
  return;
41
  }
 
 
 
 
 
42
  if ( ! get_option( 'ewww_image_optimizer_relative_migration_status' ) ) {
43
  update_option( 'ewww_image_optimizer_relative_migration_status', 'started' );
44
  }
45
  $this->maybe_schedule();
46
  }
47
 
 
 
 
 
 
 
 
 
 
 
48
  /**
49
  * Retrieves a batch of records based on the current offset.
50
  */
@@ -179,7 +194,7 @@ class EWWWIO_Relative_Migration {
179
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
180
  $schedules['ewwwio_relative_migration_interval'] = array(
181
  'interval' => MINUTE_IN_SECONDS * 5,
182
- 'display' => 'Every 5 Minutes',
183
  );
184
  return $schedules;
185
  }
39
  if ( 'done' === get_option( 'ewww_image_optimizer_relative_migration_status' ) ) {
40
  return;
41
  }
42
+ if ( ! $this->table_exists() ) {
43
+ $this->unschedule();
44
+ update_option( 'ewww_image_optimizer_relative_migration_status', 'done' );
45
+ delete_option( 'ewww_image_optimizer_relative_migration_offset' );
46
+ }
47
  if ( ! get_option( 'ewww_image_optimizer_relative_migration_status' ) ) {
48
  update_option( 'ewww_image_optimizer_relative_migration_status', 'started' );
49
  }
50
  $this->maybe_schedule();
51
  }
52
 
53
+ /**
54
+ * Check to see if the ewwwio_images table actually exists.
55
+ *
56
+ * @return bool True if does, false if it don't.
57
+ */
58
+ private function table_exists() {
59
+ global $wpdb;
60
+ return $wpdb->get_var( "SHOW TABLES LIKE '$wpdb->ewwwio_images'" ) === $wpdb->ewwwio_images;
61
+ }
62
+
63
  /**
64
  * Retrieves a batch of records based on the current offset.
65
  */
194
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
195
  $schedules['ewwwio_relative_migration_interval'] = array(
196
  'interval' => MINUTE_IN_SECONDS * 5,
197
+ 'display' => 'Every 5 Minutes until complete',
198
  );
199
  return $schedules;
200
  }
classes/class-exactdn.php CHANGED
@@ -120,10 +120,6 @@ if ( ! class_exists( 'ExactDN' ) ) {
120
  if ( is_customize_preview() ) {
121
  return;
122
  }
123
- // Make sure we have an ExactDN domain to use.
124
- if ( ! $this->setup() ) {
125
- return;
126
- }
127
 
128
  if ( ! $this->scheme ) {
129
  $site_url = get_home_url();
@@ -159,6 +155,11 @@ if ( ! class_exists( 'ExactDN' ) ) {
159
  return;
160
  }
161
 
 
 
 
 
 
162
  // Images in post content and galleries.
163
  add_filter( 'the_content', array( $this, 'filter_the_content' ), 999999 );
164
  // Start an output buffer before any output starts.
@@ -209,7 +210,7 @@ if ( ! class_exists( 'ExactDN' ) ) {
209
  add_filter( 'wp_resource_hints', array( $this, 'dns_prefetch' ), 10, 2 );
210
 
211
  // Get all the script/css urls and rewrite them (if enabled).
212
- if ( $this->get_option( 'exactdn_all_the_things' ) && $this->plan_id > 1 ) {
213
  add_filter( 'style_loader_src', array( $this, 'parse_enqueue' ), 9999 );
214
  add_filter( 'script_loader_src', array( $this, 'parse_enqueue' ), 9999 );
215
  }
@@ -229,40 +230,26 @@ if ( ! class_exists( 'ExactDN' ) ) {
229
  return;
230
  }
231
 
232
- $upload_url_parts = $this->parse_url( $this->content_url() );
233
  if ( empty( $upload_url_parts ) ) {
234
  $this->debug_message( "could not break down URL: $this->site_url" );
235
  return;
236
  }
237
- $this->upload_domain = $upload_url_parts['host'];
238
  if ( ! $this->get_option( $this->prefix . 'exactdn_local_domain' ) ) {
239
  $this->set_option( $this->prefix . 'exactdn_local_domain', $this->upload_domain );
240
  }
241
  $this->debug_message( "allowing images from here: $this->upload_domain" );
242
  if (
243
- ( false !== strpos( $this->upload_domain, 'amazonaws.com' ) || false !== strpos( $this->upload_domain, 'storage.googleapis.com' ) ) &&
244
- ! empty( $upload_url_parts['path'] )
 
 
 
 
245
  ) {
246
  $this->remove_path = rtrim( $upload_url_parts['path'], '/' );
247
  $this->debug_message( "removing this from urls: $this->remove_path" );
248
  }
249
- $this->allowed_domains[] = $this->upload_domain;
250
- if ( ! $this->s3_active && false === strpos( $this->upload_domain, 'www' ) ) {
251
- $this->allowed_domains[] = 'www.' . $this->upload_domain;
252
- } elseif ( 0 === strpos( $this->upload_domain, 'www' ) ) {
253
- $nonwww = ltrim( ltrim( $this->upload_domain, 'w' ), '.' );
254
- if ( $nonwww && $nonwww !== $this->upload_domain ) {
255
- $this->allowed_domains[] = $nonwww;
256
- }
257
- }
258
- $wpml_domains = apply_filters( 'wpml_setting', array(), 'language_domains' );
259
- if ( $this->is_iterable( $wpml_domains ) ) {
260
- $this->debug_message( 'wpml domains: ' . implode( ',', $wpml_domains ) );
261
- $this->allowed_domains[] = $this->parse_url( get_option( 'home' ), PHP_URL_HOST );
262
- foreach ( $wpml_domains as $wpml_domain ) {
263
- $this->allowed_domains[] = $wpml_domain;
264
- }
265
- }
266
  if (
267
  $this->get_option( $this->prefix . 'exactdn_local_domain' ) !== $this->upload_domain &&
268
  ! $this->allow_image_domain( $this->get_option( $this->prefix . 'exactdn_local_domain' ) ) &&
@@ -367,16 +354,13 @@ if ( ! class_exists( 'ExactDN' ) ) {
367
  $this->plan_id = 3;
368
  } else {
369
  $this->set_exactdn_option( 'plan_id', 1 );
370
- $this->set_option( 'exactdn_all_the_things', true );
371
  $this->plan_id = 1;
372
  }
373
  }
374
  if ( get_option( 'exactdn_never_been_active' ) ) {
375
  $this->set_option( $this->prefix . 'lazy_load', true );
376
  $this->set_option( 'exactdn_lossy', true );
377
- if ( $this->plan_id > 1 ) {
378
- $this->set_option( 'exactdn_all_the_things', true );
379
- }
380
  delete_option( 'exactdn_never_been_active' );
381
  }
382
  if ( 'external' === get_option( 'elementor_css_print_method' ) ) {
@@ -722,8 +706,8 @@ if ( ! class_exists( 'ExactDN' ) ) {
722
  $this->include_path = basename( $wp_include_path );
723
  $this->uploads_path = basename( $wp_content_path );
724
 
725
- // NOTE: This bit is not currently in use, so we'll see if anyone needs it.
726
- $uploads_info = wp_upload_dir();
727
  if ( ! empty( $uploads_info['baseurl'] ) && false === strpos( $uploads_info['baseurl'], $wp_content_path ) ) {
728
  $uploads_path = trim( $this->parse_url( $uploads_info['baseurl'], PHP_URL_PATH ), '/' );
729
  $this->debug_message( "wp uploads path: $uploads_path" );
@@ -745,7 +729,7 @@ if ( ! class_exists( 'ExactDN' ) ) {
745
  if ( ! is_string( $exclusion ) ) {
746
  continue;
747
  }
748
- if ( false !== strpos( $exclusion, $this->content_path ) ) {
749
  $exclusion = preg_replace( '#([^"\'?>]+?)?' . $this->content_path . '/#i', '', $exclusion );
750
  }
751
  $this->user_exclusions[] = ltrim( $exclusion, '/' );
@@ -1000,6 +984,13 @@ if ( ! class_exists( 'ExactDN' ) ) {
1000
  $width = $width && is_numeric( $width ) ? $width : false;
1001
  $height = $height && is_numeric( $height ) ? $height : false;
1002
 
 
 
 
 
 
 
 
1003
  // See if there is a width/height set in the style attribute.
1004
  $style_width = $this->get_img_style_width( $images['img_tag'][ $index ] );
1005
  $style_height = $this->get_img_style_height( $images['img_tag'][ $index ] );
@@ -1238,6 +1229,12 @@ if ( ! class_exists( 'ExactDN' ) ) {
1238
  unset( $placeholder_src );
1239
  }
1240
 
 
 
 
 
 
 
1241
  // Replace original tag with modified version.
1242
  $content = str_replace( $tag, $new_tag, $content );
1243
  }
@@ -1299,10 +1296,17 @@ if ( ! class_exists( 'ExactDN' ) ) {
1299
  $zoom = true;
1300
  }
1301
  }
 
 
 
 
 
 
 
1302
  if ( empty( $width ) || ! is_numeric( $width ) ) {
1303
- $width = $this->get_attribute( $images['img_tag'][ $index ], 'width' );
1304
  }
1305
- list( $filename_width, $discard_height ) = $this->get_dimensions_from_filename( $src );
1306
  if ( empty( $width ) || ! is_numeric( $width ) ) {
1307
  $width = $filename_width;
1308
  }
@@ -1321,6 +1325,11 @@ if ( ! class_exists( 'ExactDN' ) ) {
1321
  $this->set_attribute( $new_tag, 'sizes', sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', $width ) );
1322
  }
1323
  }
 
 
 
 
 
1324
  if ( $new_tag !== $images['img_tag'][ $index ] ) {
1325
  // Replace original tag with modified version.
1326
  $content = str_replace( $images['img_tag'][ $index ], $new_tag, $content );
@@ -1340,7 +1349,7 @@ if ( ! class_exists( 'ExactDN' ) ) {
1340
  if ( $this->filtering_the_page ) {
1341
  $content = $this->filter_style_blocks( $content );
1342
  }
1343
- if ( $this->filtering_the_page && $this->get_option( 'exactdn_all_the_things' ) && $this->plan_id > 1 ) {
1344
  $this->debug_message( 'rewriting all other wp-content/wp-includes urls' );
1345
  $content = $this->filter_all_the_things( $content );
1346
  }
@@ -1354,7 +1363,7 @@ if ( ! class_exists( 'ExactDN' ) ) {
1354
  if ( ! $this->get_option( 'exactdn_prevent_db_queries' ) && $this->elapsed_time > .5 ) {
1355
  $this->set_option( 'exactdn_prevent_db_queries', true );
1356
  }
1357
- if ( $this->filtering_the_page && $this->get_option( $this->prefix . 'debug' ) ) {
1358
  $content .= '<!-- Easy IO processing time: ' . $this->elapsed_time . ' seconds -->';
1359
  }
1360
  return $content;
@@ -1499,7 +1508,7 @@ if ( ! class_exists( 'ExactDN' ) ) {
1499
  * @return string The filtered HTML content.
1500
  */
1501
  function filter_all_the_things( $content ) {
1502
- if ( $this->exactdn_domain && $this->upload_domain && $this->plan_id > 1 ) {
1503
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
1504
  $upload_domain = $this->upload_domain;
1505
  if ( 0 === strpos( $this->upload_domain, 'www.' ) ) {
120
  if ( is_customize_preview() ) {
121
  return;
122
  }
 
 
 
 
123
 
124
  if ( ! $this->scheme ) {
125
  $site_url = get_home_url();
155
  return;
156
  }
157
 
158
+ // Make sure we have an ExactDN domain to use.
159
+ if ( ! $this->setup() ) {
160
+ return;
161
+ }
162
+
163
  // Images in post content and galleries.
164
  add_filter( 'the_content', array( $this, 'filter_the_content' ), 999999 );
165
  // Start an output buffer before any output starts.
210
  add_filter( 'wp_resource_hints', array( $this, 'dns_prefetch' ), 10, 2 );
211
 
212
  // Get all the script/css urls and rewrite them (if enabled).
213
+ if ( $this->get_option( 'exactdn_all_the_things' ) ) {
214
  add_filter( 'style_loader_src', array( $this, 'parse_enqueue' ), 9999 );
215
  add_filter( 'script_loader_src', array( $this, 'parse_enqueue' ), 9999 );
216
  }
230
  return;
231
  }
232
 
233
+ $upload_url_parts = $this->parse_url( $this->site_url );
234
  if ( empty( $upload_url_parts ) ) {
235
  $this->debug_message( "could not break down URL: $this->site_url" );
236
  return;
237
  }
 
238
  if ( ! $this->get_option( $this->prefix . 'exactdn_local_domain' ) ) {
239
  $this->set_option( $this->prefix . 'exactdn_local_domain', $this->upload_domain );
240
  }
241
  $this->debug_message( "allowing images from here: $this->upload_domain" );
242
  if (
243
+ (
244
+ false !== strpos( $this->upload_domain, 'amazonaws.com' ) ||
245
+ false !== strpos( $this->upload_domain, 'digitaloceanspaces.com' ) ||
246
+ false !== strpos( $this->upload_domain, 'storage.googleapis.com' )
247
+ )
248
+ && ! empty( $upload_url_parts['path'] )
249
  ) {
250
  $this->remove_path = rtrim( $upload_url_parts['path'], '/' );
251
  $this->debug_message( "removing this from urls: $this->remove_path" );
252
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  if (
254
  $this->get_option( $this->prefix . 'exactdn_local_domain' ) !== $this->upload_domain &&
255
  ! $this->allow_image_domain( $this->get_option( $this->prefix . 'exactdn_local_domain' ) ) &&
354
  $this->plan_id = 3;
355
  } else {
356
  $this->set_exactdn_option( 'plan_id', 1 );
 
357
  $this->plan_id = 1;
358
  }
359
  }
360
  if ( get_option( 'exactdn_never_been_active' ) ) {
361
  $this->set_option( $this->prefix . 'lazy_load', true );
362
  $this->set_option( 'exactdn_lossy', true );
363
+ $this->set_option( 'exactdn_all_the_things', true );
 
 
364
  delete_option( 'exactdn_never_been_active' );
365
  }
366
  if ( 'external' === get_option( 'elementor_css_print_method' ) ) {
706
  $this->include_path = basename( $wp_include_path );
707
  $this->uploads_path = basename( $wp_content_path );
708
 
709
+ // NOTE: $this->uploads_path is not currently in use, so we'll see if anyone needs it.
710
+ $uploads_info = wp_get_upload_dir();
711
  if ( ! empty( $uploads_info['baseurl'] ) && false === strpos( $uploads_info['baseurl'], $wp_content_path ) ) {
712
  $uploads_path = trim( $this->parse_url( $uploads_info['baseurl'], PHP_URL_PATH ), '/' );
713
  $this->debug_message( "wp uploads path: $uploads_path" );
729
  if ( ! is_string( $exclusion ) ) {
730
  continue;
731
  }
732
+ if ( $this->content_path && false !== strpos( $exclusion, $this->content_path ) ) {
733
  $exclusion = preg_replace( '#([^"\'?>]+?)?' . $this->content_path . '/#i', '', $exclusion );
734
  }
735
  $this->user_exclusions[] = ltrim( $exclusion, '/' );
984
  $width = $width && is_numeric( $width ) ? $width : false;
985
  $height = $height && is_numeric( $height ) ? $height : false;
986
 
987
+ // Get width/height attributes from the URL/file if they are missing.
988
+ $insert_dimensions = false;
989
+ if ( apply_filters( 'eio_add_missing_width_height_attrs', true ) && ( empty( $width ) || empty( $height ) ) ) {
990
+ $this->debug_message( 'missing width attr or height attr' );
991
+ $insert_dimensions = true;
992
+ }
993
+
994
  // See if there is a width/height set in the style attribute.
995
  $style_width = $this->get_img_style_width( $images['img_tag'][ $index ] );
996
  $style_height = $this->get_img_style_height( $images['img_tag'][ $index ] );
1229
  unset( $placeholder_src );
1230
  }
1231
 
1232
+ if ( $insert_dimensions && $filename_width > 0 && $filename_height > 0 ) {
1233
+ $this->debug_message( "filling in width = $filename_width and height = $filename_height" );
1234
+ $this->set_attribute( $new_tag, 'width', $filename_width, true );
1235
+ $this->set_attribute( $new_tag, 'height', $filename_height, true );
1236
+ }
1237
+
1238
  // Replace original tag with modified version.
1239
  $content = str_replace( $tag, $new_tag, $content );
1240
  }
1296
  $zoom = true;
1297
  }
1298
  }
1299
+ $width_attr = $this->get_attribute( $images['img_tag'][ $index ], 'width' );
1300
+ // Get width/height attributes from the URL/file if they are missing.
1301
+ $insert_dimensions = false;
1302
+ if ( apply_filters( 'eio_add_missing_width_height_attrs', true ) && empty( $width_attr ) ) {
1303
+ $this->debug_message( 'missing width attr or height attr' );
1304
+ $insert_dimensions = true;
1305
+ }
1306
  if ( empty( $width ) || ! is_numeric( $width ) ) {
1307
+ $width = $width_attr;
1308
  }
1309
+ list( $filename_width, $filename_height ) = $this->get_dimensions_from_filename( $src );
1310
  if ( empty( $width ) || ! is_numeric( $width ) ) {
1311
  $width = $filename_width;
1312
  }
1325
  $this->set_attribute( $new_tag, 'sizes', sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', $width ) );
1326
  }
1327
  }
1328
+ if ( $insert_dimensions && $filename_width > 0 && $filename_height > 0 ) {
1329
+ $this->debug_message( "filling in width = $filename_width and height = $filename_height" );
1330
+ $this->set_attribute( $new_tag, 'width', $filename_width, true );
1331
+ $this->set_attribute( $new_tag, 'height', $filename_height, true );
1332
+ }
1333
  if ( $new_tag !== $images['img_tag'][ $index ] ) {
1334
  // Replace original tag with modified version.
1335
  $content = str_replace( $images['img_tag'][ $index ], $new_tag, $content );
1349
  if ( $this->filtering_the_page ) {
1350
  $content = $this->filter_style_blocks( $content );
1351
  }
1352
+ if ( $this->filtering_the_page && $this->get_option( 'exactdn_all_the_things' ) ) {
1353
  $this->debug_message( 'rewriting all other wp-content/wp-includes urls' );
1354
  $content = $this->filter_all_the_things( $content );
1355
  }
1363
  if ( ! $this->get_option( 'exactdn_prevent_db_queries' ) && $this->elapsed_time > .5 ) {
1364
  $this->set_option( 'exactdn_prevent_db_queries', true );
1365
  }
1366
+ if ( $this->filtering_the_page && $this->get_option( $this->prefix . 'debug' ) && 0 !== strpos( $content, '{' ) && false === strpos( '$content', '<loc>' ) ) {
1367
  $content .= '<!-- Easy IO processing time: ' . $this->elapsed_time . ' seconds -->';
1368
  }
1369
  return $content;
1508
  * @return string The filtered HTML content.
1509
  */
1510
  function filter_all_the_things( $content ) {
1511
+ if ( $this->exactdn_domain && $this->upload_domain && $this->content_path ) {
1512
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
1513
  $upload_domain = $this->upload_domain;
1514
  if ( 0 === strpos( $this->upload_domain, 'www.' ) ) {
common.php CHANGED
@@ -14,7 +14,7 @@ if ( ! defined( 'ABSPATH' ) ) {
14
  exit;
15
  }
16
 
17
- define( 'EWWW_IMAGE_OPTIMIZER_VERSION', '603.0' );
18
 
19
  // Initialize a couple globals.
20
  $eio_debug = '';
@@ -46,6 +46,16 @@ use lsolesen\pel\PelTag;
46
  * Hooks
47
  */
48
 
 
 
 
 
 
 
 
 
 
 
49
  // If automatic optimization is NOT disabled.
50
  if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_noauto' ) ) {
51
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_DISABLE_EDITOR' ) || ! EWWW_IMAGE_OPTIMIZER_DISABLE_EDITOR ) {
@@ -112,16 +122,6 @@ add_filter( 'as3cf_attachment_file_paths', 'ewww_image_optimizer_as3cf_attachmen
112
  add_filter( 'as3cf_remove_attachment_paths', 'ewww_image_optimizer_as3cf_remove_attachment_file_paths', 10, 2 );
113
  // Fix the ContentType for WP Offload S3 on WebP images.
114
  add_filter( 'as3cf_object_meta', 'ewww_image_optimizer_as3cf_object_meta' );
115
- // Loads the plugin translations.
116
- add_action( 'plugins_loaded', 'ewww_image_optimizer_preinit' );
117
- // Runs any checks that need to run everywhere and early.
118
- add_action( 'init', 'ewww_image_optimizer_init', 9 );
119
- // Load our front-end parsers for ExactDN and/or Alt WebP.
120
- add_action( 'init', 'ewww_image_optimizer_parser_init', 99 );
121
- // Initializes the plugin for admin interactions, like saving network settings and scheduling cron jobs.
122
- add_action( 'admin_init', 'ewww_image_optimizer_admin_init' );
123
- // Check the current screen ID to see if temp debugging should still be enabled.
124
- add_action( 'current_screen', 'ewww_image_optimizer_current_screen', 10, 1 );
125
  // Get admin color scheme and save it for later.
126
  add_action( 'admin_head', 'ewww_image_optimizer_save_admin_colors' );
127
  // Legacy (non-AJAX) action hook for manually optimizing an image.
@@ -207,6 +207,9 @@ add_action( 'shutdown', 'ewww_image_optimizer_debug_log' );
207
  if ( defined( 'WP_CLI' ) && WP_CLI ) {
208
  require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-cli.php' );
209
  }
 
 
 
210
 
211
  /**
212
  * Setup page parsing classes after theme functions.php is loaded and plugins have run init routines.
@@ -629,8 +632,14 @@ function ewww_image_optimizer_save_network_settings() {
629
  update_site_option( 'exactdn_exclude', ewww_image_optimizer_exclude_paths_sanitize( $exactdn_exclude ) );
630
  $ewww_image_optimizer_lazy_load = ( empty( $_POST['ewww_image_optimizer_lazy_load'] ) ? false : true );
631
  update_site_option( 'ewww_image_optimizer_lazy_load', $ewww_image_optimizer_lazy_load );
 
 
632
  $ewww_image_optimizer_use_lqip = ( empty( $_POST['ewww_image_optimizer_use_lqip'] ) ? false : true );
633
  update_site_option( 'ewww_image_optimizer_use_lqip', $ewww_image_optimizer_use_lqip );
 
 
 
 
634
  $ewww_image_optimizer_ll_exclude = empty( $_POST['ewww_image_optimizer_ll_exclude'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['ewww_image_optimizer_ll_exclude'] ) );
635
  update_site_option( 'ewww_image_optimizer_ll_exclude', ewww_image_optimizer_exclude_paths_sanitize( $ewww_image_optimizer_ll_exclude ) );
636
  $ewww_image_optimizer_maxmediawidth = empty( $_POST['ewww_image_optimizer_maxmediawidth'] ) ? 0 : (int) $_POST['ewww_image_optimizer_maxmediawidth'];
@@ -806,12 +815,12 @@ function ewww_image_optimizer_init() {
806
  */
807
  function ewww_image_optimizer_upgrade() {
808
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
809
- ewwwio_memory( __FUNCTION__ );
 
810
  if ( get_option( 'ewww_image_optimizer_version' ) < EWWW_IMAGE_OPTIMIZER_VERSION ) {
811
  if ( wp_doing_ajax() ) {
812
  return;
813
  }
814
- global $ewwwio_upgrading;
815
  $ewwwio_upgrading = true;
816
  ewww_image_optimizer_enable_background_optimization();
817
  ewww_image_optimizer_install_table();
@@ -969,9 +978,6 @@ function ewww_image_optimizer_admin_init() {
969
  ewww_image_optimizer_cloud_init();
970
  ewww_image_optimizer_upgrade();
971
 
972
- if ( 'done' !== get_option( 'ewww_image_optimizer_relative_migration_status' ) ) {
973
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-relative-migration.php' );
974
- }
975
  // Do settings validation for multi-site.
976
  ewww_image_optimizer_save_network_settings();
977
 
@@ -1001,7 +1007,10 @@ function ewww_image_optimizer_admin_init() {
1001
  register_setting( 'ewww_image_optimizer_options', 'exactdn_lossy', 'boolval' );
1002
  register_setting( 'ewww_image_optimizer_options', 'exactdn_exclude', 'ewww_image_optimizer_exclude_paths_sanitize' );
1003
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_lazy_load', 'boolval' );
 
1004
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_use_lqip', 'boolval' );
 
 
1005
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_ll_exclude', 'ewww_image_optimizer_exclude_paths_sanitize' );
1006
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_resize_detection', 'boolval' );
1007
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_maxmediawidth', 'intval' );
@@ -2198,9 +2207,9 @@ function ewww_image_optimizer_notice_reoptimization() {
2198
  global $wpdb;
2199
  $reoptimized = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->ewwwio_images WHERE updates > 5 AND path NOT LIKE '%wp-content/themes%' AND path NOT LIKE '%wp-content/plugins%' LIMIT 10" );
2200
  if ( empty( $reoptimized ) ) {
2201
- set_transient( 'ewww_image_optimizer_images_reoptimized', 'zero', HOUR_IN_SECONDS );
2202
  } else {
2203
- set_transient( 'ewww_image_optimizer_images_reoptimized', $reoptimized, HOUR_IN_SECONDS );
2204
  }
2205
  } elseif ( 'zero' === $reoptimized ) {
2206
  $reoptimized = 0;
@@ -4551,9 +4560,6 @@ function ewww_image_optimizer_cloud_verify( $api_key, $cache = true ) {
4551
  return false;
4552
  } else {
4553
  set_transient( 'ewww_image_optimizer_cloud_status', $verified, HOUR_IN_SECONDS );
4554
- if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_level' ) < 20 && ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_level' ) < 20 && ewww_image_optimizer_get_option( 'ewww_image_optimizer_gif_level' ) < 20 && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_pdf_level' ) ) {
4555
- ewww_image_optimizer_cloud_enable();
4556
- }
4557
  ewwwio_debug_message( "verification body contents: {$result['body']}" );
4558
  ewwwio_memory( __FUNCTION__ );
4559
  return $verified;
@@ -4630,7 +4636,8 @@ function ewww_image_optimizer_cloud_quota( $raw = false ) {
4630
  if ( $raw ) {
4631
  return $quota;
4632
  }
4633
- if ( ! empty( $quota['unlimited'] ) && $quota['consumed'] >= 0 ) {
 
4634
  return sprintf(
4635
  /* translators: %d: Number of images */
4636
  __( 'optimized %d images.', 'ewww-image-optimizer' ),
@@ -5487,7 +5494,7 @@ function ewww_image_optimizer_find_file_by_id( $id ) {
5487
  /**
5488
  * Inserts multiple records into the table at once.
5489
  *
5490
- * Each sub-array in $images should have the same number of items as $format.
5491
  *
5492
  * @global object $wpdb
5493
  * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity.
@@ -8013,7 +8020,9 @@ function ewww_image_optimizer_lr_sync_update( $meta, $id = null ) {
8013
  * @return bool True if the IP location lock is enabled.
8014
  */
8015
  function ewww_image_optimizer_detect_wpsf_location_lock() {
8016
- if ( class_exists( 'ICWP_Wordpress_Simple_Firewall' ) ) {
 
 
8017
  $shield_user_man = ewww_image_optimizer_get_option( 'icwp_wpsf_user_management_options' );
8018
  if ( ewww_image_optimizer_function_exists( 'print_r' ) ) {
8019
  ewwwio_debug_message( print_r( $shield_user_man, true ) );
@@ -8515,7 +8524,7 @@ function ewww_image_optimizer_png_alpha( $filename ) {
8515
  }
8516
 
8517
  /**
8518
- * Check the submitted GIF to see if it is animated
8519
  *
8520
  * @param string $filename Name of the GIF to test for animation.
8521
  * @return bool True if animation found.
@@ -8542,6 +8551,48 @@ function ewww_image_optimizer_is_animated( $filename ) {
8542
  return $count > 1;
8543
  }
8544
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8545
  /**
8546
  * Count how many sizes are in the metadata, accounting for those with duplicate dimensions.
8547
  *
@@ -8708,12 +8759,18 @@ function ewww_image_optimizer_custom_column( $column_name, $id, $meta = null ) {
8708
  break;
8709
  case 'image/png':
8710
  // If pngout and optipng are missing and should not be skipped.
8711
- if ( ( ! $skip['optipng'] && ! EWWW_IMAGE_OPTIMIZER_OPTIPNG ) || ( ! $skip['pngout'] && ! EWWW_IMAGE_OPTIMIZER_PNGOUT ) ) {
8712
  $msg = '<div>' . sprintf(
8713
  /* translators: %s: name of a tool like jpegtran */
8714
  __( '%s is missing', 'ewww-image-optimizer' ),
8715
  '<em>optipng</em>'
8716
  ) . '</div>';
 
 
 
 
 
 
8717
  } elseif ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_level' ) ) {
8718
  $msg = '<div>' . sprintf(
8719
  /* translators: %s: JPG, PNG, GIF, or PDF */
@@ -9625,6 +9682,9 @@ function ewww_image_optimizer_get_option( $option_name, $default = false, $singl
9625
  return trim( $option_value );
9626
  }
9627
  }
 
 
 
9628
  if (
9629
  (
9630
  'ewww_image_optimizer_exclude_paths' === $option_name ||
@@ -10332,7 +10392,10 @@ function ewwwio_debug_info() {
10332
  ewwwio_debug_message( $eio_exclude_paths );
10333
  ewwwio_debug_message( 'lazy load: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) ? 'on' : 'off' ) );
10334
  ewwwio_other_lazy_detected();
 
10335
  ewwwio_debug_message( 'LQIP: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_use_lqip' ) ? 'on' : 'off' ) );
 
 
10336
  ewwwio_debug_message( 'LL exclusions:' );
10337
  $ll_exclude_paths = ewww_image_optimizer_get_option( 'ewww_image_optimizer_ll_exclude' ) ? esc_html( implode( "\n", ewww_image_optimizer_get_option( 'ewww_image_optimizer_ll_exclude' ) ) ) : '';
10338
  ewwwio_debug_message( $ll_exclude_paths );
@@ -10437,6 +10500,9 @@ function ewwwio_debug_info() {
10437
  $webp_paths = ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_paths' ) ? esc_html( implode( "\n", ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_paths' ) ) ) : '';
10438
  ewwwio_debug_message( $webp_paths );
10439
  ewwwio_debug_message( 'forced webp: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_force' ) ? 'on' : 'off' ) );
 
 
 
10440
  ewwwio_debug_message( 'forced gif2webp: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_force_gif2webp' ) ? 'on' : 'off' ) );
10441
  ewwwio_debug_message( 'enable help beacon: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help' ) ? 'yes' : 'no' ) );
10442
  if ( ! empty( $_SERVER['SERVER_ADDR'] ) ) {
@@ -11423,26 +11489,26 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
11423
  </div>
11424
  <!-- begin notices section -->
11425
  <div id="ewww-notices" class="ewww-status-detail">
11426
- <p>
11427
- <?php
11428
- printf(
11429
- /* translators: %s: Bulk Optimize (link) */
11430
- esc_html__( 'New uploads will be optimized automatically. Optimize existing images with the %s.', 'ewww-image-optimizer' ),
11431
- ( 'network-multisite' === esc_attr( $network ) ?
11432
- esc_html__( 'Media Library', 'ewww-image-optimizer' ) . ' -> ' . esc_html__( 'Bulk Optimizer', 'ewww-image-optimizer' ) :
11433
- '<a href="' . esc_url( admin_url( 'upload.php?page=ewww-image-optimizer-bulk' ) ) . '">' . esc_html__( 'Bulk Optimizer', 'ewww-image-optimizer' ) . '</a>'
11434
- )
11435
- );
11436
- ewwwio_help_link( 'https://docs.ewww.io/article/4-getting-started', '5853713bc697912ffd6c0b98' );
11437
- echo ' ' . ( ! class_exists( 'Amazon_S3_And_CloudFront' ) ?
11438
- '<br>' .
11439
- sprintf(
11440
- /* translators: %s: S3 Image Optimizer (link) */
11441
- esc_html__( 'Optimize unlimited Amazon S3 buckets with our %s.' ),
11442
- '<a href="https://ewww.io/downloads/s3-image-optimizer/">' . esc_html__( 'S3 Image Optimizer', 'ewww-image-optimizer' ) . '</a>'
11443
- ) : '' );
11444
- ?>
11445
- </p>
11446
  <p>
11447
  <strong><?php esc_html_e( 'Background optimization (faster uploads):', 'ewww-image-optimizer' ); ?></strong><br>
11448
  <?php if ( defined( 'EWWW_DISABLE_ASYNC' ) && EWWW_DISABLE_ASYNC ) : ?>
@@ -11451,6 +11517,8 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
11451
  <span style="color: orange; font-weight: bolder"><?php esc_html_e( 'Disabled, sleep function missing', 'ewww-image-optimizer' ); ?></span>
11452
  <?php elseif ( $ewwwio_upgrading ) : ?>
11453
  <span><?php esc_html_e( 'Update detected, re-testing', 'ewww-image-optimizer' ); ?></span>
 
 
11454
  <?php elseif ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_background_optimization' ) ) : ?>
11455
  <span style="color: orange; font-weight: bolder">
11456
  <?php esc_html_e( 'Disabled automatically, async requests blocked', 'ewww-image-optimizer' ); ?>
@@ -11459,8 +11527,6 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
11459
  </a>
11460
  </span>
11461
  <?php ewwwio_help_link( 'https://docs.ewww.io/article/42-background-and-parallel-optimization-disabled', '598cb8be2c7d3a73488be237' ); ?>
11462
- <?php elseif ( ewww_image_optimizer_detect_wpsf_location_lock() ) : ?>
11463
- <span style="color: orange; font-weight: bolder"><?php esc_html_e( "Disabled by Shield's Lock to Location feature", 'ewww-image-optimizer' ); ?></span>
11464
  <?php else : ?>
11465
  <span><?php esc_html_e( 'Enabled', 'ewww-image-optimizer' ); ?>
11466
  - <a href="<?php echo esc_url( admin_url( 'admin.php?action=ewww_image_optimizer_retest_background_optimization' ) ); ?>">
@@ -11508,9 +11574,6 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
11508
  $loading_image_url = plugins_url( '/images/spinner.gif', __FILE__ );
11509
  $eio_base = new EIO_Base();
11510
  $easyio_site_url = $eio_base->content_url();
11511
- $exactdn_att_che = ewww_image_optimizer_get_option( 'exactdn_all_the_things' ) && ( ! is_object( $exactdn ) || 1 < $exactdn->get_plan_id() );
11512
- $exactdn_att_id = ( ! $exactdn_enabled || 1 === $exactdn->get_plan_id() ? 'exactdn_all_the_things_disabled' : 'exactdn_all_the_things' );
11513
- $exactdn_att_dis = ! $exactdn_enabled || 1 === $exactdn->get_plan_id();
11514
  $exactdn_los_che = ewww_image_optimizer_get_option( 'exactdn_lossy' ) || ( is_object( $exactdn ) && 1 === $exactdn->get_plan_id() );
11515
  $exactdn_los_id = ( ! $exactdn_enabled || 1 === $exactdn->get_plan_id() ? 'exactdn_lossy_disabled' : 'exactdn_lossy' );
11516
  $exactdn_los_dis = ! $exactdn_enabled || 1 === $exactdn->get_plan_id();
@@ -11784,15 +11847,12 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
11784
  <tr class='ewwwio-exactdn-options' <?php echo $exactdn_enabled ? '' : 'style="display:none;"'; ?>>
11785
  <td>&nbsp;</td>
11786
  <td>
11787
- <input type='checkbox' name='exactdn_all_the_things' value='true' id='<?php echo esc_attr( $exactdn_att_id ); ?>' <?php disabled( $exactdn_att_dis ); ?> <?php checked( $exactdn_att_che ); ?> />
11788
  <label for='exactdn_all_the_things'><strong><?php esc_html_e( 'Include All Resources', 'ewww-image-optimizer' ); ?></strong></label>
11789
  <?php ewwwio_help_link( 'https://docs.ewww.io/article/47-getting-more-from-exactdn', '59de6631042863379ddc953c' ); ?>
11790
  <p class='description'>
11791
  <?php esc_html_e( 'Use Easy IO for all resources in wp-includes/ and wp-content/, including JavaScript, CSS, fonts, etc.', 'ewww-image-optimizer' ); ?>
11792
  </p>
11793
- <?php if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'photon-cdn' ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) : ?>
11794
- <p style="color: red"><?php esc_html_e( 'Inactive, please disable the Site Accelerator in the Jetpack Performance settings.', 'ewww-image-optimizer' ); ?></p>
11795
- <?php endif; ?>
11796
  </td>
11797
  </tr>
11798
  <tr class='ewwwio-exactdn-options' <?php echo $exactdn_enabled && ! $easymode ? '' : 'style="display:none;"'; ?>>
@@ -11807,7 +11867,6 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
11807
  </td>
11808
  </tr>
11809
  <?php if ( ! $exactdn_enabled || 1 === $exactdn->get_plan_id() ) : ?>
11810
- <input type='hidden' id='exactdn_all_the_things' name='exactdn_all_the_things' <?php echo ( ewww_image_optimizer_get_option( 'exactdn_all_the_things' ) ? "value='1'" : "value='0'" ); ?> />
11811
  <input type='hidden' id='exactdn_lossy' name='exactdn_lossy' <?php echo ( ewww_image_optimizer_get_option( 'exactdn_lossy' ) ? "value='1'" : "value='0'" ); ?> />
11812
  <input type='hidden' id='ewww_image_optimizer_use_lqip' name='ewww_image_optimizer_use_lqip' <?php echo ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_use_lqip' ) ? "value='1'" : "value='0'" ); ?> />
11813
  <?php endif; ?>
@@ -11869,9 +11928,15 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
11869
  <label for='ewww_image_optimizer_maxmediaheight'><?php esc_html_e( 'Max Height', 'ewww-image-optimizer' ); ?></label>
11870
  <input type='number' step='1' min='0' class='small-text' id='ewww_image_optimizer_maxmediaheight' name='ewww_image_optimizer_maxmediaheight' value='<?php echo (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediaheight' ); ?>' <?php disabled( function_exists( 'imsanity_get_max_width_height' ) ); ?> />
11871
  <?php esc_html_e( 'in pixels', 'ewww-image-optimizer' ); ?>
 
 
 
 
 
11872
  <p class='description'>
11873
  <?php esc_html_e( 'Resize uploaded images to these dimensions (in pixels).', 'ewww-image-optimizer' ); ?>
11874
  </p>
 
11875
  </td>
11876
  </tr>
11877
  <tr>
@@ -11890,7 +11955,28 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
11890
  <?php endif; ?>
11891
  <p class='description'>
11892
  <?php esc_html_e( 'The lazy loader chooses the best available image size from existing responsive markup. When used with Easy IO, all images become responsive.', 'ewww-image-optimizer' ); ?></br>
11893
- <?php esc_html_e( 'To disable auto-scaling for an image, add "skip-autoscale" to the HTML element via a class or attribute.', 'ewww-image-optimizer' ); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11894
  </p>
11895
  </td>
11896
  </tr>
@@ -11905,6 +11991,20 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
11905
  </p>
11906
  </td>
11907
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11908
  <tr id='ewww_image_optimizer_ll_exclude_container' <?php echo ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) ? '' : ' style="display:none"'; ?>>
11909
  <td>&nbsp;</td>
11910
  <td>
@@ -11916,6 +12016,22 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
11916
  </p>
11917
  </td>
11918
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11919
  <?php endif; ?>
11920
  <?php if ( $free_exec ) : ?>
11921
  <tr>
@@ -12474,16 +12590,6 @@ AddType image/webp .webp</pre>
12474
  <?php esc_html_e( 'Highlight images that need to be resized because the browser is scaling them down. Only visible for Admin users and adds a button to the admin bar to detect scaled images that have been lazy loaded.', 'ewww-image-optimizer' ); ?>
12475
  </td>
12476
  </tr>
12477
- <?php if ( function_exists( 'imsanity_get_max_width_height' ) ) : ?>
12478
- <tr>
12479
- <th>&nbsp;</th>
12480
- <td>
12481
- <p>
12482
- <span style="color: #3eadc9"><?php esc_html_e( '*Imsanity settings override the EWWW resize dimensions.', 'ewww-image-optimizer' ); ?></span>
12483
- </p>
12484
- </td>
12485
- </tr>
12486
- <?php endif; ?>
12487
  <tr>
12488
  <th scope='row'>
12489
  <label for='ewww_image_optimizer_resize_existing'><?php esc_html_e( 'Resize Existing Images', 'ewww-image-optimizer' ); ?></label>
14
  exit;
15
  }
16
 
17
+ define( 'EWWW_IMAGE_OPTIMIZER_VERSION', '610' );
18
 
19
  // Initialize a couple globals.
20
  $eio_debug = '';
46
  * Hooks
47
  */
48
 
49
+ // Loads the plugin translations.
50
+ add_action( 'plugins_loaded', 'ewww_image_optimizer_preinit' );
51
+ // Runs any checks that need to run everywhere and early.
52
+ add_action( 'init', 'ewww_image_optimizer_init', 9 );
53
+ // Load our front-end parsers for ExactDN and/or Alt WebP.
54
+ add_action( 'init', 'ewww_image_optimizer_parser_init', 99 );
55
+ // Initializes the plugin for admin interactions, like saving network settings and scheduling cron jobs.
56
+ add_action( 'admin_init', 'ewww_image_optimizer_admin_init' );
57
+ // Check the current screen ID to see if temp debugging should still be enabled.
58
+ add_action( 'current_screen', 'ewww_image_optimizer_current_screen', 10, 1 );
59
  // If automatic optimization is NOT disabled.
60
  if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_noauto' ) ) {
61
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_DISABLE_EDITOR' ) || ! EWWW_IMAGE_OPTIMIZER_DISABLE_EDITOR ) {
122
  add_filter( 'as3cf_remove_attachment_paths', 'ewww_image_optimizer_as3cf_remove_attachment_file_paths', 10, 2 );
123
  // Fix the ContentType for WP Offload S3 on WebP images.
124
  add_filter( 'as3cf_object_meta', 'ewww_image_optimizer_as3cf_object_meta' );
 
 
 
 
 
 
 
 
 
 
125
  // Get admin color scheme and save it for later.
126
  add_action( 'admin_head', 'ewww_image_optimizer_save_admin_colors' );
127
  // Legacy (non-AJAX) action hook for manually optimizing an image.
207
  if ( defined( 'WP_CLI' ) && WP_CLI ) {
208
  require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-cli.php' );
209
  }
210
+ if ( 'done' !== get_option( 'ewww_image_optimizer_relative_migration_status' ) ) {
211
+ require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-relative-migration.php' );
212
+ }
213
 
214
  /**
215
  * Setup page parsing classes after theme functions.php is loaded and plugins have run init routines.
632
  update_site_option( 'exactdn_exclude', ewww_image_optimizer_exclude_paths_sanitize( $exactdn_exclude ) );
633
  $ewww_image_optimizer_lazy_load = ( empty( $_POST['ewww_image_optimizer_lazy_load'] ) ? false : true );
634
  update_site_option( 'ewww_image_optimizer_lazy_load', $ewww_image_optimizer_lazy_load );
635
+ $ewww_image_optimizer_ll_autoscale = ( empty( $_POST['ewww_image_optimizer_ll_autoscale'] ) ? false : true );
636
+ update_site_option( 'ewww_image_optimizer_ll_autoscale', $ewww_image_optimizer_ll_autoscale );
637
  $ewww_image_optimizer_use_lqip = ( empty( $_POST['ewww_image_optimizer_use_lqip'] ) ? false : true );
638
  update_site_option( 'ewww_image_optimizer_use_lqip', $ewww_image_optimizer_use_lqip );
639
+ $ewww_image_optimizer_use_siip = ( empty( $_POST['ewww_image_optimizer_use_siip'] ) ? false : true );
640
+ update_site_option( 'ewww_image_optimizer_use_siip', $ewww_image_optimizer_use_siip );
641
+ $ewww_image_optimizer_ll_all_things = empty( $_POST['ewww_image_optimizer_ll_all_things'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['ewww_image_optimizer_ll_all_things'] ) );
642
+ update_site_option( 'ewww_image_optimizer_ll_all_things', ewww_image_optimizer_exclude_paths_sanitize( $ewww_image_optimizer_ll_all_things ) );
643
  $ewww_image_optimizer_ll_exclude = empty( $_POST['ewww_image_optimizer_ll_exclude'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['ewww_image_optimizer_ll_exclude'] ) );
644
  update_site_option( 'ewww_image_optimizer_ll_exclude', ewww_image_optimizer_exclude_paths_sanitize( $ewww_image_optimizer_ll_exclude ) );
645
  $ewww_image_optimizer_maxmediawidth = empty( $_POST['ewww_image_optimizer_maxmediawidth'] ) ? 0 : (int) $_POST['ewww_image_optimizer_maxmediawidth'];
815
  */
816
  function ewww_image_optimizer_upgrade() {
817
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
818
+ global $ewwwio_upgrading;
819
+ $ewwwio_upgrading = false;
820
  if ( get_option( 'ewww_image_optimizer_version' ) < EWWW_IMAGE_OPTIMIZER_VERSION ) {
821
  if ( wp_doing_ajax() ) {
822
  return;
823
  }
 
824
  $ewwwio_upgrading = true;
825
  ewww_image_optimizer_enable_background_optimization();
826
  ewww_image_optimizer_install_table();
978
  ewww_image_optimizer_cloud_init();
979
  ewww_image_optimizer_upgrade();
980
 
 
 
 
981
  // Do settings validation for multi-site.
982
  ewww_image_optimizer_save_network_settings();
983
 
1007
  register_setting( 'ewww_image_optimizer_options', 'exactdn_lossy', 'boolval' );
1008
  register_setting( 'ewww_image_optimizer_options', 'exactdn_exclude', 'ewww_image_optimizer_exclude_paths_sanitize' );
1009
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_lazy_load', 'boolval' );
1010
+ register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_ll_autoscale', 'boolval' );
1011
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_use_lqip', 'boolval' );
1012
+ register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_use_siip', 'boolval' );
1013
+ register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_ll_all_things', 'sanitize_text_field' );
1014
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_ll_exclude', 'ewww_image_optimizer_exclude_paths_sanitize' );
1015
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_resize_detection', 'boolval' );
1016
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_maxmediawidth', 'intval' );
2207
  global $wpdb;
2208
  $reoptimized = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->ewwwio_images WHERE updates > 5 AND path NOT LIKE '%wp-content/themes%' AND path NOT LIKE '%wp-content/plugins%' LIMIT 10" );
2209
  if ( empty( $reoptimized ) ) {
2210
+ set_transient( 'ewww_image_optimizer_images_reoptimized', 'zero', 12 * HOUR_IN_SECONDS );
2211
  } else {
2212
+ set_transient( 'ewww_image_optimizer_images_reoptimized', $reoptimized, 12 * HOUR_IN_SECONDS );
2213
  }
2214
  } elseif ( 'zero' === $reoptimized ) {
2215
  $reoptimized = 0;
4560
  return false;
4561
  } else {
4562
  set_transient( 'ewww_image_optimizer_cloud_status', $verified, HOUR_IN_SECONDS );
 
 
 
4563
  ewwwio_debug_message( "verification body contents: {$result['body']}" );
4564
  ewwwio_memory( __FUNCTION__ );
4565
  return $verified;
4636
  if ( $raw ) {
4637
  return $quota;
4638
  }
4639
+ if ( ! empty( $quota['unlimited'] ) ) {
4640
+ $quota['consumed'] = max( $quota['consumed'], 0 );
4641
  return sprintf(
4642
  /* translators: %d: Number of images */
4643
  __( 'optimized %d images.', 'ewww-image-optimizer' ),
5494
  /**
5495
  * Inserts multiple records into the table at once.
5496
  *
5497
+ * Each sub-array in $data should have the same number of items as $format.
5498
  *
5499
  * @global object $wpdb
5500
  * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity.
8020
  * @return bool True if the IP location lock is enabled.
8021
  */
8022
  function ewww_image_optimizer_detect_wpsf_location_lock() {
8023
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
8024
+ if ( function_exists( 'icwp_wpsf_init' ) ) {
8025
+ ewwwio_debug_message( 'Shield Security detected' );
8026
  $shield_user_man = ewww_image_optimizer_get_option( 'icwp_wpsf_user_management_options' );
8027
  if ( ewww_image_optimizer_function_exists( 'print_r' ) ) {
8028
  ewwwio_debug_message( print_r( $shield_user_man, true ) );
8524
  }
8525
 
8526
  /**
8527
+ * Check the submitted GIF to see if it is animated.
8528
  *
8529
  * @param string $filename Name of the GIF to test for animation.
8530
  * @return bool True if animation found.
8551
  return $count > 1;
8552
  }
8553
 
8554
+ /**
8555
+ * Check the submitted PNG to see if it is animated. Thanks @GregOriol!
8556
+ *
8557
+ * @param string $filename Name of the PNG to test for animation.
8558
+ * @return bool True if animation found.
8559
+ */
8560
+ function ewww_image_optimizer_is_animated_png( $filename ) {
8561
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
8562
+ $apng = false;
8563
+ if ( ! ewwwio_is_file( $filename ) ) {
8564
+ return false;
8565
+ }
8566
+ // If we can't open the file in read-only buffered mode.
8567
+ $fh = fopen( $filename, 'rb' );
8568
+ if ( ! $fh ) {
8569
+ return false;
8570
+ }
8571
+ $previousdata = '';
8572
+ // We read through the file til we reach the end of the file, or we've found an acTL or IDAT chunk.
8573
+ while ( ! feof( $fh ) ) {
8574
+ $data = fread( $fh, 1024 ); // Read 1kb at a time.
8575
+ if ( false !== strpos( $data, 'acTL' ) ) {
8576
+ ewwwio_debug_message( 'found acTL chunk (animated) in PNG' );
8577
+ $apng = true;
8578
+ break;
8579
+ } elseif ( false !== strpos( $previousdata . $data, 'acTL' ) ) {
8580
+ ewwwio_debug_message( 'found acTL chunk (animated) in PNG' );
8581
+ $apng = true;
8582
+ break;
8583
+ } elseif ( false !== strpos( $data, 'IDAT' ) ) {
8584
+ ewwwio_debug_message( 'found IDAT, but no acTL (animated) chunk in PNG' );
8585
+ break;
8586
+ } elseif ( false !== strpos( $previousdata . $data, 'IDAT' ) ) {
8587
+ ewwwio_debug_message( 'found IDAT, but no acTL (animated) chunk in PNG' );
8588
+ break;
8589
+ }
8590
+ $previousdata = $data;
8591
+ }
8592
+ fclose( $fh );
8593
+ return $apng;
8594
+ }
8595
+
8596
  /**
8597
  * Count how many sizes are in the metadata, accounting for those with duplicate dimensions.
8598
  *
8759
  break;
8760
  case 'image/png':
8761
  // If pngout and optipng are missing and should not be skipped.
8762
+ if ( ! $skip['optipng'] && ! EWWW_IMAGE_OPTIMIZER_OPTIPNG ) {
8763
  $msg = '<div>' . sprintf(
8764
  /* translators: %s: name of a tool like jpegtran */
8765
  __( '%s is missing', 'ewww-image-optimizer' ),
8766
  '<em>optipng</em>'
8767
  ) . '</div>';
8768
+ } elseif ( ! $skip['pngout'] && ! EWWW_IMAGE_OPTIMIZER_PNGOUT ) {
8769
+ $msg = '<div>' . sprintf(
8770
+ /* translators: %s: name of a tool like jpegtran */
8771
+ __( '%s is missing', 'ewww-image-optimizer' ),
8772
+ '<em>pngout</em>'
8773
+ ) . '</div>';
8774
  } elseif ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_level' ) ) {
8775
  $msg = '<div>' . sprintf(
8776
  /* translators: %s: JPG, PNG, GIF, or PDF */
9682
  return trim( $option_value );
9683
  }
9684
  }
9685
+ if ( 'ewww_image_optimizer_ll_all_things' === $option_name && defined( $constant_name ) ) {
9686
+ return sanitize_text_field( constant( $constant_name ) );
9687
+ }
9688
  if (
9689
  (
9690
  'ewww_image_optimizer_exclude_paths' === $option_name ||
10392
  ewwwio_debug_message( $eio_exclude_paths );
10393
  ewwwio_debug_message( 'lazy load: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) ? 'on' : 'off' ) );
10394
  ewwwio_other_lazy_detected();
10395
+ ewwwio_debug_message( 'LL autoscale: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_ll_autoscale' ) ? 'on' : 'off' ) );
10396
  ewwwio_debug_message( 'LQIP: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_use_lqip' ) ? 'on' : 'off' ) );
10397
+ ewwwio_debug_message( 'S(VG)IIP: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_use_siip' ) ? 'on' : 'off' ) );
10398
+ ewwwio_debug_message( 'external CSS background (all things): ' . ewww_image_optimizer_get_option( 'ewww_image_optimizer_ll_all_things' ) );
10399
  ewwwio_debug_message( 'LL exclusions:' );
10400
  $ll_exclude_paths = ewww_image_optimizer_get_option( 'ewww_image_optimizer_ll_exclude' ) ? esc_html( implode( "\n", ewww_image_optimizer_get_option( 'ewww_image_optimizer_ll_exclude' ) ) ) : '';
10401
  ewwwio_debug_message( $ll_exclude_paths );
10500
  $webp_paths = ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_paths' ) ? esc_html( implode( "\n", ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_paths' ) ) ) : '';
10501
  ewwwio_debug_message( $webp_paths );
10502
  ewwwio_debug_message( 'forced webp: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_force' ) ? 'on' : 'off' ) );
10503
+ if ( ewww_image_optimizer_cloud_based_media() ) {
10504
+ ewwwio_debug_message( 'forced webp auto-enabled' );
10505
+ }
10506
  ewwwio_debug_message( 'forced gif2webp: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_force_gif2webp' ) ? 'on' : 'off' ) );
10507
  ewwwio_debug_message( 'enable help beacon: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help' ) ? 'yes' : 'no' ) );
10508
  if ( ! empty( $_SERVER['SERVER_ADDR'] ) ) {
11489
  </div>
11490
  <!-- begin notices section -->
11491
  <div id="ewww-notices" class="ewww-status-detail">
11492
+ <p>
11493
+ <?php
11494
+ printf(
11495
+ /* translators: %s: Bulk Optimize (link) */
11496
+ esc_html__( 'New uploads will be optimized automatically. Optimize existing images with the %s.', 'ewww-image-optimizer' ),
11497
+ ( 'network-multisite' === esc_attr( $network ) ?
11498
+ esc_html__( 'Media Library', 'ewww-image-optimizer' ) . ' -> ' . esc_html__( 'Bulk Optimizer', 'ewww-image-optimizer' ) :
11499
+ '<a href="' . esc_url( admin_url( 'upload.php?page=ewww-image-optimizer-bulk' ) ) . '">' . esc_html__( 'Bulk Optimizer', 'ewww-image-optimizer' ) . '</a>'
11500
+ )
11501
+ );
11502
+ ewwwio_help_link( 'https://docs.ewww.io/article/4-getting-started', '5853713bc697912ffd6c0b98' );
11503
+ echo ' ' . ( ! class_exists( 'Amazon_S3_And_CloudFront' ) ?
11504
+ '<br>' .
11505
+ sprintf(
11506
+ /* translators: %s: S3 Image Optimizer (link) */
11507
+ esc_html__( 'Optimize unlimited Amazon S3 buckets with our %s.' ),
11508
+ '<a href="https://ewww.io/downloads/s3-image-optimizer/">' . esc_html__( 'S3 Image Optimizer', 'ewww-image-optimizer' ) . '</a>'
11509
+ ) : '' );
11510
+ ?>
11511
+ </p>
11512
  <p>
11513
  <strong><?php esc_html_e( 'Background optimization (faster uploads):', 'ewww-image-optimizer' ); ?></strong><br>
11514
  <?php if ( defined( 'EWWW_DISABLE_ASYNC' ) && EWWW_DISABLE_ASYNC ) : ?>
11517
  <span style="color: orange; font-weight: bolder"><?php esc_html_e( 'Disabled, sleep function missing', 'ewww-image-optimizer' ); ?></span>
11518
  <?php elseif ( $ewwwio_upgrading ) : ?>
11519
  <span><?php esc_html_e( 'Update detected, re-testing', 'ewww-image-optimizer' ); ?></span>
11520
+ <?php elseif ( ewww_image_optimizer_detect_wpsf_location_lock() ) : ?>
11521
+ <span style="color: orange; font-weight: bolder"><?php esc_html_e( "Disabled by Shield's Lock to Location feature", 'ewww-image-optimizer' ); ?></span>
11522
  <?php elseif ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_background_optimization' ) ) : ?>
11523
  <span style="color: orange; font-weight: bolder">
11524
  <?php esc_html_e( 'Disabled automatically, async requests blocked', 'ewww-image-optimizer' ); ?>
11527
  </a>
11528
  </span>
11529
  <?php ewwwio_help_link( 'https://docs.ewww.io/article/42-background-and-parallel-optimization-disabled', '598cb8be2c7d3a73488be237' ); ?>
 
 
11530
  <?php else : ?>
11531
  <span><?php esc_html_e( 'Enabled', 'ewww-image-optimizer' ); ?>
11532
  - <a href="<?php echo esc_url( admin_url( 'admin.php?action=ewww_image_optimizer_retest_background_optimization' ) ); ?>">
11574
  $loading_image_url = plugins_url( '/images/spinner.gif', __FILE__ );
11575
  $eio_base = new EIO_Base();
11576
  $easyio_site_url = $eio_base->content_url();
 
 
 
11577
  $exactdn_los_che = ewww_image_optimizer_get_option( 'exactdn_lossy' ) || ( is_object( $exactdn ) && 1 === $exactdn->get_plan_id() );
11578
  $exactdn_los_id = ( ! $exactdn_enabled || 1 === $exactdn->get_plan_id() ? 'exactdn_lossy_disabled' : 'exactdn_lossy' );
11579
  $exactdn_los_dis = ! $exactdn_enabled || 1 === $exactdn->get_plan_id();
11847
  <tr class='ewwwio-exactdn-options' <?php echo $exactdn_enabled ? '' : 'style="display:none;"'; ?>>
11848
  <td>&nbsp;</td>
11849
  <td>
11850
+ <input type='checkbox' name='exactdn_all_the_things' value='true' id='exactdn_all_the_things' <?php checked( ewww_image_optimizer_get_option( 'exactdn_all_the_things' ) ); ?> />
11851
  <label for='exactdn_all_the_things'><strong><?php esc_html_e( 'Include All Resources', 'ewww-image-optimizer' ); ?></strong></label>
11852
  <?php ewwwio_help_link( 'https://docs.ewww.io/article/47-getting-more-from-exactdn', '59de6631042863379ddc953c' ); ?>
11853
  <p class='description'>
11854
  <?php esc_html_e( 'Use Easy IO for all resources in wp-includes/ and wp-content/, including JavaScript, CSS, fonts, etc.', 'ewww-image-optimizer' ); ?>
11855
  </p>
 
 
 
11856
  </td>
11857
  </tr>
11858
  <tr class='ewwwio-exactdn-options' <?php echo $exactdn_enabled && ! $easymode ? '' : 'style="display:none;"'; ?>>
11867
  </td>
11868
  </tr>
11869
  <?php if ( ! $exactdn_enabled || 1 === $exactdn->get_plan_id() ) : ?>
 
11870
  <input type='hidden' id='exactdn_lossy' name='exactdn_lossy' <?php echo ( ewww_image_optimizer_get_option( 'exactdn_lossy' ) ? "value='1'" : "value='0'" ); ?> />
11871
  <input type='hidden' id='ewww_image_optimizer_use_lqip' name='ewww_image_optimizer_use_lqip' <?php echo ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_use_lqip' ) ? "value='1'" : "value='0'" ); ?> />
11872
  <?php endif; ?>
11928
  <label for='ewww_image_optimizer_maxmediaheight'><?php esc_html_e( 'Max Height', 'ewww-image-optimizer' ); ?></label>
11929
  <input type='number' step='1' min='0' class='small-text' id='ewww_image_optimizer_maxmediaheight' name='ewww_image_optimizer_maxmediaheight' value='<?php echo (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediaheight' ); ?>' <?php disabled( function_exists( 'imsanity_get_max_width_height' ) ); ?> />
11930
  <?php esc_html_e( 'in pixels', 'ewww-image-optimizer' ); ?>
11931
+ <?php if ( function_exists( 'imsanity_get_max_width_height' ) ) : ?>
11932
+ <p>
11933
+ <span style="color: #3eadc9"><?php esc_html_e( '*Imsanity settings override the resize dimensions.', 'ewww-image-optimizer' ); ?></span>
11934
+ </p>
11935
+ <?php else : ?>
11936
  <p class='description'>
11937
  <?php esc_html_e( 'Resize uploaded images to these dimensions (in pixels).', 'ewww-image-optimizer' ); ?>
11938
  </p>
11939
+ <?php endif; ?>
11940
  </td>
11941
  </tr>
11942
  <tr>
11955
  <?php endif; ?>
11956
  <p class='description'>
11957
  <?php esc_html_e( 'The lazy loader chooses the best available image size from existing responsive markup. When used with Easy IO, all images become responsive.', 'ewww-image-optimizer' ); ?></br>
11958
+ </p>
11959
+ </td>
11960
+ </tr>
11961
+ <tr id='ewww_image_optimizer_ll_autoscale_container' <?php echo ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) ? '' : ' style="display:none"'; ?>>
11962
+ <td>&nbsp;</td>
11963
+ <td>
11964
+ <input type='checkbox' name='ewww_image_optimizer_ll_autoscale' value='true' id='ewww_image_optimizer_ll_autoscale' <?php checked( ewww_image_optimizer_get_option( 'ewww_image_optimizer_ll_autoscale' ) ); ?> />
11965
+ <label for='ewww_image_optimizer_ll_autoscale'><strong><?php esc_html_e( 'Automatic Scaling', 'ewww-image-optimizer' ); ?></strong></label>
11966
+ <?php ewwwio_help_link( 'https://docs.ewww.io/article/74-lazy-load', '5c6c36ed042863543ccd2d9b' ); ?>
11967
+ <p class='description'>
11968
+ <?php esc_html_e( 'Automatically detect the correct image size within responsive (srcset) markup.', 'ewww-image-optimizer' ); ?>
11969
+ </p>
11970
+ </td>
11971
+ </tr>
11972
+ <tr id='ewww_image_optimizer_siip_container' <?php echo ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) ? '' : ' style="display:none"'; ?>>
11973
+ <td>&nbsp;</td>
11974
+ <td>
11975
+ <input type='checkbox' name='ewww_image_optimizer_use_siip' value='true' id='ewww_image_optimizer_use_siip' <?php checked( ewww_image_optimizer_get_option( 'ewww_image_optimizer_use_siip' ) ); ?> />
11976
+ <label for='ewww_image_optimizer_use_siip'><strong><?php esc_html_e( 'SVG Placeholders', 'ewww-image-optimizer' ); ?></strong></label>
11977
+ <?php ewwwio_help_link( 'https://docs.ewww.io/article/75-lazy-load-placeholders', '5c9a7a302c7d3a1544615e47' ); ?>
11978
+ <p class='description'>
11979
+ <?php esc_html_e( 'Inline SVG placeholders use fewer HTTP requests than right-sized PNG placeholders, but may not work with some themes.', 'ewww-image-optimizer' ); ?>
11980
  </p>
11981
  </td>
11982
  </tr>
11991
  </p>
11992
  </td>
11993
  </tr>
11994
+ <tr id='ewww_image_optimizer_ll_all_things_container' <?php echo ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) ? '' : ' style="display:none"'; ?>>
11995
+ <td>&nbsp;</td>
11996
+ <td>
11997
+ <label for='ewww_image_optimizer_ll_all_things'><strong><?php esc_html_e( 'External Background Images', 'ewww-image-optimizer' ); ?></strong></label>
11998
+ <?php ewwwio_help_link( 'https://docs.ewww.io/article/74-lazy-load', '5c6c36ed042863543ccd2d9b' ); ?><br>
11999
+ <input type='text' name='ewww_image_optimizer_ll_all_things' id='ewww_image_optimizer_all_things' class='regular-text' value='<?php echo esc_attr( ewww_image_optimizer_get_option( 'ewww_image_optimizer_ll_all_things' ) ); ?>' />
12000
+ <p class='description'>
12001
+ <?php esc_html_e( 'Specify class/id values of elements with CSS background images (comma-separated).', 'ewww-image-optimizer' ); ?>
12002
+ <br>*<?php esc_html_e( 'Background images directly attached via inline style attributes will be lazy loaded by default.', 'ewww-image-optimizer' ); ?>
12003
+ </p>
12004
+ </td>
12005
+ </tr>
12006
+ <?php if ( true || ! $easymode ) : ?>
12007
+ <?php endif; ?>
12008
  <tr id='ewww_image_optimizer_ll_exclude_container' <?php echo ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) ? '' : ' style="display:none"'; ?>>
12009
  <td>&nbsp;</td>
12010
  <td>
12016
  </p>
12017
  </td>
12018
  </tr>
12019
+ <?php if ( false && $easymode ) : ?>
12020
+ <tr id='ewww_image_optimizer_more_options_container' <?php echo ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) ? '' : ' style="display:none"'; ?>>
12021
+ <td>&nbsp;</td>
12022
+ <td>
12023
+ <p class='description'>
12024
+ <?php
12025
+ printf(
12026
+ /* translators: %s: Ludicrous Mode */
12027
+ '*' . esc_html__( 'More Lazy Load options are available in %s.', 'ewww-image-optimizer' ),
12028
+ "<a href='" . esc_url( $enable_local_url ) . "'>" . esc_html__( 'Ludicrous Mode', 'ewww-image-optimizer' ) . '</a>'
12029
+ );
12030
+ ?>
12031
+ </p>
12032
+ </td>
12033
+ </tr>
12034
+ <?php endif; ?>
12035
  <?php endif; ?>
12036
  <?php if ( $free_exec ) : ?>
12037
  <tr>
12590
  <?php esc_html_e( 'Highlight images that need to be resized because the browser is scaling them down. Only visible for Admin users and adds a button to the admin bar to detect scaled images that have been lazy loaded.', 'ewww-image-optimizer' ); ?>
12591
  </td>
12592
  </tr>
 
 
 
 
 
 
 
 
 
 
12593
  <tr>
12594
  <th scope='row'>
12595
  <label for='ewww_image_optimizer_resize_existing'><?php esc_html_e( 'Resize Existing Images', 'ewww-image-optimizer' ); ?></label>
ewww-image-optimizer.php CHANGED
@@ -13,7 +13,7 @@ Plugin Name: EWWW Image Optimizer
13
  Plugin URI: https://wordpress.org/plugins/ewww-image-optimizer/
14
  Description: Reduce file sizes for images within WordPress including NextGEN Gallery and GRAND FlAGallery. Uses jpegtran, optipng/pngout, and gifsicle.
15
  Author: Exactly WWW
16
- Version: 6.0.3
17
  Author URI: https://ewww.io/
18
  License: GPLv3
19
  */
13
  Plugin URI: https://wordpress.org/plugins/ewww-image-optimizer/
14
  Description: Reduce file sizes for images within WordPress including NextGEN Gallery and GRAND FlAGallery. Uses jpegtran, optipng/pngout, and gifsicle.
15
  Author: Exactly WWW
16
+ Version: 6.1.0
17
  Author URI: https://ewww.io/
18
  License: GPLv3
19
  */
includes/eio-settings.js CHANGED
@@ -289,9 +289,15 @@ jQuery(document).ready(function($) {
289
  $('#ewww_image_optimizer_lazy_load').on( 'click', function() {
290
  if($(this).prop('checked')) {
291
  $('#ewww_image_optimizer_ll_exclude_container').fadeIn();
 
 
 
292
  $('#ewww_image_optimizer_lqip_container').fadeIn();
293
  } else {
294
  $('#ewww_image_optimizer_ll_exclude_container').fadeOut();
 
 
 
295
  $('#ewww_image_optimizer_lqip_container').fadeOut();
296
  }
297
  });
289
  $('#ewww_image_optimizer_lazy_load').on( 'click', function() {
290
  if($(this).prop('checked')) {
291
  $('#ewww_image_optimizer_ll_exclude_container').fadeIn();
292
+ $('#ewww_image_optimizer_ll_autoscale_container').fadeIn();
293
+ $('#ewww_image_optimizer_ll_all_things_container').fadeIn();
294
+ $('#ewww_image_optimizer_siip_container').fadeIn();
295
  $('#ewww_image_optimizer_lqip_container').fadeIn();
296
  } else {
297
  $('#ewww_image_optimizer_ll_exclude_container').fadeOut();
298
+ $('#ewww_image_optimizer_ll_autoscale_container').fadeOut();
299
+ $('#ewww_image_optimizer_ll_all_things_container').fadeOut();
300
+ $('#ewww_image_optimizer_siip_container').fadeOut();
301
  $('#ewww_image_optimizer_lqip_container').fadeOut();
302
  }
303
  });
includes/lazysizes-post.js CHANGED
@@ -109,7 +109,8 @@ function constrainSrc(url,objectWidth,objectHeight,objectType){
109
  return url;
110
  }
111
  document.addEventListener('lazybeforesizes', function(e){
112
- console.log('auto-sizing to: ' + e.detail.width);
 
113
  if (e.target._lazysizesWidth === undefined) {
114
  return;
115
  }
@@ -125,16 +126,25 @@ document.addEventListener('lazybeforeunveil', function(e){
125
  console.log(target);
126
  var wrongSize = false;
127
  var srcset = target.getAttribute('data-srcset');
128
- if ( target.naturalWidth) {
129
  console.log('we have an image with no srcset');
130
  if ((target.naturalWidth > 1) && (target.naturalHeight > 1)) {
131
  // For each image with a natural width which isn't
132
  // a 1x1 image, check its size.
133
  var dPR = (window.devicePixelRatio || 1);
134
- var wrongWidth = (target.clientWidth && (target.clientWidth * 1.25 < target.naturalWidth));
135
- var wrongHeight = (target.clientHeight && (target.clientHeight * 1.25 < target.naturalHeight));
136
- console.log(Math.round(target.clientWidth * dPR) + "x" + Math.round(target.clientHeight * dPR) + ", natural is " +
137
- target.naturalWidth + "x" + target.naturalHeight + "!");
 
 
 
 
 
 
 
 
 
138
  console.log('the data-src: ' + target.getAttribute('data-src') );
139
  if (wrongWidth || wrongHeight) {
140
  var targetWidth = Math.round(target.offsetWidth * dPR);
109
  return url;
110
  }
111
  document.addEventListener('lazybeforesizes', function(e){
112
+ var src = e.target.getAttribute('data-src');
113
+ console.log('auto-sizing ' + src + ' to: ' + e.detail.width);
114
  if (e.target._lazysizesWidth === undefined) {
115
  return;
116
  }
126
  console.log(target);
127
  var wrongSize = false;
128
  var srcset = target.getAttribute('data-srcset');
129
+ if (target.naturalWidth && ! srcset) {
130
  console.log('we have an image with no srcset');
131
  if ((target.naturalWidth > 1) && (target.naturalHeight > 1)) {
132
  // For each image with a natural width which isn't
133
  // a 1x1 image, check its size.
134
  var dPR = (window.devicePixelRatio || 1);
135
+ var physicalWidth = target.naturalWidth;
136
+ var physicalHeight = target.naturalHeight;
137
+ var realWidth = target.getAttribute('data-eio-rwidth');
138
+ var realHeight = target.getAttribute('data-eio-rheight');
139
+ if (realWidth && realWidth > physicalWidth) {
140
+ console.log( 'using ' + realWidth + 'w instead of ' + physicalWidth + 'w and ' + realHeight + 'h instead of ' + physicalHeight + 'h from data-eio-r*')
141
+ physicalWidth = realWidth;
142
+ physicalHeight = realHeight;
143
+ }
144
+ var wrongWidth = (target.clientWidth && (target.clientWidth * 1.25 < physicalWidth));
145
+ var wrongHeight = (target.clientHeight && (target.clientHeight * 1.25 < physicalHeight));
146
+ console.log('displayed at ' + Math.round(target.clientWidth * dPR) + 'w x ' + Math.round(target.clientHeight * dPR) + 'h, natural/physical is ' +
147
+ physicalWidth + 'w x ' + physicalHeight + 'h!');
148
  console.log('the data-src: ' + target.getAttribute('data-src') );
149
  if (wrongWidth || wrongHeight) {
150
  var targetWidth = Math.round(target.offsetWidth * dPR);
includes/lazysizes-pre.js CHANGED
@@ -16,3 +16,8 @@ function lazysizesWebP(feature, callback) {
16
  }
17
  window.lazySizesConfig = window.lazySizesConfig || {};
18
  window.lazySizesConfig.init = false;
 
 
 
 
 
16
  }
17
  window.lazySizesConfig = window.lazySizesConfig || {};
18
  window.lazySizesConfig.init = false;
19
+ window.lazySizesConfig.expand = document.documentElement.clientHeight > 500 && document.documentElement.clientWidth > 500 ? 1000 : 740;
20
+ if (eio_lazy_vars.threshold > 50) {
21
+ window.lazySizesConfig.expand = eio_lazy_vars.threshold;
22
+ }
23
+ console.log( 'root margin: ' + window.lazySizesConfig.expand );
includes/lazysizes.min.js CHANGED
@@ -1 +1 @@
1
- var ewww_webp_supported=!1;function lazysizesWebP(e,t){var a=new Image;a.onload=function(){ewww_webp_supported=0<a.width&&0<a.height,t()},a.onerror=function(){t()},a.src="data:image/webp;base64,"+{alpha:"UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",animation:"UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"}[e]}function shouldAutoScale(e){if(1==eio_lazy_vars.skip_autoscale)return!1;if(e.hasAttributes())for(var t=e.attributes,a=/skip-autoscale/,i=t.length-1;0<=i;i--){if(a.test(t[i].name))return!1;if(a.test(t[i].value))return!1}return!0}function constrainSrc(e,t,a,i){if(null===e)return e;var r=/w=(\d+)/,n=/fit=(\d+),(\d+)/,o=/resize=(\d+),(\d+)/,s=decodeURIComponent(e);if("undefined"==typeof eio_lazy_vars&&(eio_lazy_vars={exactdn_domain:".exactdn.com"}),0<e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)){var l=o.exec(s);if(l&&t<l[1])return s.replace(o,"resize="+t+","+a);var d=r.exec(e);if(d&&t<=d[1]){if("bg-cover"!==i&&"img-crop"!==i)return e.replace(r,"w="+t);var c=d[1]-t;return 20<c||a<1080?e.replace(r,"resize="+t+","+a):e}var u=n.exec(s);if(u&&t<u[1]){if("bg-cover"!==i&&"img-crop"!==i)return s.replace(n,"fit="+t+","+a);var f=u[1]-t,A=u[2]-a;return 20<f||20<A?e.replace(r,"resize="+t+","+a):e}if(!d&&!u&&!l)return"img"===i?e+"&fit="+t+","+a:"bg-cover"===i||"img-crop"===i?e+"?resize="+t+","+a:t<a?e+"&h="+a:e+"&w="+t}return-1==e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)?"img"===i?e+"?fit="+t+","+a:"bg-cover"===i||"img-crop"===i?e+"?resize="+t+","+a:t<a?e+"?h="+a:e+"?w="+t:e}window.lazySizesConfig=window.lazySizesConfig||{},window.lazySizesConfig.init=!1,function(e,t){var a=function(i,A,n){"use strict";var g,h;if(function(){var e,t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",fastLoadedClass:"ls-is-cached",iframeLoadMode:0,srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:!0,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:!0,ricTimeout:0,throttleDelay:125};for(e in h=i.lazySizesConfig||i.lazysizesConfig||{},t)e in h||(h[e]=t[e])}(),!A||!A.getElementsByClassName)return{init:function(){},cfg:h,noSupport:!0};var z=A.documentElement,r=i.HTMLPictureElement,o="addEventListener",v="getAttribute",e=i[o].bind(i),m=i.setTimeout,a=i.requestAnimationFrame||m,s=i.requestIdleCallback,p=/^picture$/i,l=["load","error","lazyincluded","_lazyloaded"],d={},y=Array.prototype.forEach,c=function(e,t){return d[t]||(d[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")),d[t].test(e[v]("class")||"")&&d[t]},b=function(e,t){c(e,t)||e.setAttribute("class",(e[v]("class")||"").trim()+" "+t)},w=function(e,t){var a;(a=c(e,t))&&e.setAttribute("class",(e[v]("class")||"").replace(a," "))},_=function(t,a,e){var i=e?o:"removeEventListener";e&&_(t,a),l.forEach(function(e){t[i](e,a)})},C=function(e,t,a,i,r){var n=A.createEvent("Event");return a||(a={}),a.instance=g,n.initEvent(t,!i,!r),n.detail=a,e.dispatchEvent(n),n},E=function(e,t){var a;!r&&(a=i.picturefill||h.pf)?(t&&t.src&&!e[v]("srcset")&&e.setAttribute("srcset",t.src),a({reevaluate:!0,elements:[e]})):t&&t.src&&(e.src=t.src)},u=function(e,t){return(getComputedStyle(e,null)||{})[t]},f=function(e,t,a){for(a=a||e.offsetWidth;a<h.minSize&&t&&!e._lazysizesWidth;)a=t.offsetWidth,t=t.parentNode;return a},S=(we=[],_e=[],Ce=we,Ee=function(){var e=Ce;for(Ce=we.length?_e:we,be=!(ye=!0);e.length;)e.shift()();ye=!1},Se=function(e,t){ye&&!t?e.apply(this,arguments):(Ce.push(e),be||(be=!0,(A.hidden?m:a)(Ee)))},Se._lsFlush=Ee,Se),t=function(a,e){return e?function(){S(a)}:function(){var e=this,t=arguments;S(function(){a.apply(e,t)})}},W=function(e){var t,a,i=function(){t=null,e()},r=function(){var e=n.now()-a;e<99?m(r,99-e):(s||i)(i)};return function(){a=n.now(),t||(t=m(r,99))}},x=(ee=/^img$/i,te=/^iframe$/i,ae="onscroll"in i&&!/(gle|ing)bot/.test(navigator.userAgent),ie=0,re=0,ne=-1,oe=function(e){re--,(!e||re<0||!e.target)&&(re=0)},se=function(e){return null==$&&($="hidden"==u(A.body,"visibility")),$||!("hidden"==u(e.parentNode,"visibility")&&"hidden"==u(e,"visibility"))},le=function(e,t){var a,i=e,r=se(e);for(I-=t,G+=t,J-=t,O+=t;r&&(i=i.offsetParent)&&i!=A.body&&i!=z;)(r=0<(u(i,"opacity")||1))&&"visible"!=u(i,"overflow")&&(a=i.getBoundingClientRect(),r=O>a.left&&J<a.right&&G>a.top-1&&I<a.bottom+1);return r},de=function(){var e,t,a,i,r,n,o,s,l,d,c,u,f=g.elements;if((H=h.loadMode)&&re<8&&(e=f.length)){for(t=0,ne++;t<e;t++)if(f[t]&&!f[t]._lazyRace)if(!ae||g.prematureUnveil&&g.prematureUnveil(f[t]))ze(f[t]);else if((s=f[t][v]("data-expand"))&&(n=1*s)||(n=ie),d||(d=!h.expand||h.expand<1?500<z.clientHeight&&500<z.clientWidth?500:370:h.expand,g._defEx=d,c=d*h.expFactor,u=h.hFac,$=null,ie<c&&re<1&&2<ne&&2<H&&!A.hidden?(ie=c,ne=0):ie=1<H&&1<ne&&re<6?d:0),l!==n&&(U=innerWidth+n*u,F=innerHeight+n,o=-1*n,l=n),a=f[t].getBoundingClientRect(),(G=a.bottom)>=o&&(I=a.top)<=F&&(O=a.right)>=o*u&&(J=a.left)<=U&&(G||O||J||I)&&(h.loadHidden||se(f[t]))&&(P&&re<3&&!s&&(H<3||ne<4)||le(f[t],n))){if(ze(f[t]),r=!0,9<re)break}else!r&&P&&!i&&re<4&&ne<4&&2<H&&(k[0]||h.preloadAfterLoad)&&(k[0]||!s&&(G||O||J||I||"auto"!=f[t][v](h.sizesAttr)))&&(i=k[0]||f[t]);i&&!r&&ze(i)}},q=de,V=0,X=h.throttleDelay,Y=h.ricTimeout,K=function(){j=!1,V=n.now(),q()},Z=s&&49<Y?function(){s(K,{timeout:Y}),Y!==h.ricTimeout&&(Y=h.ricTimeout)}:t(function(){m(K)},!0),ce=function(e){var t;(e=!0===e)&&(Y=33),j||(j=!0,(t=X-(n.now()-V))<0&&(t=0),e||t<9?Z():m(Z,t))},ue=function(e){var t=e.target;t._lazyCache?delete t._lazyCache:(oe(e),b(t,h.loadedClass),w(t,h.loadingClass),_(t,Ae),C(t,"lazyloaded"))},fe=t(ue),Ae=function(e){fe({target:e.target})},ge=function(e){var t,a=e[v](h.srcsetAttr);(t=h.customMedia[e[v]("data-media")||e[v]("media")])&&e.setAttribute("media",t),a&&e.setAttribute("srcset",a)},he=t(function(t,e,a,i,r){var n,o,s,l,d,c,u,f,A;(d=C(t,"lazybeforeunveil",e)).defaultPrevented||(i&&(a?b(t,h.autosizesClass):t.setAttribute("sizes",i)),o=t[v](h.srcsetAttr),n=t[v](h.srcAttr),r&&(s=t.parentNode,l=s&&p.test(s.nodeName||"")),c=e.firesLoad||"src"in t&&(o||n||l),d={target:t},b(t,h.loadingClass),c&&(clearTimeout(D),D=m(oe,2500),_(t,Ae,!0)),l&&y.call(s.getElementsByTagName("source"),ge),o?t.setAttribute("srcset",o):n&&!l&&(te.test(t.nodeName)?(f=n,0==(A=(u=t).getAttribute("data-load-mode")||h.iframeLoadMode)?u.contentWindow.location.replace(f):1==A&&(u.src=f)):t.src=n),r&&(o||l)&&E(t,{src:n})),t._lazyRace&&delete t._lazyRace,w(t,h.lazyClass),S(function(){var e=t.complete&&1<t.naturalWidth;c&&!e||(e&&b(t,h.fastLoadedClass),ue(d),t._lazyCache=!0,m(function(){"_lazyCache"in t&&delete t._lazyCache},9)),"lazy"==t.loading&&re--},!0)}),ze=function(e){if(!e._lazyRace){var t,a=ee.test(e.nodeName),i=a&&(e[v](h.sizesAttr)||e[v]("sizes")),r="auto"==i;(!r&&P||!a||!e[v]("src")&&!e.srcset||e.complete||c(e,h.errorClass)||!c(e,h.lazyClass))&&(t=C(e,"lazyunveilread").detail,r&&M.updateElem(e,!0,e.offsetWidth),e._lazyRace=!0,re++,he(e,t,r,i,a))}},ve=W(function(){h.loadMode=3,ce()}),me=function(){3==h.loadMode&&(h.loadMode=2),ve()},pe=function(){P||(n.now()-T<999?m(pe,999):(P=!0,h.loadMode=3,ce(),e("scroll",me,!0)))},{_:function(){T=n.now(),g.elements=A.getElementsByClassName(h.lazyClass),k=A.getElementsByClassName(h.lazyClass+" "+h.preloadClass),e("scroll",ce,!0),e("resize",ce,!0),e("pageshow",function(e){if(e.persisted){var t=A.querySelectorAll("."+h.loadingClass);t.length&&t.forEach&&a(function(){t.forEach(function(e){e.complete&&ze(e)})})}}),i.MutationObserver?new MutationObserver(ce).observe(z,{childList:!0,subtree:!0,attributes:!0}):(z[o]("DOMNodeInserted",ce,!0),z[o]("DOMAttrModified",ce,!0),setInterval(ce,999)),e("hashchange",ce,!0),["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){A[o](e,ce,!0)}),/d$|^c/.test(A.readyState)?pe():(e("load",pe),A[o]("DOMContentLoaded",ce),m(pe,2e4)),g.elements.length?(de(),S._lsFlush()):ce()},checkElems:ce,unveil:ze,_aLSL:me}),M=(N=t(function(e,t,a,i){var r,n,o;if(e._lazysizesWidth=i,i+="px",e.setAttribute("sizes",i),p.test(t.nodeName||""))for(r=t.getElementsByTagName("source"),n=0,o=r.length;n<o;n++)r[n].setAttribute("sizes",i);a.detail.dataAttr||E(e,a.detail)}),R=function(e,t,a){var i,r=e.parentNode;r&&(a=f(e,r,a),(i=C(e,"lazybeforesizes",{width:a,dataAttr:!!t})).defaultPrevented||(a=i.detail.width)&&a!==e._lazysizesWidth&&N(e,r,i,a))},Q=W(function(){var e,t=L.length;if(t)for(e=0;e<t;e++)R(L[e])}),{_:function(){L=A.getElementsByClassName(h.autosizesClass),e("resize",Q)},checkElems:Q,updateElem:R}),B=function(){!B.i&&A.getElementsByClassName&&(B.i=!0,M._(),x._())};var L,N,R,Q;var k,P,D,H,T,U,F,I,J,O,G,$,q,j,V,X,Y,K,Z,ee,te,ae,ie,re,ne,oe,se,le,de,ce,ue,fe,Ae,ge,he,ze,ve,me,pe;var ye,be,we,_e,Ce,Ee,Se;return m(function(){h.init&&B()}),g={cfg:h,autoSizer:M,loader:x,init:B,uP:E,aC:b,rC:w,hC:c,fire:C,gW:f,rAF:S}}(e,e.document,Date);e.lazySizes=a,"object"==typeof module&&module.exports&&(module.exports=a)}("undefined"!=typeof window?window:{}),lazysizesWebP("alpha",lazySizes.init),document.addEventListener("lazybeforesizes",function(e){void 0!==e.target._lazysizesWidth&&e.detail.width<e.target._lazysizesWidth&&(e.detail.width=e.target._lazysizesWidth)}),document.addEventListener("lazybeforeunveil",function(e){var t=e.target,a=t.getAttribute("data-srcset");if(t.naturalWidth&&1<t.naturalWidth&&1<t.naturalHeight){var i=window.devicePixelRatio||1,r=t.clientWidth&&1.25*t.clientWidth<t.naturalWidth,n=t.clientHeight&&1.25*t.clientHeight<t.naturalHeight;if(r||n){var o=Math.round(t.offsetWidth*i),s=Math.round(t.offsetHeight*i),l=t.getAttribute("data-src"),d=t.getAttribute("data-src-webp");if(ewww_webp_supported&&d&&-1==l.search("webp=1")&&(l=d),shouldAutoScale(t)&&shouldAutoScale(t.parentNode))if(window.lazySizes.hC(t,"et_pb_jt_filterable_grid_item_image")||window.lazySizes.hC(t,"ss-foreground-image"))c=constrainSrc(l,o,s,"img-crop");else c=constrainSrc(l,o,s,"img");else var c=!1;c&&l!=c&&t.setAttribute("data-src",c)}}if(ewww_webp_supported){if(a){var u=t.getAttribute("data-srcset-webp");u&&t.setAttribute("data-srcset",u)}if(!(d=t.getAttribute("data-src-webp")))return;t.setAttribute("data-src",d)}}),function(e,t){var a=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(o,e,s){"use strict";var l;e.addEventListener&&(l=/\(|\)|\s|'/,addEventListener("lazybeforeunveil",function(e){var t,a;if(e.detail.instance==s&&(!e.defaultPrevented&&("none"==e.target.preload&&(e.target.preload="auto"),t=e.target.getAttribute("data-bg")))){ewww_webp_supported&&(a=e.target.getAttribute("data-bg-webp"))&&(t=a);var i=o.devicePixelRatio||1,r=Math.round(e.target.offsetWidth*i),n=Math.round(e.target.offsetHeight*i);shouldAutoScale(e.target)&&shouldAutoScale(e.target.parentNode)&&(t=o.lazySizes.hC(e.target,"wp-block-cover")?(o.lazySizes.hC(e.target,"has-parallax")&&(r=Math.round(o.screen.width*i),n=Math.round(o.screen.height*i)),constrainSrc(t,r,n,"bg-cover")):o.lazySizes.hC(e.target,"elementor-bg")?constrainSrc(t,r,n,"bg-cover"):constrainSrc(t,r,n,"bg")),e.target.style.backgroundImage="url("+(l.test(t)?JSON.stringify(t):t)+")"}},!1))});
1
+ var ewww_webp_supported=!1;function lazysizesWebP(e,t){var a=new Image;a.onload=function(){ewww_webp_supported=0<a.width&&0<a.height,t()},a.onerror=function(){t()},a.src="data:image/webp;base64,"+{alpha:"UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",animation:"UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"}[e]}function shouldAutoScale(e){if(1==eio_lazy_vars.skip_autoscale)return!1;if(e.hasAttributes())for(var t=e.attributes,a=/skip-autoscale/,i=t.length-1;0<=i;i--){if(a.test(t[i].name))return!1;if(a.test(t[i].value))return!1}return!0}function constrainSrc(e,t,a,i){if(null===e)return e;var r=/w=(\d+)/,n=/fit=(\d+),(\d+)/,o=/resize=(\d+),(\d+)/,s=decodeURIComponent(e);if("undefined"==typeof eio_lazy_vars&&(eio_lazy_vars={exactdn_domain:".exactdn.com"}),0<e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)){var l=o.exec(s);if(l&&t<l[1])return s.replace(o,"resize="+t+","+a);var d=r.exec(e);if(d&&t<=d[1]){if("bg-cover"!==i&&"img-crop"!==i)return e.replace(r,"w="+t);var c=d[1]-t;return 20<c||a<1080?e.replace(r,"resize="+t+","+a):e}var u=n.exec(s);if(u&&t<u[1]){if("bg-cover"!==i&&"img-crop"!==i)return s.replace(n,"fit="+t+","+a);var f=u[1]-t,A=u[2]-a;return 20<f||20<A?e.replace(r,"resize="+t+","+a):e}if(!d&&!u&&!l)return"img"===i?e+"&fit="+t+","+a:"bg-cover"===i||"img-crop"===i?e+"?resize="+t+","+a:t<a?e+"&h="+a:e+"&w="+t}return-1==e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)?"img"===i?e+"?fit="+t+","+a:"bg-cover"===i||"img-crop"===i?e+"?resize="+t+","+a:t<a?e+"?h="+a:e+"?w="+t:e}window.lazySizesConfig=window.lazySizesConfig||{},window.lazySizesConfig.init=!1,window.lazySizesConfig.expand=500<document.documentElement.clientHeight&&500<document.documentElement.clientWidth?1e3:740,50<eio_lazy_vars.threshold&&(window.lazySizesConfig.expand=eio_lazy_vars.threshold),function(e,t){var a=function(i,A,n){"use strict";var g,h;if(function(){var e,t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",fastLoadedClass:"ls-is-cached",iframeLoadMode:0,srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:!0,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:!0,ricTimeout:0,throttleDelay:125};for(e in h=i.lazySizesConfig||i.lazysizesConfig||{},t)e in h||(h[e]=t[e])}(),!A||!A.getElementsByClassName)return{init:function(){},cfg:h,noSupport:!0};var z=A.documentElement,r=i.HTMLPictureElement,o="addEventListener",v="getAttribute",e=i[o].bind(i),m=i.setTimeout,a=i.requestAnimationFrame||m,s=i.requestIdleCallback,p=/^picture$/i,l=["load","error","lazyincluded","_lazyloaded"],d={},y=Array.prototype.forEach,c=function(e,t){return d[t]||(d[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")),d[t].test(e[v]("class")||"")&&d[t]},b=function(e,t){c(e,t)||e.setAttribute("class",(e[v]("class")||"").trim()+" "+t)},w=function(e,t){var a;(a=c(e,t))&&e.setAttribute("class",(e[v]("class")||"").replace(a," "))},_=function(t,a,e){var i=e?o:"removeEventListener";e&&_(t,a),l.forEach(function(e){t[i](e,a)})},C=function(e,t,a,i,r){var n=A.createEvent("Event");return a||(a={}),a.instance=g,n.initEvent(t,!i,!r),n.detail=a,e.dispatchEvent(n),n},E=function(e,t){var a;!r&&(a=i.picturefill||h.pf)?(t&&t.src&&!e[v]("srcset")&&e.setAttribute("srcset",t.src),a({reevaluate:!0,elements:[e]})):t&&t.src&&(e.src=t.src)},u=function(e,t){return(getComputedStyle(e,null)||{})[t]},f=function(e,t,a){for(a=a||e.offsetWidth;a<h.minSize&&t&&!e._lazysizesWidth;)a=t.offsetWidth,t=t.parentNode;return a},S=(we=[],_e=[],Ce=we,Ee=function(){var e=Ce;for(Ce=we.length?_e:we,be=!(ye=!0);e.length;)e.shift()();ye=!1},Se=function(e,t){ye&&!t?e.apply(this,arguments):(Ce.push(e),be||(be=!0,(A.hidden?m:a)(Ee)))},Se._lsFlush=Ee,Se),t=function(a,e){return e?function(){S(a)}:function(){var e=this,t=arguments;S(function(){a.apply(e,t)})}},W=function(e){var t,a,i=function(){t=null,e()},r=function(){var e=n.now()-a;e<99?m(r,99-e):(s||i)(i)};return function(){a=n.now(),t||(t=m(r,99))}},x=(ee=/^img$/i,te=/^iframe$/i,ae="onscroll"in i&&!/(gle|ing)bot/.test(navigator.userAgent),ie=0,re=0,ne=-1,oe=function(e){re--,(!e||re<0||!e.target)&&(re=0)},se=function(e){return null==$&&($="hidden"==u(A.body,"visibility")),$||!("hidden"==u(e.parentNode,"visibility")&&"hidden"==u(e,"visibility"))},le=function(e,t){var a,i=e,r=se(e);for(I-=t,G+=t,J-=t,O+=t;r&&(i=i.offsetParent)&&i!=A.body&&i!=z;)(r=0<(u(i,"opacity")||1))&&"visible"!=u(i,"overflow")&&(a=i.getBoundingClientRect(),r=O>a.left&&J<a.right&&G>a.top-1&&I<a.bottom+1);return r},de=function(){var e,t,a,i,r,n,o,s,l,d,c,u,f=g.elements;if((D=h.loadMode)&&re<8&&(e=f.length)){for(t=0,ne++;t<e;t++)if(f[t]&&!f[t]._lazyRace)if(!ae||g.prematureUnveil&&g.prematureUnveil(f[t]))ze(f[t]);else if((s=f[t][v]("data-expand"))&&(n=1*s)||(n=ie),d||(d=!h.expand||h.expand<1?500<z.clientHeight&&500<z.clientWidth?500:370:h.expand,g._defEx=d,c=d*h.expFactor,u=h.hFac,$=null,ie<c&&re<1&&2<ne&&2<D&&!A.hidden?(ie=c,ne=0):ie=1<D&&1<ne&&re<6?d:0),l!==n&&(U=innerWidth+n*u,F=innerHeight+n,o=-1*n,l=n),a=f[t].getBoundingClientRect(),(G=a.bottom)>=o&&(I=a.top)<=F&&(O=a.right)>=o*u&&(J=a.left)<=U&&(G||O||J||I)&&(h.loadHidden||se(f[t]))&&(P&&re<3&&!s&&(D<3||ne<4)||le(f[t],n))){if(ze(f[t]),r=!0,9<re)break}else!r&&P&&!i&&re<4&&ne<4&&2<D&&(k[0]||h.preloadAfterLoad)&&(k[0]||!s&&(G||O||J||I||"auto"!=f[t][v](h.sizesAttr)))&&(i=k[0]||f[t]);i&&!r&&ze(i)}},q=de,V=0,X=h.throttleDelay,Y=h.ricTimeout,K=function(){j=!1,V=n.now(),q()},Z=s&&49<Y?function(){s(K,{timeout:Y}),Y!==h.ricTimeout&&(Y=h.ricTimeout)}:t(function(){m(K)},!0),ce=function(e){var t;(e=!0===e)&&(Y=33),j||(j=!0,(t=X-(n.now()-V))<0&&(t=0),e||t<9?Z():m(Z,t))},ue=function(e){var t=e.target;t._lazyCache?delete t._lazyCache:(oe(e),b(t,h.loadedClass),w(t,h.loadingClass),_(t,Ae),C(t,"lazyloaded"))},fe=t(ue),Ae=function(e){fe({target:e.target})},ge=function(e){var t,a=e[v](h.srcsetAttr);(t=h.customMedia[e[v]("data-media")||e[v]("media")])&&e.setAttribute("media",t),a&&e.setAttribute("srcset",a)},he=t(function(t,e,a,i,r){var n,o,s,l,d,c,u,f,A;(d=C(t,"lazybeforeunveil",e)).defaultPrevented||(i&&(a?b(t,h.autosizesClass):t.setAttribute("sizes",i)),o=t[v](h.srcsetAttr),n=t[v](h.srcAttr),r&&(s=t.parentNode,l=s&&p.test(s.nodeName||"")),c=e.firesLoad||"src"in t&&(o||n||l),d={target:t},b(t,h.loadingClass),c&&(clearTimeout(H),H=m(oe,2500),_(t,Ae,!0)),l&&y.call(s.getElementsByTagName("source"),ge),o?t.setAttribute("srcset",o):n&&!l&&(te.test(t.nodeName)?(f=n,0==(A=(u=t).getAttribute("data-load-mode")||h.iframeLoadMode)?u.contentWindow.location.replace(f):1==A&&(u.src=f)):t.src=n),r&&(o||l)&&E(t,{src:n})),t._lazyRace&&delete t._lazyRace,w(t,h.lazyClass),S(function(){var e=t.complete&&1<t.naturalWidth;c&&!e||(e&&b(t,h.fastLoadedClass),ue(d),t._lazyCache=!0,m(function(){"_lazyCache"in t&&delete t._lazyCache},9)),"lazy"==t.loading&&re--},!0)}),ze=function(e){if(!e._lazyRace){var t,a=ee.test(e.nodeName),i=a&&(e[v](h.sizesAttr)||e[v]("sizes")),r="auto"==i;(!r&&P||!a||!e[v]("src")&&!e.srcset||e.complete||c(e,h.errorClass)||!c(e,h.lazyClass))&&(t=C(e,"lazyunveilread").detail,r&&M.updateElem(e,!0,e.offsetWidth),e._lazyRace=!0,re++,he(e,t,r,i,a))}},ve=W(function(){h.loadMode=3,ce()}),me=function(){3==h.loadMode&&(h.loadMode=2),ve()},pe=function(){P||(n.now()-T<999?m(pe,999):(P=!0,h.loadMode=3,ce(),e("scroll",me,!0)))},{_:function(){T=n.now(),g.elements=A.getElementsByClassName(h.lazyClass),k=A.getElementsByClassName(h.lazyClass+" "+h.preloadClass),e("scroll",ce,!0),e("resize",ce,!0),e("pageshow",function(e){if(e.persisted){var t=A.querySelectorAll("."+h.loadingClass);t.length&&t.forEach&&a(function(){t.forEach(function(e){e.complete&&ze(e)})})}}),i.MutationObserver?new MutationObserver(ce).observe(z,{childList:!0,subtree:!0,attributes:!0}):(z[o]("DOMNodeInserted",ce,!0),z[o]("DOMAttrModified",ce,!0),setInterval(ce,999)),e("hashchange",ce,!0),["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){A[o](e,ce,!0)}),/d$|^c/.test(A.readyState)?pe():(e("load",pe),A[o]("DOMContentLoaded",ce),m(pe,2e4)),g.elements.length?(de(),S._lsFlush()):ce()},checkElems:ce,unveil:ze,_aLSL:me}),M=(N=t(function(e,t,a,i){var r,n,o;if(e._lazysizesWidth=i,i+="px",e.setAttribute("sizes",i),p.test(t.nodeName||""))for(r=t.getElementsByTagName("source"),n=0,o=r.length;n<o;n++)r[n].setAttribute("sizes",i);a.detail.dataAttr||E(e,a.detail)}),R=function(e,t,a){var i,r=e.parentNode;r&&(a=f(e,r,a),(i=C(e,"lazybeforesizes",{width:a,dataAttr:!!t})).defaultPrevented||(a=i.detail.width)&&a!==e._lazysizesWidth&&N(e,r,i,a))},Q=W(function(){var e,t=L.length;if(t)for(e=0;e<t;e++)R(L[e])}),{_:function(){L=A.getElementsByClassName(h.autosizesClass),e("resize",Q)},checkElems:Q,updateElem:R}),B=function(){!B.i&&A.getElementsByClassName&&(B.i=!0,M._(),x._())};var L,N,R,Q;var k,P,H,D,T,U,F,I,J,O,G,$,q,j,V,X,Y,K,Z,ee,te,ae,ie,re,ne,oe,se,le,de,ce,ue,fe,Ae,ge,he,ze,ve,me,pe;var ye,be,we,_e,Ce,Ee,Se;return m(function(){h.init&&B()}),g={cfg:h,autoSizer:M,loader:x,init:B,uP:E,aC:b,rC:w,hC:c,fire:C,gW:f,rAF:S}}(e,e.document,Date);e.lazySizes=a,"object"==typeof module&&module.exports&&(module.exports=a)}("undefined"!=typeof window?window:{}),lazysizesWebP("alpha",lazySizes.init),document.addEventListener("lazybeforesizes",function(e){e.target.getAttribute("data-src");void 0!==e.target._lazysizesWidth&&e.detail.width<e.target._lazysizesWidth&&(e.detail.width=e.target._lazysizesWidth)}),document.addEventListener("lazybeforeunveil",function(e){var t=e.target,a=t.getAttribute("data-srcset");if(t.naturalWidth&&!a&&1<t.naturalWidth&&1<t.naturalHeight){var i=window.devicePixelRatio||1,r=t.naturalWidth,n=t.naturalHeight,o=t.getAttribute("data-eio-rwidth"),s=t.getAttribute("data-eio-rheight");o&&r<o&&(r=o,n=s);var l=t.clientWidth&&1.25*t.clientWidth<r,d=t.clientHeight&&1.25*t.clientHeight<n;if(l||d){var c=Math.round(t.offsetWidth*i),u=Math.round(t.offsetHeight*i),f=t.getAttribute("data-src"),A=t.getAttribute("data-src-webp");if(ewww_webp_supported&&A&&-1==f.search("webp=1")&&(f=A),shouldAutoScale(t)&&shouldAutoScale(t.parentNode))if(window.lazySizes.hC(t,"et_pb_jt_filterable_grid_item_image")||window.lazySizes.hC(t,"ss-foreground-image"))g=constrainSrc(f,c,u,"img-crop");else g=constrainSrc(f,c,u,"img");else var g=!1;g&&f!=g&&t.setAttribute("data-src",g)}}if(ewww_webp_supported){if(a){var h=t.getAttribute("data-srcset-webp");h&&t.setAttribute("data-srcset",h)}if(!(A=t.getAttribute("data-src-webp")))return;t.setAttribute("data-src",A)}}),function(e,t){var a=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(o,e,s){"use strict";var l;e.addEventListener&&(l=/\(|\)|\s|'/,addEventListener("lazybeforeunveil",function(e){var t,a;if(e.detail.instance==s&&(!e.defaultPrevented&&("none"==e.target.preload&&(e.target.preload="auto"),t=e.target.getAttribute("data-bg")))){ewww_webp_supported&&(a=e.target.getAttribute("data-bg-webp"))&&(t=a);var i=o.devicePixelRatio||1,r=Math.round(e.target.offsetWidth*i),n=Math.round(e.target.offsetHeight*i);shouldAutoScale(e.target)&&shouldAutoScale(e.target.parentNode)&&(t=o.lazySizes.hC(e.target,"wp-block-cover")?(o.lazySizes.hC(e.target,"has-parallax")&&(r=Math.round(o.screen.width*i),n=Math.round(o.screen.height*i)),constrainSrc(t,r,n,"bg-cover")):o.lazySizes.hC(e.target,"elementor-bg")?constrainSrc(t,r,n,"bg-cover"):constrainSrc(t,r,n,"bg")),e.target.style.backgroundImage="url("+(l.test(t)?JSON.stringify(t):t)+")"}},!1))});
includes/resize_detection.js CHANGED
@@ -20,6 +20,7 @@ function checkImageSizes() {
20
  return false;
21
  }
22
  function checkImageScale(img) {
 
23
  if (img.naturalWidth) {
24
  if (img.naturalWidth > 25 && img.naturalHeight > 25 && img.clientWidth > 25 && img.clientHeight > 25) {
25
  // For each image with a natural width which isn't
20
  return false;
21
  }
22
  function checkImageScale(img) {
23
+ console.log('checking size of: ' + img.src);
24
  if (img.naturalWidth) {
25
  if (img.naturalWidth > 25 && img.naturalHeight > 25 && img.clientWidth > 25 && img.clientHeight > 25) {
26
  // For each image with a natural width which isn't
readme.txt CHANGED
@@ -2,10 +2,10 @@
2
  Contributors: nosilver4u
3
  Donate link: https://ewww.io/donate/
4
  Tags: optimize, image, convert, webp, resize, compress, lazy load, optimization, lossless, lossy, seo, scale
5
- Requires at least: 5.3
6
- Tested up to: 5.6
7
- Requires PHP: 5.6
8
- Stable tag: 6.0.3
9
  License: GPLv3
10
 
11
  Smaller Images, Faster Sites, Happier Visitors. Comprehensive image optimization that doesn't require a degree in rocket science.
@@ -50,7 +50,7 @@ Configure any folder within your WordPress install to be optimized. The Bulk Opt
50
 
51
  = Plugin Compatibility =
52
 
53
- EWWW IO has been tested with hundreds (if not thousands) of [plugins and themes](https://docs.ewww.io/article/84-plugin-compatibility), here are just a few of the most common ones: BuddyPress (Activity Plus add-on too), Cloudinary, Easy Watermark, FooGallery, GD bbPress Attachments, GRAND FlAGallery, Gmedia Photo Gallery, MediaPress, Meta Slider, Microsoft Azure Storage, MyArcadePlugin, NextGEN Gallery, Regenerate Thumbnails, WP Offload Media, [WPML](https://wpml.org/plugin/ewww-image-optimizer/), WP Retina 2x, WP RSS Aggregator, WP Symposium. [Read more...](https://docs.ewww.io/article/84-plugin-compatibility)
54
 
55
  = WebP Images =
56
 
@@ -132,93 +132,29 @@ That's not a question, but since I made it up, I'll answer it. See this resource
132
  * Feature requests can be viewed and submitted on our [feedback portal](https://feedback.ewww.io)
133
  * If you would like to help translate this plugin in your language, [join the team](https://translate.wordpress.org/projects/wp-plugins/ewww-image-optimizer/)
134
 
135
- = 6.0.3 =
136
- * fixed: syntax error on PHP 7.2 or less
137
-
138
- = 6.0.2 =
139
- * security: new version of PNGOUT available on settings page (if enabled)
140
- * added: compatibility with Phoenix Media Rename plugin
141
- * changed: Easy IO supports img tags with SVG images
142
- * fixed: bulk optimizer gives incorrect message about not enough credits for unlimited plans
143
- * fixed: db install workaround for MariaDB 10.4 bug
144
- * fixed: errors with custom db setups when DB_* constants are not defined
145
- * fixed: error with JS WebP when a class attribute with no value is encountered
146
-
147
- = 6.0.1 =
148
- * changed: more reliable Cloudflare detection for WebP delivery methods
149
- * fixed: lazy load for external CSS breaking div elements in JS/JSON
150
- * fixed: call to undefined function from Imsanity
151
- * fixed: database upgrade check triggers error on MySQL 8.0.17+
152
- * fixed: delete originals tool is slow
153
- * fixed: wpdb error when attempting to run migration routine for fresh installs
154
-
155
- = 6.0.0 =
156
- * added: tool to delete originals from WP 5.3+ auto-scaling behavior (Tools menu)
157
- * added: JS WebP recognizes video elements added via JS (e.g. infinite scroll)
158
- * added: automatically convert GIF to PNG during new uploads, unless animated
159
- * added: JS WebP and picture WebP auto-detect configuration for S3 Uploads and WP Stateless
160
- * added: Lazy Load for external CSS and separate style blocks (div elements only for now)
161
- * added: Easy IO/CDN rewriting for Ultimate Member AJAX-powered activity wall
162
- * changed: settings UI revamped with wizard for first-time installs
163
- * changed: automatic PNG to JPG threshold lowered to 250kb
164
- * changed: extensions for WP_Image_Editor now disabled by default, use EWWW_IMAGE_OPTIMIZER_ENABLE_EDITOR constant to enable them
165
- * changed: JS WebP can be used with picture WebP + Lazy Load to support CSS background images
166
- * changed: better compatibility with Theia Smart Thumbnails
167
- * changed: Lazy Load auto-sizing will no longer decrease the image size, only increasing is allowed
168
- * changed: filter to include additional HTML element types via eio_allowed_background_image_elements filter for Lazy Load and Easy IO
169
- * fixed: compatibility between Easy IO and Autoptimize
170
- * fixed: Easy IO uses hard crop when constraining an image via a width/height found in the style attribute
171
- * fixed: Easy IO uses hard-coded wp-content/ and wp-includes/ paths in some cases
172
- * fixed: Easy IO not activating properly when plugin is activated network-wide for multi-site installs
173
- * fixed: database upgrade throws errors on MariaDB 10.4.x
174
- * fixed: WebP .htaccess error in Vary header rule
175
- * fixed: Easy IO doubles part of image URL when there are no thumbnails, but one is requested by a plugin or theme
176
- * fixed: Easy IO minifier breaks Beaver Builder
177
- * fixed: Lazy Load breaks Beaver Builder text editor
178
- * removed: JS defer with Easy IO, use SWIS Performance instead: https://ewww.io/swis/
179
-
180
- = 5.8.2 =
181
- * security: improper nonce verification for Nextgen bulk optimizer initialization (minor severity)
182
- * changed: Easy IO verification performed via API for better reliability
183
- * fixed: Easy IO missing https availability for admin-ajax.php requests when home_url is using plain http
184
- * fixed: Easy IO silently fails to rewrite URLs when using CNAME with WP Offload Media
185
- * fixed: wp_lazy_loading_enabled filter should have 3 parameters
186
- * fixed: Easy IO shows alert for domain change when a non-default WPML language is active
187
- * fixed: JS WebP does not auto-detect WP Offload Media CNAME
188
-
189
- = 5.8.1 =
190
- * fixed: Easy IO parser has typo in $webp_quality variable
191
-
192
- = 5.8.0 =
193
- * added: SVG optimization, huge thanks to @samsk for making this happen!
194
- * added: WebP quality setting, changed default to 75
195
- * fixed: Lazy Load and other front-end parsers breaks JSON-encoded img elements
196
- * fixed: Easy IO adds excess markup for images with height and/or width set to 'auto'
197
- * fixed: memory_limit check should be case-insensitive: g vs. G
198
- * fixed: PHP error during detection of Cache Enabler's WebP option
199
- * fixed: table upgrade routine error when primary key already exists
200
- * fixed: deleting files by always using realpath, props @ocean90
201
- * fixed: Easy IO skips images in AJAX Load More requests
202
-
203
- = 5.7.1 =
204
- * added: alert on domain change for Easy IO, like if you clone from a production environment to staging
205
- * changed: Easy IO domain and plan_id refresh automatically when visiting settings page
206
- * changed: better JS WebP and WPBakery Page Builder compatibility
207
- * changed: restore savings gauge for network settings page
208
- * fixed: resize detection visible for editors, should be admin-only
209
- * fixed: (force) re-optimize not working with parallel mode
210
- * fixed: upload error when WP cannot load image editor
211
-
212
- = 5.7.0 =
213
- * added: cleanup tool if you no longer need local WebP copies of images
214
- * added: resizing results displayed in bulk & single optimization report
215
- * changed: The browser-native portion of the Lazy Load feature obeys the wp_lazy_loading_enabled filter
216
- * fixed: plugin tables do not have PRIMARY indexes
217
- * fixed: Third-party plugins sometimes set erroneous WebP quality values
218
- * fixed: Show Re-optimized Images lists images in reverse order
219
- * fixed: cannot skip to last page of re-optimized images
220
- * fixed: Scheduled Optimizer skips files that need scaling/resizing if they have already been compressed
221
- * fixed: Lazy Load placeholders not rewritten for CDN usage by Autoptimize and WP Offload Media Assets Add-on
222
 
223
  = Earlier versions =
224
  Please refer to the separate changelog.txt file.
2
  Contributors: nosilver4u
3
  Donate link: https://ewww.io/donate/
4
  Tags: optimize, image, convert, webp, resize, compress, lazy load, optimization, lossless, lossy, seo, scale
5
+ Requires at least: 5.4
6
+ Tested up to: 5.7
7
+ Requires PHP: 7.1
8
+ Stable tag: 6.1.0
9
  License: GPLv3
10
 
11
  Smaller Images, Faster Sites, Happier Visitors. Comprehensive image optimization that doesn't require a degree in rocket science.
50
 
51
  = Plugin Compatibility =
52
 
53
+ EWWW IO has been tested with hundreds (if not thousands) of [plugins and themes](https://docs.ewww.io/article/84-plugin-compatibility), here are just a few of the most common ones: BuddyPress (Activity Plus add-on too), Cloudinary, Easy Watermark, FileBird, FooGallery, GD bbPress Attachments, GRAND FlAGallery, Gmedia Photo Gallery, MediaPress, Meta Slider, Microsoft Azure Storage, MyArcadePlugin, NextGEN Gallery, Regenerate Thumbnails, WP Offload Media, [WPML](https://wpml.org/plugin/ewww-image-optimizer/), WP Retina 2x, WP RSS Aggregator, WP Symposium. [Read more...](https://docs.ewww.io/article/84-plugin-compatibility)
54
 
55
  = WebP Images =
56
 
132
  * Feature requests can be viewed and submitted on our [feedback portal](https://feedback.ewww.io)
133
  * If you would like to help translate this plugin in your language, [join the team](https://translate.wordpress.org/projects/wp-plugins/ewww-image-optimizer/)
134
 
135
+ = 6.1.0 =
136
+ * added: ability to use SVG placeholders for more efficient lazy load
137
+ * added: Easy IO and Lazy Load add missing width and height to image elements
138
+ * added: Lazy Load - right-sized placeholders can be generated for full-sized images
139
+ * added: configure Lazy Load pre-load threshold via EIO_LL_THRESHOLD constant
140
+ * changed: Lazy Load for external (non-inline) CSS images must be configured for specific elements
141
+ * changed: Easy IO's Include All Resources unlocked for all plans
142
+ * changed: native lazy loading is now disabled when using EWWW IO lazy load, override with EIO_ENABLE_NATIVE_LAZY constant
143
+ * changed: Lazy Load pre-load threshold increased from 500px to 1000px
144
+ * changed: Lazy Load picture elements use right-sized img placeholder instead of 1x1 inline GIF
145
+ * changed: system-installed binary detection improved
146
+ * fixed: native iframe lazy load disabled in WP 5.7+
147
+ * fixed: detection for Shield Security plugin lock to location
148
+ * fixed: relative path migration showing errors in site tools
149
+ * fixed: WebP rewriters not handling relative image urls
150
+ * fixed: existing <picture> elements ignored by <picture> WebP Rewriting
151
+ * fixed: <img> elements inside <picture> elements incorrectly handled by JS WebP Rewriting
152
+ * fixed: removing metadata clobbers APNG animations
153
+ * fixed: some JSON elements still being altered by Lazy Load
154
+ * fixed: Easy IO throws warnings when WP content is not in a sub-directory
155
+ * updated: jpegtran to version 9d
156
+ * updated: cwebp to version 1.2.0
157
+ * updated: pngquant to version 2.13.1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
  = Earlier versions =
160
  Please refer to the separate changelog.txt file.
tests/test-optimize.php CHANGED
@@ -183,7 +183,7 @@ class EWWWIO_Optimize_Tests extends WP_UnitTestCase {
183
  $results = $this->optimize_jpg();
184
  update_option( 'ewww_image_optimizer_webp', '' );
185
  update_site_option( 'ewww_image_optimizer_webp', '' );
186
- $this->assertEquals( 1348837, filesize( $results[0] ) );
187
  unlink( $results[0] );
188
  $this->assertEquals( 200048, filesize( $results[0] . '.webp' ) );
189
  if ( ewwwio_is_file( $results[0] . '.webp' ) ) {
@@ -205,7 +205,7 @@ class EWWWIO_Optimize_Tests extends WP_UnitTestCase {
205
  update_option( 'ewww_image_optimizer_webp', '' );
206
  update_site_option( 'ewww_image_optimizer_webp', '' );
207
  // size post opt.
208
- $this->assertEquals( 1368385, filesize( $results[0] ) );
209
  // orientation pre-rotation.
210
  $this->assertEquals( ewww_image_optimizer_get_orientation( self::$test_jpg, 'image/jpeg' ), 8 );
211
  // orientation post-rotation should always be 1, no matter the image.
@@ -235,9 +235,9 @@ class EWWWIO_Optimize_Tests extends WP_UnitTestCase {
235
  update_option( 'ewww_image_optimizer_cloud_key', '' );
236
  update_site_option( 'ewww_image_optimizer_webp', '' );
237
  update_site_option( 'ewww_image_optimizer_cloud_key', '' );
238
- $this->assertEquals( 1335586, filesize( $results[0] ) );
239
  unlink( $results[0] );
240
- $this->assertEquals( 171174, filesize( $results[0] . '.webp' ) );
241
  if ( ewwwio_is_file( $results[0] . '.webp' ) ) {
242
  unlink( $results[0] . '.webp' );
243
  }
@@ -261,12 +261,12 @@ class EWWWIO_Optimize_Tests extends WP_UnitTestCase {
261
  update_site_option( 'ewww_image_optimizer_webp', '' );
262
  update_site_option( 'ewww_image_optimizer_cloud_key', '' );
263
  // size post opt.
264
- $this->assertEquals( 1355138, filesize( $results[0] ) );
265
  // orientation pre-rotation.
266
  $this->assertEquals( ewww_image_optimizer_get_orientation( $results[0], 'image/jpeg' ), 1 );
267
  unlink( $results[0] );
268
  // size of webp with meta.
269
- $this->assertEquals( 190760, filesize( $results[0] . '.webp' ) );
270
  if ( ewwwio_is_file( $results[0] . '.webp' ) ) {
271
  unlink( $results[0] . '.webp' );
272
  }
@@ -285,7 +285,7 @@ class EWWWIO_Optimize_Tests extends WP_UnitTestCase {
285
  $results = $this->optimize_jpg();
286
  update_option( 'ewww_image_optimizer_cloud_key', '' );
287
  update_site_option( 'ewww_image_optimizer_cloud_key', '' );
288
- $this->assertEquals( 344192, filesize( $results[0] ) );
289
  unlink( $results[0] );
290
  }
291
 
@@ -302,7 +302,7 @@ class EWWWIO_Optimize_Tests extends WP_UnitTestCase {
302
  $results = $this->optimize_jpg();
303
  update_option( 'ewww_image_optimizer_cloud_key', '' );
304
  update_site_option( 'ewww_image_optimizer_cloud_key', '' );
305
- $this->assertEquals( 307434, filesize( $results[0] ) );
306
  unlink( $results[0] );
307
  }
308
 
@@ -380,7 +380,7 @@ class EWWWIO_Optimize_Tests extends WP_UnitTestCase {
380
  update_site_option( 'ewww_image_optimizer_optipng_level', 2 );
381
  update_site_option( 'ewww_image_optimizer_metadata_remove', true );
382
  $results = $this->optimize_png();
383
- $this->assertEquals( 38639, filesize( $results[0] ) );
384
  unlink( $results[0] );
385
  }
386
 
@@ -397,7 +397,7 @@ class EWWWIO_Optimize_Tests extends WP_UnitTestCase {
397
  $results = $this->optimize_png();
398
  update_option( 'ewww_image_optimizer_cloud_key', '' );
399
  update_site_option( 'ewww_image_optimizer_cloud_key', '' );
400
- $this->assertEquals( 178258, filesize( $results[0] ) );
401
  unlink( $results[0] );
402
  }
403
 
183
  $results = $this->optimize_jpg();
184
  update_option( 'ewww_image_optimizer_webp', '' );
185
  update_site_option( 'ewww_image_optimizer_webp', '' );
186
+ $this->assertEquals( 1348499, filesize( $results[0] ) );
187
  unlink( $results[0] );
188
  $this->assertEquals( 200048, filesize( $results[0] . '.webp' ) );
189
  if ( ewwwio_is_file( $results[0] . '.webp' ) ) {
205
  update_option( 'ewww_image_optimizer_webp', '' );
206
  update_site_option( 'ewww_image_optimizer_webp', '' );
207
  // size post opt.
208
+ $this->assertEquals( 1368047, filesize( $results[0] ) );
209
  // orientation pre-rotation.
210
  $this->assertEquals( ewww_image_optimizer_get_orientation( self::$test_jpg, 'image/jpeg' ), 8 );
211
  // orientation post-rotation should always be 1, no matter the image.
235
  update_option( 'ewww_image_optimizer_cloud_key', '' );
236
  update_site_option( 'ewww_image_optimizer_webp', '' );
237
  update_site_option( 'ewww_image_optimizer_cloud_key', '' );
238
+ $this->assertEquals( 1339854, filesize( $results[0] ) );
239
  unlink( $results[0] );
240
+ $this->assertEquals( 187866, filesize( $results[0] . '.webp' ) );
241
  if ( ewwwio_is_file( $results[0] . '.webp' ) ) {
242
  unlink( $results[0] . '.webp' );
243
  }
261
  update_site_option( 'ewww_image_optimizer_webp', '' );
262
  update_site_option( 'ewww_image_optimizer_cloud_key', '' );
263
  // size post opt.
264
+ $this->assertEquals( 1359406, filesize( $results[0] ) );
265
  // orientation pre-rotation.
266
  $this->assertEquals( ewww_image_optimizer_get_orientation( $results[0], 'image/jpeg' ), 1 );
267
  unlink( $results[0] );
268
  // size of webp with meta.
269
+ $this->assertEquals( 207452, filesize( $results[0] . '.webp' ) );
270
  if ( ewwwio_is_file( $results[0] . '.webp' ) ) {
271
  unlink( $results[0] . '.webp' );
272
  }
285
  $results = $this->optimize_jpg();
286
  update_option( 'ewww_image_optimizer_cloud_key', '' );
287
  update_site_option( 'ewww_image_optimizer_cloud_key', '' );
288
+ $this->assertEquals( 348295, filesize( $results[0] ) );
289
  unlink( $results[0] );
290
  }
291
 
302
  $results = $this->optimize_jpg();
303
  update_option( 'ewww_image_optimizer_cloud_key', '' );
304
  update_site_option( 'ewww_image_optimizer_cloud_key', '' );
305
+ $this->assertEquals( 310924, filesize( $results[0] ) );
306
  unlink( $results[0] );
307
  }
308
 
380
  update_site_option( 'ewww_image_optimizer_optipng_level', 2 );
381
  update_site_option( 'ewww_image_optimizer_metadata_remove', true );
382
  $results = $this->optimize_png();
383
+ $this->assertEquals( 38517, filesize( $results[0] ) );
384
  unlink( $results[0] );
385
  }
386
 
397
  $results = $this->optimize_png();
398
  update_option( 'ewww_image_optimizer_cloud_key', '' );
399
  update_site_option( 'ewww_image_optimizer_cloud_key', '' );
400
+ $this->assertEquals( 176857, filesize( $results[0] ) );
401
  unlink( $results[0] );
402
  }
403
 
unique.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Unique functions for Standard EWWW I.O. plugins.
4
  *
5
  * This file contains functions that are unique to the regular EWWW IO plugin.
6
  *
@@ -131,7 +131,9 @@ function ewww_image_optimizer_set_defaults() {
131
  add_option( 'exactdn_lossy', true );
132
  add_option( 'exactdn_exclude', '' );
133
  add_option( 'ewww_image_optimizer_lazy_load', false );
 
134
  add_option( 'ewww_image_optimizer_ll_exclude', '' );
 
135
  add_option( 'ewww_image_optimizer_disable_pngout', true );
136
  add_option( 'ewww_image_optimizer_disable_svgcleaner', true );
137
  add_option( 'ewww_image_optimizer_optipng_level', 2 );
@@ -156,6 +158,7 @@ function ewww_image_optimizer_set_defaults() {
156
  add_site_option( 'ewww_image_optimizer_pngout_level', 2 );
157
  add_site_option( 'exactdn_all_the_things', true );
158
  add_site_option( 'exactdn_lossy', true );
 
159
  }
160
 
161
  /**
@@ -250,7 +253,7 @@ function ewww_image_optimizer_install_paths() {
250
  $optipng_src = EWWW_IMAGE_OPTIMIZER_BINARY_PATH . 'optipng-mac';
251
  $jpegtran_src = EWWW_IMAGE_OPTIMIZER_BINARY_PATH . 'jpegtran-mac';
252
  $pngquant_src = EWWW_IMAGE_OPTIMIZER_BINARY_PATH . 'pngquant-mac';
253
- $webp_src = EWWW_IMAGE_OPTIMIZER_BINARY_PATH . 'cwebp-mac14';
254
  $gifsicle_dst = $tool_path . 'gifsicle';
255
  $optipng_dst = $tool_path . 'optipng';
256
  $jpegtran_dst = $tool_path . 'jpegtran';
@@ -1057,6 +1060,11 @@ function ewww_image_optimizer_md5check( $path ) {
1057
  '4d1a1c601d291f96dc03ea7e42ab9137a17f93ebc391353db65b4e32c1e9fbdb', // jpegtran-mac 9b, EWWW 2.6.0.
1058
  '7e8719703d31e1ab9bf2b2ad7ab633649012ab6aae46ea40462365b9c00876d5', // jpegtran-sol 9b, EWWW 2.6.0.
1059
  '9767f05ae1b59d4fea25a73b276dcd1245f5281b53386dc03784539265bffbea', // jpegtran.exe 9b, EWWW 2.6.0.
 
 
 
 
 
1060
  // end jpegtran.
1061
  '6deddb5562ac13ffc3e46a0af79b592e92fb4553c5df294b6e0052bc890fd0e3', // optipng-linux 0.7.4, EWWW 1.2.0.
1062
  '51df81fa8c765efbe0aa4c1cf5293e25e7e2e7f6962f5161615239c54aec4c01', // optipng-linux 0.7.4, EWWW 1.3.0.
@@ -1111,6 +1119,7 @@ function ewww_image_optimizer_md5check( $path ) {
1111
  '03602b141432af2211882fc079ba15a773a7ec782c92755cb31279eb6d8b99d4', // gifsicle-mac 1.91, EWWW 4.1.0.
1112
  '5fcdd102146984e41b01a160d072dd36852d7be14ab569a323c47e7e56916d0d', // gifsicle-sol 1.91, EWWW 4.x.
1113
  '7156bfe16dc5e33af7facdc6847d268154ffeb75c0217517e4e188b58b293c6a', // gifsicle.exe 1.91, EWWW 4.1.0.
 
1114
  // end gifsicle.
1115
  'bdea95497d6e60aae8938cae8e999ef74a255ad603531bf523dcdb531f61fc8f', // 20110722-bsd/i686/pngout.
1116
  '57c09b3ebd7d4623d16f6056efd7951e8f98e2362a27993a7d865af677875c00', // 20110722-bsd-static/i686/pngout-static.
@@ -1174,11 +1183,16 @@ function ewww_image_optimizer_md5check( $path ) {
1174
  'c924e11d9a3166afd5ed19165193c1351ff4a2cc993498f1f28c7daee829ca76', // pngquant-mac 2.11.7 EWWW 4.1.0.
1175
  '34534e69929e7fe267f77c55f487e419f76cc1d24e41fdb642f9671383012c56', // pngquant-sol 2.11.7 EWWW 4.1.0.
1176
  'af7598aa09ba519ad15305a56011949db19c5b2176187662640bc0ebc4ddd19a', // pngquant.exe 2.11.7 EWWW 4.1.0.
1177
- '6b1d4e685a4f5b3cbed9b9c7b71c7f75ae860684783e4a8274cdc66247d11fae', // pngquant.exe 2.12.5 EWWW 5.1.0.
1178
  '1ab09e21dd0c8aafe482227c2b53f13faf00fa9ba2b9046c1e9f8c4d4d851b9d', // pngquant-fbsd 2.12.5 EWWW 5.1.0.
1179
  'b580c7d68c3ec7cd7685fb388cdbb2635aae92c7d520e54e8f67c57fc6215db0', // pngquant-linux 2.12.5 EWWW 5.1.0.
1180
  'ddec62d4074d54d76dde9313302b6a95025286ad82006a0f83eb0452cc86da6c', // pngquant-mac 2.12.5 EWWW 5.1.0.
1181
  '7c10d643f936114aaa307c5fa2024c5bd5f9a25fa90a07e7f2b100c161f15898', // pngquant-sol 2.12.5 EWWW 5.1.0.
 
 
 
 
 
 
1182
  // end pngquant.
1183
  'bf0e12f996802dc114a864e5150647ce41089a5a2b5e36c3a270ac848b655c26', // cwebp-fbsd 0.4.1, EWWW 2.0.0.
1184
  '5349646072c3ef5f8b4588bbee8635e882c245439e2d86b863f04b7e27f4fafe', // cwebp-fbsd64 0.4.1, EWWW 2.0.0.
@@ -1227,6 +1241,11 @@ function ewww_image_optimizer_md5check( $path ) {
1227
  '7332ed5f0d4091e2379b1eaa32a764f8c0d51b7926996a1dc8b4ef4e3c441a12', // cwebp-mac14 1.0.3, EWWW 5.1.0.
1228
  '66568f3b31f8f22deef38aa6ba3d2be19516514e94b7d623cd2ce2a290ccdd69', // cwebp-sol 1.0.3, EWWW 5.1.0.
1229
  'e1041c5486fb4e57e31155c45d66117f8fc270e5a56a1049408a05f54bd52969', // cwebp.exe 1.0.3, EWWW 5.1.0.
 
 
 
 
 
1230
  // end cwebp.
1231
  '15d8b7d54b73059a9a63ab3d5ca8201cd30c2f6fc59fc068f7bd6c85e6a22420', // svgcleaner-linux 0.9.5.
1232
  'c88c1961374b3edc93a29376ccbd447a514c1cda335fe6a868c0dac6d77c79fa', // svgcleaner-mac 0.9.5.
@@ -1686,16 +1705,16 @@ function ewww_image_optimizer_find_nix_binary( $binary, $switch ) {
1686
  }
1687
  }
1688
  // If we still haven't found a usable binary, try a system-installed version.
1689
- if ( ewww_image_optimizer_tool_found( $binary, $switch ) ) {
1690
- return $binary;
1691
- } elseif ( ewww_image_optimizer_tool_found( '/usr/bin/' . $binary, $switch ) ) {
1692
  return '/usr/bin/' . $binary;
1693
- } elseif ( ewww_image_optimizer_tool_found( '/usr/local/bin/' . $binary, $switch ) ) {
1694
  return '/usr/local/bin/' . $binary;
1695
- } elseif ( ewww_image_optimizer_tool_found( '/usr/gnu/bin/' . $binary, $switch ) ) {
1696
  return '/usr/gnu/bin/' . $binary;
1697
- } elseif ( ewww_image_optimizer_tool_found( '/usr/syno/bin/' . $binary, $switch ) ) { // For synology diskstation OS.
1698
  return '/usr/syno/bin/' . $binary;
 
 
1699
  } else {
1700
  return '';
1701
  }
@@ -2262,6 +2281,11 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
2262
  $jpg_size = 0;
2263
  // Png2jpg conversion is turned on, and the image is in the WordPress media library.
2264
  // We check for transparency later, after optimization, because optipng might fix an empty alpha channel.
 
 
 
 
 
2265
  if (
2266
  1 === (int) $gallery_type &&
2267
  $fullsize &&
@@ -2414,10 +2438,9 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
2414
  if ( $tools['OPTIPNG'] ) {
2415
  // Retrieve the optimization level for optipng.
2416
  $optipng_level = (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_optipng_level' );
 
2417
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_metadata_remove' ) && preg_match( '/0.7/', ewww_image_optimizer_tool_found( $tools['OPTIPNG'], 'o' ) ) && ! $keep_metadata ) {
2418
  $strip = '-strip all ';
2419
- } else {
2420
- $strip = '';
2421
  }
2422
  // Run optipng on the PNG file.
2423
  exec( "$nice " . $tools['OPTIPNG'] . " -o$optipng_level -quiet $strip " . ewww_image_optimizer_escapeshellarg( $tempfile ) );
@@ -2426,8 +2449,12 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
2426
  if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_disable_pngout' ) ) {
2427
  // Retrieve the optimization level for pngout.
2428
  $pngout_level = (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_pngout_level' );
 
 
 
 
2429
  // Run pngout on the PNG file.
2430
- exec( "$nice " . $tools['PNGOUT'] . " -s$pngout_level -q " . ewww_image_optimizer_escapeshellarg( $tempfile ) );
2431
  }
2432
  // Retrieve the filesize of the temporary PNG.
2433
  $new_size = ewww_image_optimizer_filesize( $tempfile );
@@ -2943,6 +2970,9 @@ function ewww_image_optimizer_webp_create( $file, $orig_size, $type, $tool, $rec
2943
  } elseif ( ewwwio_is_file( $webpfile ) && empty( $ewww_force ) && ! $recreate ) {
2944
  ewwwio_debug_message( 'webp file exists, not forcing or recreating' );
2945
  return esc_html__( 'WebP image already exists.', 'ewww-image-optimizer' );
 
 
 
2946
  }
2947
  if ( empty( $tool ) || 'image/gif' === $type ) {
2948
  ewww_image_optimizer_cloud_optimizer( $file, $type, false, $webpfile, 'image/webp' );
1
  <?php
2
  /**
3
+ * Unique functions for Standard EWWW IO plugins.
4
  *
5
  * This file contains functions that are unique to the regular EWWW IO plugin.
6
  *
131
  add_option( 'exactdn_lossy', true );
132
  add_option( 'exactdn_exclude', '' );
133
  add_option( 'ewww_image_optimizer_lazy_load', false );
134
+ add_option( 'ewww_image_optimizer_ll_autoscale', true );
135
  add_option( 'ewww_image_optimizer_ll_exclude', '' );
136
+ add_option( 'ewww_image_optimizer_ll_all_things', '' );
137
  add_option( 'ewww_image_optimizer_disable_pngout', true );
138
  add_option( 'ewww_image_optimizer_disable_svgcleaner', true );
139
  add_option( 'ewww_image_optimizer_optipng_level', 2 );
158
  add_site_option( 'ewww_image_optimizer_pngout_level', 2 );
159
  add_site_option( 'exactdn_all_the_things', true );
160
  add_site_option( 'exactdn_lossy', true );
161
+ add_site_option( 'ewww_image_optimizer_ll_autoscale', true );
162
  }
163
 
164
  /**
253
  $optipng_src = EWWW_IMAGE_OPTIMIZER_BINARY_PATH . 'optipng-mac';
254
  $jpegtran_src = EWWW_IMAGE_OPTIMIZER_BINARY_PATH . 'jpegtran-mac';
255
  $pngquant_src = EWWW_IMAGE_OPTIMIZER_BINARY_PATH . 'pngquant-mac';
256
+ $webp_src = EWWW_IMAGE_OPTIMIZER_BINARY_PATH . 'cwebp-mac15';
257
  $gifsicle_dst = $tool_path . 'gifsicle';
258
  $optipng_dst = $tool_path . 'optipng';
259
  $jpegtran_dst = $tool_path . 'jpegtran';
1060
  '4d1a1c601d291f96dc03ea7e42ab9137a17f93ebc391353db65b4e32c1e9fbdb', // jpegtran-mac 9b, EWWW 2.6.0.
1061
  '7e8719703d31e1ab9bf2b2ad7ab633649012ab6aae46ea40462365b9c00876d5', // jpegtran-sol 9b, EWWW 2.6.0.
1062
  '9767f05ae1b59d4fea25a73b276dcd1245f5281b53386dc03784539265bffbea', // jpegtran.exe 9b, EWWW 2.6.0.
1063
+ 'd2f3f9c1fb90a56a4afad411e70f5bb596c0a373e7799104f5c3ff79bf617697', // jpegtran-fbsd 9d, EWWW 6.1.0.
1064
+ 'c0a44f6f16ddc78d8d027ffd3e09c512d637876833c5ffaaf5b1e7acd5ce3cda', // jpegtran-linux 9d, EWWW 6.1.0.
1065
+ '68bbeddef97f9aca5f76fcf71f3394dae98559c4107c3497f4f097196f09ff89', // jpegtran-mac 9d, EWWW 6.1.0.
1066
+ '9f728b5fd533a73d46138c14514ba5424ef153386d80f75669ab9b64df02aef6', // jpegtran-sol 9d, EWWW 6.1.0.
1067
+ '39096e3dd3d9c375de23e5d6ac2c4e0000c994d768d9de5c60680a1d5b99cb7b', // jpegtran.exe 9d, EWWW 6.1.0.
1068
  // end jpegtran.
1069
  '6deddb5562ac13ffc3e46a0af79b592e92fb4553c5df294b6e0052bc890fd0e3', // optipng-linux 0.7.4, EWWW 1.2.0.
1070
  '51df81fa8c765efbe0aa4c1cf5293e25e7e2e7f6962f5161615239c54aec4c01', // optipng-linux 0.7.4, EWWW 1.3.0.
1119
  '03602b141432af2211882fc079ba15a773a7ec782c92755cb31279eb6d8b99d4', // gifsicle-mac 1.91, EWWW 4.1.0.
1120
  '5fcdd102146984e41b01a160d072dd36852d7be14ab569a323c47e7e56916d0d', // gifsicle-sol 1.91, EWWW 4.x.
1121
  '7156bfe16dc5e33af7facdc6847d268154ffeb75c0217517e4e188b58b293c6a', // gifsicle.exe 1.91, EWWW 4.1.0.
1122
+ '3f59274d214a9c4f7a3bf68755ff75b6801c94f3e9e73b5a95767e2d7ec0fc42', // gifsicle.exe 1.92, EWWW 6.1.0.
1123
  // end gifsicle.
1124
  'bdea95497d6e60aae8938cae8e999ef74a255ad603531bf523dcdb531f61fc8f', // 20110722-bsd/i686/pngout.
1125
  '57c09b3ebd7d4623d16f6056efd7951e8f98e2362a27993a7d865af677875c00', // 20110722-bsd-static/i686/pngout-static.
1183
  'c924e11d9a3166afd5ed19165193c1351ff4a2cc993498f1f28c7daee829ca76', // pngquant-mac 2.11.7 EWWW 4.1.0.
1184
  '34534e69929e7fe267f77c55f487e419f76cc1d24e41fdb642f9671383012c56', // pngquant-sol 2.11.7 EWWW 4.1.0.
1185
  'af7598aa09ba519ad15305a56011949db19c5b2176187662640bc0ebc4ddd19a', // pngquant.exe 2.11.7 EWWW 4.1.0.
 
1186
  '1ab09e21dd0c8aafe482227c2b53f13faf00fa9ba2b9046c1e9f8c4d4d851b9d', // pngquant-fbsd 2.12.5 EWWW 5.1.0.
1187
  'b580c7d68c3ec7cd7685fb388cdbb2635aae92c7d520e54e8f67c57fc6215db0', // pngquant-linux 2.12.5 EWWW 5.1.0.
1188
  'ddec62d4074d54d76dde9313302b6a95025286ad82006a0f83eb0452cc86da6c', // pngquant-mac 2.12.5 EWWW 5.1.0.
1189
  '7c10d643f936114aaa307c5fa2024c5bd5f9a25fa90a07e7f2b100c161f15898', // pngquant-sol 2.12.5 EWWW 5.1.0.
1190
+ '6b1d4e685a4f5b3cbed9b9c7b71c7f75ae860684783e4a8274cdc66247d11fae', // pngquant.exe 2.12.5 EWWW 5.1.0.
1191
+ 'f5a4258d284542c44fe2847fc1a0058bb819418160069ee6010071ab1aefd7f9', // pngquant-fbsd 2.13.1 EWWW 6.1.0.
1192
+ 'b52b6b90385f1eed71d265fd181c15b515a10b64c959e974f7d6301695a689cf', // pngquant-linux 2.13.1 EWWW 6.1.0.
1193
+ 'd8f5cfeb240ade34cf2f4b06dd66d29a28b8fd38e275d4caa9278bc83a39571f', // pngquant-mac 2.13.1 EWWW 6.1.0.
1194
+ '199365d719c045a291596fc47cddc0111125cc3ff9d55235cabffdf476db4ca4', // pngquant-sol 2.13.1 EWWW 6.1.0.
1195
+ '1e93bc6991d7e77ad7a1f48560d62a1b80faa99df38ddf56030e23d48476769e', // pngquant.exe 2.13.1 EWWW 6.1.0.
1196
  // end pngquant.
1197
  'bf0e12f996802dc114a864e5150647ce41089a5a2b5e36c3a270ac848b655c26', // cwebp-fbsd 0.4.1, EWWW 2.0.0.
1198
  '5349646072c3ef5f8b4588bbee8635e882c245439e2d86b863f04b7e27f4fafe', // cwebp-fbsd64 0.4.1, EWWW 2.0.0.
1241
  '7332ed5f0d4091e2379b1eaa32a764f8c0d51b7926996a1dc8b4ef4e3c441a12', // cwebp-mac14 1.0.3, EWWW 5.1.0.
1242
  '66568f3b31f8f22deef38aa6ba3d2be19516514e94b7d623cd2ce2a290ccdd69', // cwebp-sol 1.0.3, EWWW 5.1.0.
1243
  'e1041c5486fb4e57e31155c45d66117f8fc270e5a56a1049408a05f54bd52969', // cwebp.exe 1.0.3, EWWW 5.1.0.
1244
+ '709804fe0c89ce7b3a23df11a503c663c6476cbb02f2ed0135245af9e81ac24b', // cwebp-fbsd 1.2.0, EWWW 6.1.0.
1245
+ '5fec3397c56b74b8a8ac8c9bac99dc11d40f9528a6c05e4108f1cd65d5a0a4fc', // cwebp-linux 1.2.0, EWWW 6.1.0.
1246
+ 'fc25866344efb604b3e70dc3e5519199605da13b550ccee4b7bbdcdeb0b5e6be', // cwebp-mac15 1.2.0, EWWW 6.1.0.
1247
+ '488410937dbbc4ec55fddfc0fa6835b862f7024680744a5e5ac8b88be9270fcc', // cwebp-sol 1.2.0, EWWW 6.1.0.
1248
+ '2849fd06012a9eb311b02a4f8918ae4b16775693bc21e95f4cc6a382eac299f9', // cwebp.exe 1.2.0, EWWW 6.1.0.
1249
  // end cwebp.
1250
  '15d8b7d54b73059a9a63ab3d5ca8201cd30c2f6fc59fc068f7bd6c85e6a22420', // svgcleaner-linux 0.9.5.
1251
  'c88c1961374b3edc93a29376ccbd447a514c1cda335fe6a868c0dac6d77c79fa', // svgcleaner-mac 0.9.5.
1705
  }
1706
  }
1707
  // If we still haven't found a usable binary, try a system-installed version.
1708
+ if ( is_file( '/usr/bin/' . $binary ) && ewww_image_optimizer_tool_found( '/usr/bin/' . $binary, $switch ) ) {
 
 
1709
  return '/usr/bin/' . $binary;
1710
+ } elseif ( is_file( '/usr/local/bin/' . $binary ) && ewww_image_optimizer_tool_found( '/usr/local/bin/' . $binary, $switch ) ) {
1711
  return '/usr/local/bin/' . $binary;
1712
+ } elseif ( is_file( '/usr/gnu/bin/' . $binary ) && ewww_image_optimizer_tool_found( '/usr/gnu/bin/' . $binary, $switch ) ) {
1713
  return '/usr/gnu/bin/' . $binary;
1714
+ } elseif ( is_file( '/usr/syno/bin/' . $binary ) && ewww_image_optimizer_tool_found( '/usr/syno/bin/' . $binary, $switch ) ) { // For synology diskstation OS.
1715
  return '/usr/syno/bin/' . $binary;
1716
+ } elseif ( ewww_image_optimizer_tool_found( $binary, $switch ) ) {
1717
+ return $binary;
1718
  } else {
1719
  return '';
1720
  }
2281
  $jpg_size = 0;
2282
  // Png2jpg conversion is turned on, and the image is in the WordPress media library.
2283
  // We check for transparency later, after optimization, because optipng might fix an empty alpha channel.
2284
+ $apng = ewww_image_optimizer_is_animated_png( $file );
2285
+ if ( $apng ) {
2286
+ $keep_metadata = true;
2287
+ $skip_lossy = true;
2288
+ }
2289
  if (
2290
  1 === (int) $gallery_type &&
2291
  $fullsize &&
2438
  if ( $tools['OPTIPNG'] ) {
2439
  // Retrieve the optimization level for optipng.
2440
  $optipng_level = (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_optipng_level' );
2441
+ $strip = '';
2442
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_metadata_remove' ) && preg_match( '/0.7/', ewww_image_optimizer_tool_found( $tools['OPTIPNG'], 'o' ) ) && ! $keep_metadata ) {
2443
  $strip = '-strip all ';
 
 
2444
  }
2445
  // Run optipng on the PNG file.
2446
  exec( "$nice " . $tools['OPTIPNG'] . " -o$optipng_level -quiet $strip " . ewww_image_optimizer_escapeshellarg( $tempfile ) );
2449
  if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_disable_pngout' ) ) {
2450
  // Retrieve the optimization level for pngout.
2451
  $pngout_level = (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_pngout_level' );
2452
+ $strip = '';
2453
+ if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_metadata_remove' ) || $keep_metadata ) {
2454
+ $strip = '-k1';
2455
+ }
2456
  // Run pngout on the PNG file.
2457
+ exec( "$nice " . $tools['PNGOUT'] . " -s$pngout_level -k1 -q " . ewww_image_optimizer_escapeshellarg( $tempfile ) );
2458
  }
2459
  // Retrieve the filesize of the temporary PNG.
2460
  $new_size = ewww_image_optimizer_filesize( $tempfile );
2970
  } elseif ( ewwwio_is_file( $webpfile ) && empty( $ewww_force ) && ! $recreate ) {
2971
  ewwwio_debug_message( 'webp file exists, not forcing or recreating' );
2972
  return esc_html__( 'WebP image already exists.', 'ewww-image-optimizer' );
2973
+ } elseif ( 'image/png' === $type && ewww_image_optimizer_is_animated_png( $file ) ) {
2974
+ ewwwio_debug_message( 'APNG found, WebP not possible' );
2975
+ return esc_html__( 'APNG cannot be converted to WebP.', 'ewww-image-optimizer' );
2976
  }
2977
  if ( empty( $tool ) || 'image/gif' === $type ) {
2978
  ewww_image_optimizer_cloud_optimizer( $file, $type, false, $webpfile, 'image/webp' );