EWWW Image Optimizer - Version 6.2.2

Version Description

  • added: disable Easy IO's "deep" integration with image_downsize filter via EIO_DISABLE_DEEP_INTEGRATION override
  • added: integration with JSON/AJAX respones from Spotlight Social Media Feeds plugin
  • changed: PNG placeholders are now inlined for less HTTP requests and better auto-scaling
  • changed: Bulk Optimizer processes images from oldest to newest for the Media Library
  • changed: Resize Detection uses minified JS and console logging suppressed unless using SCRIPT_DEBUG
  • fixed: Easy IO does not rewrite image (href) links if image_downsize integration has rewritten the img tag
  • fixed: Lazy Load throws error when ewww_webp_supported not defined in edge cases
  • fixed: front-end scripts loading for page builders when they shouldn't be
  • fixed: when using WP/LR Sync, EWWWIO_WPLR_AUTO does not trigger optimization for new images
  • fixed: img element search parsing JSON incorrectly
  • fixed: WebP uploads not resized to max dimensions
Download this release

Release Info

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

Code changes from version 6.2.1 to 6.2.2

aux-optimize.php CHANGED
@@ -970,7 +970,7 @@ function ewww_image_optimizer_get_all_attachments() {
970
  function ewww_image_optimizer_get_queued_attachments( $gallery, $limit = 100 ) {
971
  global $wpdb;
972
  // Retrieve the attachment IDs that were pre-loaded in the database.
973
- $selected_ids = $wpdb->get_col( $wpdb->prepare( "SELECT attachment_id FROM $wpdb->ewwwio_queue WHERE gallery = %s AND scanned = 1 LIMIT %d", $gallery, $limit ) );
974
  if ( empty( $selected_ids ) ) {
975
  ewwwio_debug_message( 'no attachments found in queue' );
976
  return array( 0 );
970
  function ewww_image_optimizer_get_queued_attachments( $gallery, $limit = 100 ) {
971
  global $wpdb;
972
  // Retrieve the attachment IDs that were pre-loaded in the database.
973
+ $selected_ids = $wpdb->get_col( $wpdb->prepare( "SELECT attachment_id FROM $wpdb->ewwwio_queue WHERE gallery = %s AND scanned = 1 LIMIT %d ORDER BY attachment_id DESC", $gallery, $limit ) );
974
  if ( empty( $selected_ids ) ) {
975
  ewwwio_debug_message( 'no attachments found in queue' );
976
  return array( 0 );
changelog.txt CHANGED
@@ -1,3 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = 6.2.1 =
2
  * fixed: Lazy Load regression prevents above-the-fold CSS background images from loading
3
  * fixed: WebP Conversion for CMYK images leaves empty color profile attached
1
+ = 6.2.2 =
2
+ * added: disable Easy IO's "deep" integration with image_downsize filter via EIO_DISABLE_DEEP_INTEGRATION override
3
+ * added: integration with JSON/AJAX respones from Spotlight Social Media Feeds plugin
4
+ * changed: PNG placeholders are now inlined for less HTTP requests and better auto-scaling
5
+ * changed: Bulk Optimizer processes images from oldest to newest for the Media Library
6
+ * changed: Resize Detection uses minified JS and console logging suppressed unless using SCRIPT_DEBUG
7
+ * fixed: Easy IO does not rewrite image (href) links if image_downsize integration has rewritten the img tag
8
+ * fixed: Lazy Load throws error when ewww_webp_supported not defined in edge cases
9
+ * fixed: front-end scripts loading for page builders when they shouldn't be
10
+ * fixed: when using WP/LR Sync, EWWWIO_WPLR_AUTO does not trigger optimization for new images
11
+ * fixed: img element search parsing JSON incorrectly
12
+ * fixed: WebP uploads not resized to max dimensions
13
+
14
  = 6.2.1 =
15
  * fixed: Lazy Load regression prevents above-the-fold CSS background images from loading
16
  * fixed: WebP Conversion for CMYK images leaves empty color profile attached
classes/class-eio-base.php CHANGED
@@ -251,13 +251,32 @@ if ( ! class_exists( 'EIO_Base' ) ) {
251
  $this->debug_message( "$supports: $supported" );
252
  }
253
  if ( ( ! empty( $gd_support['JPEG Support'] ) || ! empty( $gd_support['JPG Support'] ) ) && ! empty( $gd_support['PNG Support'] ) ) {
254
- return true;
255
  }
256
  }
257
  }
258
  return false;
259
  }
260
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  /**
262
  * Retrieve option: use 'site' setting if plugin is network activated, otherwise use 'blog' setting.
263
  *
@@ -426,6 +445,26 @@ if ( ! class_exists( 'EIO_Base' ) ) {
426
  return ! empty( $var ) && ( is_array( $var ) || $var instanceof Traversable );
427
  }
428
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
  /**
430
  * Finds the current PHP memory limit or a reasonable default.
431
  *
251
  $this->debug_message( "$supports: $supported" );
252
  }
253
  if ( ( ! empty( $gd_support['JPEG Support'] ) || ! empty( $gd_support['JPG Support'] ) ) && ! empty( $gd_support['PNG Support'] ) ) {
254
+ return ! empty( $gd_support['GD Version'] ) ? $gd_support['GD Version'] : '1';
255
  }
256
  }
257
  }
258
  return false;
259
  }
260
 
261
+ /**
262
+ * Check for IMagick support of both PNG and JPG.
263
+ *
264
+ * @return bool True if full Imagick support is detected.
265
+ */
266
+ function imagick_support() {
267
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
268
+ if ( extension_loaded( 'imagick' ) && class_exists( 'Imagick' ) ) {
269
+ $imagick = new Imagick();
270
+ $formats = $imagick->queryFormats();
271
+ $this->debug_message( implode( ',', $formats ) );
272
+ if ( in_array( 'PNG', $formats, true ) && in_array( 'JPG', $formats, true ) ) {
273
+ return true;
274
+ }
275
+ $this->debug_message( 'imagick found, but PNG or JPG not supported' );
276
+ }
277
+ return false;
278
+ }
279
+
280
  /**
281
  * Retrieve option: use 'site' setting if plugin is network activated, otherwise use 'blog' setting.
282
  *
445
  return ! empty( $var ) && ( is_array( $var ) || $var instanceof Traversable );
446
  }
447
 
448
+ /**
449
+ * Checks if there is enough memory still available.
450
+ *
451
+ * Looks to see if the current usage + padding will fit within the memory_limit defined by PHP.
452
+ *
453
+ * @param int $padding Optional. The amount of memory needed to continue. Default 1050000.
454
+ * @return True to proceed, false if there is not enough memory.
455
+ */
456
+ function check_memory_available( $padding = 1050000 ) {
457
+ $memory_limit = $this->memory_limit();
458
+
459
+ $current_memory = memory_get_usage( true ) + $padding;
460
+ if ( $current_memory >= $memory_limit ) {
461
+ $this->debug_message( "detected memory limit is not enough: $memory_limit" );
462
+ return false;
463
+ }
464
+ $this->debug_message( "detected memory limit is: $memory_limit" );
465
+ return true;
466
+ }
467
+
468
  /**
469
  * Finds the current PHP memory limit or a reasonable default.
470
  *
classes/class-eio-js-webp.php CHANGED
@@ -63,12 +63,24 @@ class EIO_JS_Webp extends EIO_Page_Parser {
63
  if ( is_object( $eio_js_webp ) ) {
64
  return 'you are doing it wrong';
65
  }
66
- if ( ewww_image_optimizer_ce_webp_enabled() ) {
67
- return false;
68
- }
69
  parent::__construct();
70
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  // Hook into the output buffer callback function.
73
  add_filter( 'ewww_image_optimizer_filter_page_output', array( $this, 'filter_page_output' ), 20 );
74
  // Filter for NextGEN image urls within JSON.
@@ -108,19 +120,106 @@ class EIO_JS_Webp extends EIO_Page_Parser {
108
  }
109
 
110
  /**
111
- * Grant read-only access to allowed WebP domains.
112
  *
113
- * @return array A list of WebP domains.
 
 
 
 
114
  */
115
- function get_webp_domains() {
116
- return $this->allowed_domains;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  }
118
 
119
  /**
120
- * Starts an output buffer and registers the callback function to do WebP replacement.
 
 
121
  */
122
- function buffer_start() {
123
- ob_start( array( $this, 'filter_page_output' ) );
124
  }
125
 
126
  /**
@@ -235,40 +334,27 @@ class EIO_JS_Webp extends EIO_Page_Parser {
235
  * @return string The altered buffer containing the full page with WebP images inserted.
236
  */
237
  function filter_page_output( $buffer ) {
238
- ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
239
- // If any of this is true, don't filter the page.
240
- $uri = add_query_arg( null, null );
241
- $this->debug_message( "request uri is $uri" );
242
  if (
243
  empty( $buffer ) ||
244
- is_admin() ||
245
- strpos( $uri, 'cornerstone=' ) !== false ||
246
- strpos( $uri, 'cornerstone-endpoint' ) !== false ||
247
- did_action( 'cornerstone_boot_app' ) || did_action( 'cs_before_preview_frame' ) ||
248
- '/print/' === substr( $uri, -7 ) ||
249
- strpos( $uri, 'elementor-preview=' ) !== false ||
250
- strpos( $uri, 'et_fb=' ) !== false ||
251
- strpos( $uri, 'tatsu=' ) !== false ||
252
- ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === sanitize_text_field( wp_unslash( $_POST['action'] ) ) ) || // phpcs:ignore WordPress.Security.NonceVerification
253
- is_embed() ||
254
- is_feed() ||
255
- is_preview() ||
256
- is_customize_preview() ||
257
- ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ||
258
  preg_match( '/^<\?xml/', $buffer ) ||
259
- strpos( $buffer, 'amp-boilerplate' ) ||
260
- $this->is_amp() ||
261
- ewww_image_optimizer_ce_webp_enabled()
262
  ) {
263
- ewwwio_debug_message( 'JS WebP disabled' );
 
 
 
 
264
  return $buffer;
265
  }
266
 
267
- $body_tags = $this->get_elements_from_html( $buffer, 'body' );
 
268
  if ( $this->is_iterable( $body_tags ) && ! empty( $body_tags[0] ) && false !== strpos( $body_tags[0], '<body' ) ) {
269
- $body_webp_script = '<script>if(ewww_webp_supported){document.body.classList.add("webp-support");}</script>';
270
  // Add the WebP script right after the opening tag.
271
  $buffer = str_replace( $body_tags[0], $body_tags[0] . "\n" . $body_webp_script, $buffer );
 
 
272
  }
273
  $images = $this->get_images_from_html( preg_replace( '/<(picture|noscript).*?\/\1>/s', '', $buffer ), false );
274
  if ( ! empty( $images[0] ) && $this->is_iterable( $images[0] ) ) {
@@ -906,10 +992,11 @@ class EIO_JS_Webp extends EIO_Page_Parser {
906
  * Load full WebP script when SCRIPT_DEBUG is enabled.
907
  */
908
  function debug_script() {
909
- if ( $this->is_amp() ) {
910
  return;
911
  }
912
  if ( ! ewww_image_optimizer_ce_webp_enabled() ) {
 
913
  wp_enqueue_script( 'ewww-webp-load-script', plugins_url( '/includes/load-webp.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION, true );
914
  }
915
  }
@@ -918,10 +1005,11 @@ class EIO_JS_Webp extends EIO_Page_Parser {
918
  * Load minified WebP script when EWWW_IMAGE_OPTIMIZER_WEBP_EXTERNAL_SCRIPT is set.
919
  */
920
  function min_external_script() {
921
- if ( $this->is_amp() ) {
922
  return;
923
  }
924
  if ( ! ewww_image_optimizer_ce_webp_enabled() ) {
 
925
  wp_enqueue_script( 'ewww-webp-load-script', plugins_url( '/includes/load-webp.min.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION, true );
926
  }
927
  }
@@ -930,10 +1018,10 @@ class EIO_JS_Webp extends EIO_Page_Parser {
930
  * Load minified inline version of check WebP script.
931
  */
932
  function inline_check_script() {
933
- if ( defined( 'EWWW_IMAGE_OPTIMIZER_NO_JS' ) && EWWW_IMAGE_OPTIMIZER_NO_JS ) {
934
  return;
935
  }
936
- if ( $this->is_amp() ) {
937
  return;
938
  }
939
  $this->debug_message( 'inlining check webp script' );
@@ -947,7 +1035,7 @@ class EIO_JS_Webp extends EIO_Page_Parser {
947
  if ( defined( 'EWWW_IMAGE_OPTIMIZER_NO_JS' ) && EWWW_IMAGE_OPTIMIZER_NO_JS ) {
948
  return;
949
  }
950
- if ( $this->is_amp() ) {
951
  return;
952
  }
953
  $this->debug_message( 'inlining load webp script' );
63
  if ( is_object( $eio_js_webp ) ) {
64
  return 'you are doing it wrong';
65
  }
 
 
 
66
  parent::__construct();
67
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
68
 
69
+ $uri = add_query_arg( null, null );
70
+ $this->debug_message( "request uri is $uri" );
71
+
72
+ add_filter( 'eio_do_js_webp', array( $this, 'should_process_page' ), 10, 2 );
73
+
74
+ /**
75
+ * Allow pre-empting JS WebP by page.
76
+ *
77
+ * @param bool Whether to parse the page for images to rewrite for WebP, default true.
78
+ * @param string $uri The URL of the page.
79
+ */
80
+ if ( ! apply_filters( 'eio_do_js_webp', true, $uri ) ) {
81
+ return;
82
+ }
83
+
84
  // Hook into the output buffer callback function.
85
  add_filter( 'ewww_image_optimizer_filter_page_output', array( $this, 'filter_page_output' ), 20 );
86
  // Filter for NextGEN image urls within JSON.
120
  }
121
 
122
  /**
123
+ * Check if pages should be processed, especially for things like page builders.
124
  *
125
+ * @since 6.2.2
126
+ *
127
+ * @param boolean $should_process Whether JS WebP should process the page.
128
+ * @param string $uri The URI of the page (no domain or scheme included).
129
+ * @return boolean True to process the page, false to skip.
130
  */
131
+ function should_process_page( $should_process = true, $uri = '' ) {
132
+ // Don't foul up the admin side of things, unless a plugin needs to.
133
+ if ( is_admin() &&
134
+ /**
135
+ * Provide plugins a way of running JS WebP for images in the WordPress Admin, usually for admin-ajax.php.
136
+ *
137
+ * @param bool false Allow JS WebP to run on the Dashboard. Defaults to false.
138
+ */
139
+ false === apply_filters( 'eio_allow_admin_js_webp', false )
140
+ ) {
141
+ $this->debug_message( 'is_admin' );
142
+ return false;
143
+ }
144
+ if ( $this->is_amp() ) {
145
+ return false;
146
+ }
147
+ if ( ewww_image_optimizer_ce_webp_enabled() ) {
148
+ return false;
149
+ }
150
+ if ( empty( $uri ) ) {
151
+ $uri = add_query_arg( null, null );
152
+ }
153
+ if ( false !== strpos( $uri, '?brizy-edit' ) ) {
154
+ return false;
155
+ }
156
+ if ( false !== strpos( $uri, 'cornerstone=' ) || false !== strpos( $uri, 'cornerstone-endpoint' ) ) {
157
+ return false;
158
+ }
159
+ if ( false !== strpos( $uri, 'ct_builder=' ) ) {
160
+ return false;
161
+ }
162
+ if ( false !== strpos( $uri, 'ct_render_shortcode=' ) || false !== strpos( $uri, 'action=oxy_render' ) ) {
163
+ return false;
164
+ }
165
+ if ( did_action( 'cornerstone_boot_app' ) || did_action( 'cs_before_preview_frame' ) ) {
166
+ return false;
167
+ }
168
+ if ( false !== strpos( $uri, 'elementor-preview=' ) ) {
169
+ return false;
170
+ }
171
+ if ( false !== strpos( $uri, 'et_fb=' ) ) {
172
+ return false;
173
+ }
174
+ if ( false !== strpos( $uri, '?fl_builder' ) ) {
175
+ return false;
176
+ }
177
+ if ( '/print/' === substr( $uri, -7 ) ) {
178
+ return false;
179
+ }
180
+ if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
181
+ return false;
182
+ }
183
+ if ( false !== strpos( $uri, 'tatsu=' ) ) {
184
+ return false;
185
+ }
186
+ if ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === sanitize_text_field( wp_unslash( $_POST['action'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
187
+ return false;
188
+ }
189
+ global $wp_query;
190
+ if ( ! isset( $wp_query ) ) {
191
+ return $should_process;
192
+ }
193
+ if ( is_embed() ) {
194
+ $this->debug_message( 'is_embed' );
195
+ return false;
196
+ }
197
+ if ( is_feed() ) {
198
+ $this->debug_message( 'is_feed' );
199
+ return false;
200
+ }
201
+ if ( is_customize_preview() ) {
202
+ $this->debug_message( 'is_customize_preview' );
203
+ return false;
204
+ }
205
+ if ( is_preview() ) {
206
+ $this->debug_message( 'is_preview' );
207
+ return false;
208
+ }
209
+ if ( wp_script_is( 'twentytwenty-twentytwenty', 'enqueued' ) ) {
210
+ $this->debug_message( 'twentytwenty enqueued' );
211
+ return false;
212
+ }
213
+ return $should_process;
214
  }
215
 
216
  /**
217
+ * Grant read-only access to allowed WebP domains.
218
+ *
219
+ * @return array A list of WebP domains.
220
  */
221
+ function get_webp_domains() {
222
+ return $this->allowed_domains;
223
  }
224
 
225
  /**
334
  * @return string The altered buffer containing the full page with WebP images inserted.
335
  */
336
  function filter_page_output( $buffer ) {
337
+ $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
 
 
 
338
  if (
339
  empty( $buffer ) ||
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  preg_match( '/^<\?xml/', $buffer ) ||
341
+ strpos( $buffer, 'amp-boilerplate' )
 
 
342
  ) {
343
+ $this->debug_message( 'JS WebP disabled' );
344
+ return $buffer;
345
+ }
346
+ if ( ! $this->should_process_page() ) {
347
+ $this->debug_message( 'JS WebP should not process page' );
348
  return $buffer;
349
  }
350
 
351
+ $body_tags = $this->get_elements_from_html( $buffer, 'body' );
352
+ $body_webp_script = '<script>if(ewww_webp_supported){document.body.classList.add("webp-support");}</script>';
353
  if ( $this->is_iterable( $body_tags ) && ! empty( $body_tags[0] ) && false !== strpos( $body_tags[0], '<body' ) ) {
 
354
  // Add the WebP script right after the opening tag.
355
  $buffer = str_replace( $body_tags[0], $body_tags[0] . "\n" . $body_webp_script, $buffer );
356
+ } else {
357
+ $buffer = str_replace( '<body>', "<body>\n$body_webp_script", $buffer );
358
  }
359
  $images = $this->get_images_from_html( preg_replace( '/<(picture|noscript).*?\/\1>/s', '', $buffer ), false );
360
  if ( ! empty( $images[0] ) && $this->is_iterable( $images[0] ) ) {
992
  * Load full WebP script when SCRIPT_DEBUG is enabled.
993
  */
994
  function debug_script() {
995
+ if ( ! $this->should_process_page() ) {
996
  return;
997
  }
998
  if ( ! ewww_image_optimizer_ce_webp_enabled() ) {
999
+ wp_enqueue_script( 'ewww-webp-check-script', plugins_url( '/includes/check-webp.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION );
1000
  wp_enqueue_script( 'ewww-webp-load-script', plugins_url( '/includes/load-webp.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION, true );
1001
  }
1002
  }
1005
  * Load minified WebP script when EWWW_IMAGE_OPTIMIZER_WEBP_EXTERNAL_SCRIPT is set.
1006
  */
1007
  function min_external_script() {
1008
+ if ( ! $this->should_process_page() ) {
1009
  return;
1010
  }
1011
  if ( ! ewww_image_optimizer_ce_webp_enabled() ) {
1012
+ wp_enqueue_script( 'ewww-webp-check-script', plugins_url( '/includes/check-webp.min.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION );
1013
  wp_enqueue_script( 'ewww-webp-load-script', plugins_url( '/includes/load-webp.min.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION, true );
1014
  }
1015
  }
1018
  * Load minified inline version of check WebP script.
1019
  */
1020
  function inline_check_script() {
1021
+ if ( ! $this->should_process_page() ) {
1022
  return;
1023
  }
1024
+ if ( defined( 'EWWW_IMAGE_OPTIMIZER_NO_JS' ) && EWWW_IMAGE_OPTIMIZER_NO_JS ) {
1025
  return;
1026
  }
1027
  $this->debug_message( 'inlining check webp script' );
1035
  if ( defined( 'EWWW_IMAGE_OPTIMIZER_NO_JS' ) && EWWW_IMAGE_OPTIMIZER_NO_JS ) {
1036
  return;
1037
  }
1038
+ if ( ! $this->should_process_page() ) {
1039
  return;
1040
  }
1041
  $this->debug_message( 'inlining load webp script' );
classes/class-eio-lazy-load.php CHANGED
@@ -82,6 +82,8 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
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
  *
@@ -151,6 +153,8 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
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
  }
@@ -160,13 +164,94 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
160
  }
161
 
162
  /**
163
- * Replaces images within a srcset attribute, just a placeholder at the moment.
164
  *
165
- * @param string $srcset A valid srcset attribute from an img element.
166
- * @return bool|string False if no changes were made, or the new srcset if any WebP images replaced the originals.
 
 
 
167
  */
168
- function srcset_replace( $srcset ) {
169
- return $srcset;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  }
171
 
172
  /**
@@ -194,104 +279,30 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
194
  */
195
  function filter_page_output( $buffer ) {
196
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
197
- // Don't foul up the admin side of things, unless a plugin needs to.
198
- if ( is_admin() &&
199
- /**
200
- * Provide plugins a way of running Lazy Load for images in the WordPress Dashboard (wp-admin).
201
- *
202
- * @param bool false Allow Lazy Load to run on the Dashboard. Default to false.
203
- */
204
- false === apply_filters( 'eio_allow_admin_lazyload', false )
205
- ) {
206
- $this->debug_message( 'is_admin' );
207
  return $buffer;
208
  }
209
- // Don't lazy load in these cases...
210
- $uri = add_query_arg( null, null );
211
- $this->debug_message( "request uri is $uri" );
212
- if (
213
- empty( $buffer ) ||
214
- strpos( $uri, 'cornerstone=' ) !== false ||
215
- strpos( $uri, 'cornerstone-endpoint' ) !== false ||
216
- strpos( $uri, 'ct_builder=' ) !== false ||
217
- did_action( 'cornerstone_boot_app' ) || did_action( 'cs_before_preview_frame' ) ||
218
- '/print/' === substr( $uri, -7 ) ||
219
- strpos( $uri, 'elementor-preview=' ) !== false ||
220
- strpos( $uri, 'et_fb=' ) !== false ||
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() ||
227
- is_customize_preview() ||
228
- ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ||
229
- wp_script_is( 'twentytwenty-twentytwenty', 'enqueued' ) ||
230
- preg_match( '/^<\?xml/', $buffer ) ||
231
- strpos( $buffer, 'amp-boilerplate' ) ||
232
- $this->is_amp()
233
- ) {
234
- if ( empty( $buffer ) ) {
235
- $this->debug_message( 'empty buffer' );
236
- }
237
- if ( strpos( $uri, 'cornerstone=' ) !== false || strpos( $uri, 'cornerstone-endpoint' ) !== false ) {
238
- $this->debug_message( 'cornerstone editor' );
239
- }
240
- if ( strpos( $uri, 'ct_builder=' ) !== false ) {
241
- $this->debug_message( 'oxygen builder' );
242
- }
243
- if ( did_action( 'cornerstone_boot_app' ) || did_action( 'cs_before_preview_frame' ) ) {
244
- $this->debug_message( 'cornerstone app/preview' );
245
- }
246
- if ( '/print/' === substr( $uri, -7 ) ) {
247
- $this->debug_message( 'print page template' );
248
- }
249
- if ( strpos( $uri, 'elementor-preview=' ) !== false ) {
250
- $this->debug_message( 'elementor preview' );
251
- }
252
- if ( strpos( $uri, 'et_fb=' ) !== false ) {
253
- $this->debug_message( 'et_fb' );
254
- }
255
- if ( strpos( $uri, '?fl_builder' ) !== false ) {
256
- $this->debug_message( 'beaver builder' );
257
- }
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
- }
264
- if ( is_feed() ) {
265
- $this->debug_message( 'is_feed' );
266
- }
267
- if ( is_preview() ) {
268
- $this->debug_message( 'is_preview' );
269
- }
270
- if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
271
- $this->debug_message( 'rest request' );
272
- }
273
- if ( wp_script_is( 'twentytwenty-twentytwenty', 'enqueued' ) ) {
274
- $this->debug_message( 'twentytwenty enqueued' );
275
- }
276
- if ( preg_match( '/^<\?xml/', $buffer ) ) {
277
- $this->debug_message( 'not html, xml tag found' );
278
- }
279
- if ( strpos( $buffer, 'amp-boilerplate' ) ) {
280
- $this->debug_message( 'AMP page processing' );
281
- }
282
- if ( $this->is_amp() ) {
283
- $this->debug_message( 'AMP page processing (is_amp)' );
284
- }
285
  return $buffer;
286
  }
287
 
288
  // If JS WebP isn't running, set ewww_webp_supported to false so we have something defined.
289
  if ( ! class_exists( 'EIO_JS_Webp' ) ) {
290
- $body_tags = $this->get_elements_from_html( $buffer, 'body' );
 
291
  if ( $this->is_iterable( $body_tags ) && ! empty( $body_tags[0] ) && false !== strpos( $body_tags[0], '<body' ) ) {
292
- $body_webp_script = '<script>var ewww_webp_supported=false;</script>';
293
  // Add the WebP script right after the opening tag.
294
  $buffer = str_replace( $body_tags[0], $body_tags[0] . "\n" . $body_webp_script, $buffer );
 
 
295
  }
296
  }
297
 
@@ -532,7 +543,8 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
532
  }
533
 
534
  if ( $filename_width && $filename_height ) {
535
- $placeholder_src = $exactdn->generate_url( $this->content_url . 'lazy/placeholder-' . $filename_width . 'x' . $filename_height . '.png' );
 
536
  $use_native_lazy = true;
537
  break 2;
538
  } else {
@@ -714,6 +726,7 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
714
  if (
715
  'a' === $exclusion ||
716
  'div' === $exclusion ||
 
717
  'img' === $exclusion ||
718
  'li' === $exclusion ||
719
  'picture' === $exclusion ||
@@ -919,19 +932,41 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
919
  }
920
 
921
  $piip_path = $this->piip_folder . 'placeholder-' . $width . 'x' . $height . '.png';
922
- if ( $this->parsing_exactdn ) {
 
923
  global $exactdn;
924
  return $exactdn->generate_url( $this->content_url . 'lazy/placeholder-' . $width . 'x' . $height . '.png' );
925
  } elseif ( ! is_file( $piip_path ) ) {
926
- if ( $this->get_option( 'ewww_image_optimizer_cloud_key' ) && ! defined( 'EWWW_IMAGE_OPTIMIZER_DISABLE_API_PIP' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
927
  $piip_location = "http://optimize.exactlywww.com/resize/lazy.php?width=$width&height=$height";
928
  $piip_response = wp_remote_get( $piip_location );
929
  if ( ! is_wp_error( $piip_response ) && is_array( $piip_response ) && ! empty( $piip_response['body'] ) ) {
 
930
  file_put_contents( $piip_path, $piip_response['body'] );
931
  clearstatcache();
932
  }
933
  }
934
- if ( ! is_file( $piip_path ) && function_exists( 'ewwwio_check_memory_available' ) && ewwwio_check_memory_available( $memory_required + 500000 ) ) {
 
 
 
 
 
935
  $img = imagecreatetruecolor( $width, $height );
936
  $color = imagecolorallocatealpha( $img, 0, 0, 0, 127 );
937
  imagefill( $img, 0, 0, $color );
@@ -946,7 +981,10 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
946
  }
947
  clearstatcache();
948
  if ( is_file( $piip_path ) ) {
949
- return $this->content_url . 'lazy/placeholder-' . $width . 'x' . $height . '.png';
 
 
 
950
  }
951
  return $this->placeholder_src;
952
  }
@@ -1009,6 +1047,9 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
1009
  * Adds a small CSS block to hide lazyload elements for no-JS browsers.
1010
  */
1011
  function no_js_css() {
 
 
 
1012
  echo '<noscript><style>.lazyload[data-src]{display:none !important;}</style></noscript>';
1013
  // And this allows us to lazy load external/internal CSS background images.
1014
  echo '<style>.lazyload{background-image:none !important;}.lazyload:before{background-image:none !important;}</style>';
@@ -1019,7 +1060,7 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
1019
  */
1020
  function debug_script() {
1021
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
1022
- if ( $this->is_amp() ) {
1023
  return;
1024
  }
1025
  if ( ! defined( 'EIO_LL_FOOTER' ) ) {
@@ -1055,7 +1096,7 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
1055
  */
1056
  function min_script() {
1057
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
1058
- if ( $this->is_amp() ) {
1059
  return;
1060
  }
1061
  if ( ! defined( 'EIO_LL_FOOTER' ) ) {
@@ -1082,5 +1123,39 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
1082
  );
1083
  return;
1084
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1085
  }
1086
  }
82
  $uri = add_query_arg( null, null );
83
  $this->debug_message( "request uri is $uri" );
84
 
85
+ add_filter( 'eio_do_lazyload', array( $this, 'should_process_page' ), 10, 2 );
86
+
87
  /**
88
  * Allow pre-empting Lazy Load by page.
89
  *
153
  // Load the non-minified and separate versions of the lazy load scripts.
154
  add_action( 'wp_enqueue_scripts', array( $this, 'debug_script' ), 1 );
155
  } else {
156
+ // Load the minified, combined version of the lazy load script.
157
+ // add_action( 'wp_head', array( $this, 'inline_script' ), 1 );
158
  // Load the minified, combined version of the lazy load script.
159
  add_action( 'wp_enqueue_scripts', array( $this, 'min_script' ), 1 );
160
  }
164
  }
165
 
166
  /**
167
+ * Check if pages should be processed, especially for things like page builders.
168
  *
169
+ * @since 6.2.2
170
+ *
171
+ * @param boolean $should_process Whether LL should process the page.
172
+ * @param string $uri The URI of the page (no domain or scheme included).
173
+ * @return boolean True to process the page, false to skip.
174
  */
175
+ function should_process_page( $should_process = true, $uri = '' ) {
176
+ // Don't foul up the admin side of things, unless a plugin needs to.
177
+ if ( is_admin() &&
178
+ /**
179
+ * Provide plugins a way of running Lazy Load for images in the WordPress Admin, usually for admin-ajax.php.
180
+ *
181
+ * @param bool false Allow Lazy Load to run on the Dashboard. Default to false.
182
+ */
183
+ false === apply_filters( 'eio_allow_admin_lazyload', false )
184
+ ) {
185
+ $this->debug_message( 'is_admin' );
186
+ return false;
187
+ }
188
+ if ( $this->is_amp() ) {
189
+ return false;
190
+ }
191
+ if ( empty( $uri ) ) {
192
+ $uri = add_query_arg( null, null );
193
+ }
194
+ if ( false !== strpos( $uri, '?brizy-edit' ) ) {
195
+ return false;
196
+ }
197
+ if ( false !== strpos( $uri, 'cornerstone=' ) || false !== strpos( $uri, 'cornerstone-endpoint' ) ) {
198
+ return false;
199
+ }
200
+ if ( false !== strpos( $uri, 'ct_builder=' ) ) {
201
+ return false;
202
+ }
203
+ if ( false !== strpos( $uri, 'ct_render_shortcode=' ) || false !== strpos( $uri, 'action=oxy_render' ) ) {
204
+ return false;
205
+ }
206
+ if ( did_action( 'cornerstone_boot_app' ) || did_action( 'cs_before_preview_frame' ) ) {
207
+ return false;
208
+ }
209
+ if ( false !== strpos( $uri, 'elementor-preview=' ) ) {
210
+ return false;
211
+ }
212
+ if ( false !== strpos( $uri, 'et_fb=' ) ) {
213
+ return false;
214
+ }
215
+ if ( false !== strpos( $uri, '?fl_builder' ) ) {
216
+ return false;
217
+ }
218
+ if ( '/print/' === substr( $uri, -7 ) ) {
219
+ return false;
220
+ }
221
+ if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
222
+ return false;
223
+ }
224
+ if ( false !== strpos( $uri, 'tatsu=' ) ) {
225
+ return false;
226
+ }
227
+ if ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === sanitize_text_field( wp_unslash( $_POST['action'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
228
+ return false;
229
+ }
230
+ global $wp_query;
231
+ if ( ! isset( $wp_query ) ) {
232
+ return $should_process;
233
+ }
234
+ if ( is_embed() ) {
235
+ $this->debug_message( 'is_embed' );
236
+ return false;
237
+ }
238
+ if ( is_feed() ) {
239
+ $this->debug_message( 'is_feed' );
240
+ return false;
241
+ }
242
+ if ( is_customize_preview() ) {
243
+ $this->debug_message( 'is_customize_preview' );
244
+ return false;
245
+ }
246
+ if ( is_preview() ) {
247
+ $this->debug_message( 'is_preview' );
248
+ return false;
249
+ }
250
+ if ( wp_script_is( 'twentytwenty-twentytwenty', 'enqueued' ) ) {
251
+ $this->debug_message( 'twentytwenty enqueued' );
252
+ return false;
253
+ }
254
+ return $should_process;
255
  }
256
 
257
  /**
279
  */
280
  function filter_page_output( $buffer ) {
281
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
282
+ if ( empty( $buffer ) ) {
 
 
 
 
 
 
 
 
 
283
  return $buffer;
284
  }
285
+ if ( preg_match( '/^<\?xml/', $buffer ) ) {
286
+ $this->debug_message( 'not html, xml tag found' );
287
+ return $buffer;
288
+ }
289
+ if ( strpos( $buffer, 'amp-boilerplate' ) ) {
290
+ $this->debug_message( 'AMP page processing' );
291
+ return $buffer;
292
+ }
293
+ if ( ! $this->should_process_page() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  return $buffer;
295
  }
296
 
297
  // If JS WebP isn't running, set ewww_webp_supported to false so we have something defined.
298
  if ( ! class_exists( 'EIO_JS_Webp' ) ) {
299
+ $body_tags = $this->get_elements_from_html( $buffer, 'body' );
300
+ $body_webp_script = '<script>var ewww_webp_supported=false;</script>';
301
  if ( $this->is_iterable( $body_tags ) && ! empty( $body_tags[0] ) && false !== strpos( $body_tags[0], '<body' ) ) {
 
302
  // Add the WebP script right after the opening tag.
303
  $buffer = str_replace( $body_tags[0], $body_tags[0] . "\n" . $body_webp_script, $buffer );
304
+ } else {
305
+ $buffer = str_replace( '<body>', "<body>\n$body_webp_script", $buffer );
306
  }
307
  }
308
 
543
  }
544
 
545
  if ( $filename_width && $filename_height ) {
546
+ $placeholder_src = $this->create_piip( $filename_width, $filename_height );
547
+ /* $placeholder_src = $exactdn->generate_url( $this->content_url . 'lazy/placeholder-' . $filename_width . 'x' . $filename_height . '.png' ); */
548
  $use_native_lazy = true;
549
  break 2;
550
  } else {
726
  if (
727
  'a' === $exclusion ||
728
  'div' === $exclusion ||
729
+ 'iframe' === $exclusion ||
730
  'img' === $exclusion ||
731
  'li' === $exclusion ||
732
  'picture' === $exclusion ||
932
  }
933
 
934
  $piip_path = $this->piip_folder . 'placeholder-' . $width . 'x' . $height . '.png';
935
+ // Keep this in case folks really want external Easy IO CDN placeholders.
936
+ if ( defined( 'EIO_USE_EXTERNAL_PLACEHOLDERS' ) && EIO_USE_EXTERNAL_PLACEHOLDERS && $this->parsing_exactdn ) {
937
  global $exactdn;
938
  return $exactdn->generate_url( $this->content_url . 'lazy/placeholder-' . $width . 'x' . $height . '.png' );
939
  } elseif ( ! is_file( $piip_path ) ) {
940
+ // First try PIP generation via Imagick, as it is pretty efficient.
941
+ if ( $this->imagick_support() ) {
942
+ $placeholder = new Imagick();
943
+ $placeholder->newimage( $width, $height, 'transparent' );
944
+ $placeholder->setimageformat( 'PNG' );
945
+ $placeholder->stripimage();
946
+ $placeholder->writeimage( $piip_path );
947
+ $placeholder->clear();
948
+ }
949
+ // If that didn't work, and we have a premium service, use the API to generate the slimmest PIP available.
950
+ /* if ( $this->get_option( 'ewww_image_optimizer_cloud_key' ) && ! defined( 'EWWW_IMAGE_OPTIMIZER_DISABLE_API_PIP' ) ) { */
951
+ if (
952
+ ! is_file( $piip_path ) &&
953
+ ( $this->parsing_exactdn || $this->get_option( 'ewww_image_optimizer_cloud_key' ) ) &&
954
+ ! defined( 'EWWW_IMAGE_OPTIMIZER_DISABLE_API_PIP' )
955
+ ) {
956
  $piip_location = "http://optimize.exactlywww.com/resize/lazy.php?width=$width&height=$height";
957
  $piip_response = wp_remote_get( $piip_location );
958
  if ( ! is_wp_error( $piip_response ) && is_array( $piip_response ) && ! empty( $piip_response['body'] ) ) {
959
+ $this->debug_message( "retrieved PIP from API, storing to $piip_path" );
960
  file_put_contents( $piip_path, $piip_response['body'] );
961
  clearstatcache();
962
  }
963
  }
964
+ // Last shot, use GD and then optimize it with optipng/pngout if available.
965
+ if (
966
+ ! is_file( $piip_path ) &&
967
+ $this->gd_support() &&
968
+ $this->check_memory_available( $width * $height * 4.8 ) // 4.8 = 24-bit or 3 bytes per pixel multiplied by a factor of 1.6 for extra wiggle room.
969
+ ) {
970
  $img = imagecreatetruecolor( $width, $height );
971
  $color = imagecolorallocatealpha( $img, 0, 0, 0, 127 );
972
  imagefill( $img, 0, 0, $color );
981
  }
982
  clearstatcache();
983
  if ( is_file( $piip_path ) ) {
984
+ if ( defined( 'EIO_USE_EXTERNAL_PLACEHOLDERS' ) && EIO_USE_EXTERNAL_PLACEHOLDERS ) {
985
+ return $this->content_url . 'lazy/placeholder-' . $width . 'x' . $height . '.png';
986
+ }
987
+ return 'data:image/png;base64,' . base64_encode( file_get_contents( $piip_path ) );
988
  }
989
  return $this->placeholder_src;
990
  }
1047
  * Adds a small CSS block to hide lazyload elements for no-JS browsers.
1048
  */
1049
  function no_js_css() {
1050
+ if ( ! $this->should_process_page() ) {
1051
+ return;
1052
+ }
1053
  echo '<noscript><style>.lazyload[data-src]{display:none !important;}</style></noscript>';
1054
  // And this allows us to lazy load external/internal CSS background images.
1055
  echo '<style>.lazyload{background-image:none !important;}.lazyload:before{background-image:none !important;}</style>';
1060
  */
1061
  function debug_script() {
1062
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
1063
+ if ( ! $this->should_process_page() ) {
1064
  return;
1065
  }
1066
  if ( ! defined( 'EIO_LL_FOOTER' ) ) {
1096
  */
1097
  function min_script() {
1098
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
1099
+ if ( ! $this->should_process_page() ) {
1100
  return;
1101
  }
1102
  if ( ! defined( 'EIO_LL_FOOTER' ) ) {
1123
  );
1124
  return;
1125
  }
1126
+ /**
1127
+ * Load minified inline version of lazysizes script.
1128
+ */
1129
+ function inline_script() {
1130
+ if ( ! $this->should_process_page() ) {
1131
+ return;
1132
+ }
1133
+ $this->debug_message( 'inlining lazysizes script' );
1134
+ // Load up the minified script.
1135
+ $lazysizes_file = constant( strtoupper( $this->prefix ) . 'PLUGIN_PATH' ) . 'includes/lazysizes.min.js';
1136
+ if ( ! $this->is_file( $lazysizes_file ) ) {
1137
+ return;
1138
+ }
1139
+ $threshold = defined( 'EIO_LL_THRESHOLD' ) && EIO_LL_THRESHOLD ? EIO_LL_THRESHOLD : 0;
1140
+ $lazysizes_script = 'var eio_lazy_vars = ' .
1141
+ wp_json_encode(
1142
+ array(
1143
+ 'exactdn_domain' => ( $this->parsing_exactdn ? $this->exactdn_domain : '' ),
1144
+ 'skip_autoscale' => ( defined( 'EIO_LL_AUTOSCALE' ) && ! EIO_LL_AUTOSCALE ? 1 : 0 ),
1145
+ 'threshold' => (int) $threshold > 50 ? (int) $threshold : 0,
1146
+ )
1147
+ )
1148
+ . ';';
1149
+
1150
+ $lazysizes_script .= file_get_contents( $lazysizes_file );
1151
+ echo '<script data-cfasync="false" type="text/javascript" id="eio-lazy-load">' . $lazysizes_script . '</script>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1152
+ if ( defined( strtoupper( $this->prefix ) . 'LAZY_PRINT' ) && constant( strtoupper( $this->prefix ) . 'LAZY_PRINT' ) ) {
1153
+ $lsprint_file = constant( strtoupper( $this->prefix ) . 'PLUGIN_PATH' ) . 'includes/ls.print.min.js';
1154
+ if ( $this->is_file( $lsprint_file ) ) {
1155
+ $lsprint_script = file_get_contents( $lsprint_file );
1156
+ echo '<script data-cfasync="false" id="eio-lazy-load-print">' . $lsprint_script . '</script>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1157
+ }
1158
+ }
1159
+ }
1160
  }
1161
  }
classes/class-eio-page-parser.php CHANGED
@@ -50,15 +50,15 @@ if ( ! class_exists( 'EIO_Page_Parser' ) ) {
50
  $unquoted_images = array();
51
 
52
  $unquoted_pattern = '';
53
- $search_pattern = '#(?P<img_tag><img\s[^>]*?>)#is';
54
  if ( $hyperlinks ) {
55
  $this->debug_message( 'using figure+hyperlink(a) patterns with src required' );
56
- $search_pattern = '#(?:<figure[^>]*?\s+?class\s*=\s*["\'](?P<figure_class>[\w\s-]+?)["\'][^>]*?>\s*)?(?:<a[^>]*?\s+?href\s*=\s*["\'](?P<link_url>[^\s]+?)["\'][^>]*?>\s*)?(?P<img_tag><img[^>]*?\s+?src\s*=\s*("|\')(?P<img_url>(?!\4).+?)\4[^>]*?>){1}(?:\s*</a>)?#is';
57
- $unquoted_pattern = '#(?:<figure[^>]*?\s+?class\s*=\s*(?P<figure_class>[\w-]+)[^>]*?>\s*)?(?:<a[^>]*?\s+?href\s*=\s*(?P<link_url>[^"\'\\\\<>][^\s<>]+)[^>]*?>\s*)?(?P<img_tag><img[^>]*?\s+?src\s*=\s*(?P<img_url>[^"\'\\\\<>][^\s<>]+)[^>]*?>){1}(?:\s*</a>)?#is';
58
  } elseif ( $src_required ) {
59
  $this->debug_message( 'using plain img pattern, src still required' );
60
- $search_pattern = '#(?P<img_tag><img[^>]*?\s+?src\s*=\s*("|\')(?P<img_url>(?!\2).+?)\2[^>]*?>)#is';
61
- $unquoted_pattern = '#(?P<img_tag><img[^>]*?\s+?src\s*=\s*(?P<img_url>[^"\'\\\\<>][^\s<>]+)[^>]*?>)#is';
62
  }
63
  if ( preg_match_all( $search_pattern, $content, $images ) ) {
64
  $this->debug_message( 'found ' . count( $images[0] ) . ' image elements with quoted pattern' );
50
  $unquoted_images = array();
51
 
52
  $unquoted_pattern = '';
53
+ $search_pattern = '#(?P<img_tag><img\s[^\\\\>]*?>)#is';
54
  if ( $hyperlinks ) {
55
  $this->debug_message( 'using figure+hyperlink(a) patterns with src required' );
56
+ $search_pattern = '#(?:<figure[^>]*?\s+?class\s*=\s*["\'](?P<figure_class>[\w\s-]+?)["\'][^>]*?>\s*)?(?:<a[^>]*?\s+?href\s*=\s*["\'](?P<link_url>[^\s]+?)["\'][^>]*?>\s*)?(?P<img_tag><img[^>]*?\s+?src\s*=\s*("|\')(?P<img_url>(?!\4)[^\\\\]+?)\4[^>]*?>){1}(?:\s*</a>)?#is';
57
+ $unquoted_pattern = '#(?:<figure[^>]*?\s+?class\s*=\s*(?P<figure_class>[\w-]+)[^>]*?>\s*)?(?:<a[^>]*?\s+?href\s*=\s*(?P<link_url>[^"\'\\\\<>][^\s<>]+)[^>]*?>\s*)?(?P<img_tag><img[^>]*?\s+?src\s*=\s*(?P<img_url>[^"\'\\\\<>][^\s\\\\<>]+)(?:\s[^>]*?)?>){1}(?:\s*</a>)?#is';
58
  } elseif ( $src_required ) {
59
  $this->debug_message( 'using plain img pattern, src still required' );
60
+ $search_pattern = '#(?P<img_tag><img[^>]*?\s+?src\s*=\s*("|\')(?P<img_url>(?!\2)[^\\\\]+?)\2[^>]*?>)#is';
61
+ $unquoted_pattern = '#(?P<img_tag><img[^>]*?\s+?src\s*=\s*(?P<img_url>[^"\'\\\\<>][^\s\\\\<>]+)(?:\s[^>]*?)?>)#is';
62
  }
63
  if ( preg_match_all( $search_pattern, $content, $images ) ) {
64
  $this->debug_message( 'found ' . count( $images[0] ) . ' image elements with quoted pattern' );
classes/class-eio-picture-webp.php CHANGED
@@ -45,6 +45,21 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
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' ) );
50
  // Hook onto the output buffer function.
@@ -68,6 +83,100 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
68
  $this->validate_user_exclusions();
69
  }
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  /**
72
  * Grant read-only access to allowed WebP domains.
73
  *
@@ -127,31 +236,16 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
127
  */
128
  function filter_page_output( $buffer ) {
129
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
130
- // If any of this is true, don't filter the page.
131
- $uri = add_query_arg( null, null );
132
- $this->debug_message( "request uri is $uri" );
133
  if (
134
  empty( $buffer ) ||
135
- is_admin() ||
136
- strpos( $uri, 'cornerstone=' ) !== false ||
137
- strpos( $uri, 'cornerstone-endpoint' ) !== false ||
138
- did_action( 'cornerstone_boot_app' ) || did_action( 'cs_before_preview_frame' ) ||
139
- '/print/' === substr( $uri, -7 ) ||
140
- strpos( $uri, 'elementor-preview=' ) !== false ||
141
- strpos( $uri, 'et_fb=' ) !== false ||
142
- strpos( $uri, 'tatsu=' ) !== false ||
143
- ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === sanitize_text_field( wp_unslash( $_POST['action'] ) ) ) || // phpcs:ignore WordPress.Security.NonceVerification
144
- is_embed() ||
145
- is_feed() ||
146
- is_preview() ||
147
- is_customize_preview() ||
148
- ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ||
149
  preg_match( '/^<\?xml/', $buffer ) ||
150
- strpos( $buffer, 'amp-boilerplate' ) ||
151
- $this->is_amp() ||
152
- ewww_image_optimizer_ce_webp_enabled()
153
  ) {
154
- ewwwio_debug_message( 'picture WebP disabled' );
 
 
 
 
155
  return $buffer;
156
  }
157
 
45
  parent::__construct();
46
  $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
47
 
48
+ $uri = add_query_arg( null, null );
49
+ $this->debug_message( "request uri is $uri" );
50
+
51
+ add_filter( 'eio_do_picture_webp', array( $this, 'should_process_page' ), 10, 2 );
52
+
53
+ /**
54
+ * Allow pre-empting <picture> WebP by page.
55
+ *
56
+ * @param bool Whether to parse the page for images to rewrite for WebP, default true.
57
+ * @param string $uri The URL of the page.
58
+ */
59
+ if ( ! apply_filters( 'eio_do_picture_webp', true, $uri ) ) {
60
+ return;
61
+ }
62
+
63
  // Make sure gallery block images crop properly.
64
  add_action( 'wp_head', array( $this, 'gallery_block_css' ) );
65
  // Hook onto the output buffer function.
83
  $this->validate_user_exclusions();
84
  }
85
 
86
+ /**
87
+ * Check if pages should be processed, especially for things like page builders.
88
+ *
89
+ * @since 6.2.2
90
+ *
91
+ * @param boolean $should_process Whether <picture> WebP should process the page.
92
+ * @param string $uri The URI of the page (no domain or scheme included).
93
+ * @return boolean True to process the page, false to skip.
94
+ */
95
+ function should_process_page( $should_process = true, $uri = '' ) {
96
+ // Don't foul up the admin side of things, unless a plugin needs to.
97
+ if ( is_admin() &&
98
+ /**
99
+ * Provide plugins a way of running <picture> WebP for images in the WordPress Admin, usually for admin-ajax.php.
100
+ *
101
+ * @param bool false Allow <picture> WebP to run on the Dashboard. Defaults to false.
102
+ */
103
+ false === apply_filters( 'eio_allow_admin_picture_webp', false )
104
+ ) {
105
+ $this->debug_message( 'is_admin' );
106
+ return false;
107
+ }
108
+ if ( $this->is_amp() ) {
109
+ return false;
110
+ }
111
+ if ( ewww_image_optimizer_ce_webp_enabled() ) {
112
+ return false;
113
+ }
114
+ if ( empty( $uri ) ) {
115
+ $uri = add_query_arg( null, null );
116
+ }
117
+ if ( false !== strpos( $uri, '?brizy-edit' ) ) {
118
+ return false;
119
+ }
120
+ if ( false !== strpos( $uri, 'cornerstone=' ) || false !== strpos( $uri, 'cornerstone-endpoint' ) ) {
121
+ return false;
122
+ }
123
+ if ( false !== strpos( $uri, 'ct_builder=' ) ) {
124
+ return false;
125
+ }
126
+ if ( false !== strpos( $uri, 'ct_render_shortcode=' ) || false !== strpos( $uri, 'action=oxy_render' ) ) {
127
+ return false;
128
+ }
129
+ if ( did_action( 'cornerstone_boot_app' ) || did_action( 'cs_before_preview_frame' ) ) {
130
+ return false;
131
+ }
132
+ if ( false !== strpos( $uri, 'elementor-preview=' ) ) {
133
+ return false;
134
+ }
135
+ if ( false !== strpos( $uri, 'et_fb=' ) ) {
136
+ return false;
137
+ }
138
+ if ( false !== strpos( $uri, '?fl_builder' ) ) {
139
+ return false;
140
+ }
141
+ if ( '/print/' === substr( $uri, -7 ) ) {
142
+ return false;
143
+ }
144
+ if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
145
+ return false;
146
+ }
147
+ if ( false !== strpos( $uri, 'tatsu=' ) ) {
148
+ return false;
149
+ }
150
+ if ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === sanitize_text_field( wp_unslash( $_POST['action'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification
151
+ return false;
152
+ }
153
+ global $wp_query;
154
+ if ( ! isset( $wp_query ) ) {
155
+ return $should_process;
156
+ }
157
+ if ( is_embed() ) {
158
+ $this->debug_message( 'is_embed' );
159
+ return false;
160
+ }
161
+ if ( is_feed() ) {
162
+ $this->debug_message( 'is_feed' );
163
+ return false;
164
+ }
165
+ if ( is_customize_preview() ) {
166
+ $this->debug_message( 'is_customize_preview' );
167
+ return false;
168
+ }
169
+ if ( is_preview() ) {
170
+ $this->debug_message( 'is_preview' );
171
+ return false;
172
+ }
173
+ if ( wp_script_is( 'twentytwenty-twentytwenty', 'enqueued' ) ) {
174
+ $this->debug_message( 'twentytwenty enqueued' );
175
+ return false;
176
+ }
177
+ return $should_process;
178
+ }
179
+
180
  /**
181
  * Grant read-only access to allowed WebP domains.
182
  *
236
  */
237
  function filter_page_output( $buffer ) {
238
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
 
 
 
239
  if (
240
  empty( $buffer ) ||
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  preg_match( '/^<\?xml/', $buffer ) ||
242
+ strpos( $buffer, 'amp-boilerplate' )
 
 
243
  ) {
244
+ $this->debug_message( 'picture WebP disabled' );
245
+ return $buffer;
246
+ }
247
+ if ( ! $this->should_process_page() ) {
248
+ $this->debug_message( 'picture WebP should not process page' );
249
  return $buffer;
250
  }
251
 
classes/class-exactdn.php CHANGED
@@ -171,7 +171,9 @@ if ( ! class_exists( 'ExactDN' ) ) {
171
  add_filter( $this->prefix . 'filter_page_output', array( $this, 'filter_page_output' ), 5 );
172
 
173
  // Core image retrieval.
174
- if ( ! function_exists( 'aq_resize' ) ) {
 
 
175
  add_filter( 'image_downsize', array( $this, 'filter_image_downsize' ), 10, 3 );
176
  } else {
177
  $this->debug_message( 'aq_resize detected, image_downsize filter disabled' );
@@ -200,14 +202,20 @@ if ( ! class_exists( 'ExactDN' ) ) {
200
 
201
  /* add_filter( 'fl_builder_render_assets_inline', '__return_true' ); */
202
 
203
- // Filter for NextGEN image URLs within JS.
204
- add_filter( 'ngg_pro_lightbox_images_queue', array( $this, 'ngg_pro_lightbox_images_queue' ) );
205
- add_filter( 'ngg_get_image_url', array( $this, 'plugin_get_image_url' ) );
206
 
207
  // Filter for Envira image URLs.
208
  add_filter( 'envira_gallery_output_item_data', array( $this, 'envira_gallery_output_item_data' ) );
209
  add_filter( 'envira_gallery_image_src', array( $this, 'plugin_get_image_url' ) );
210
 
 
 
 
 
 
 
 
211
  // Filter for legacy WooCommerce API endpoints.
212
  add_filter( 'woocommerce_api_product_response', array( $this, 'woocommerce_api_product_response' ) );
213
 
@@ -661,6 +669,7 @@ if ( ! class_exists( 'ExactDN' ) ) {
661
  $this->exactdn_domain = $domain;
662
  }
663
  }
 
664
  /**
665
  * Get the ExactDN option.
666
  *
@@ -789,9 +798,6 @@ if ( ! class_exists( 'ExactDN' ) ) {
789
  }
790
  }
791
  $this->user_exclusions[] = 'plugins/anti-captcha/';
792
- $this->user_exclusions[] = 'fusion-app';
793
- $this->user_exclusions[] = 'themes/Avada/';
794
- $this->user_exclusions[] = 'plugins/fusion-builder/';
795
  }
796
 
797
  /**
@@ -1359,7 +1365,8 @@ if ( ! class_exists( 'ExactDN' ) ) {
1359
  if ( ! empty( $exactdn_url ) ) {
1360
  $src = $exactdn_url;
1361
  }
1362
- if ( ! is_feed() && $srcset_fill && ( ! defined( 'EXACTDN_PREVENT_SRCSET_FILL' ) || ! EXACTDN_PREVENT_SRCSET_FILL ) && false !== strpos( $src, $this->exactdn_domain ) ) {
 
1363
  if ( ! $this->get_attribute( $images['img_tag'][ $index ], $this->srcset_attr ) && ! $this->get_attribute( $images['img_tag'][ $index ], 'sizes' ) ) {
1364
  $this->debug_message( "srcset filling with $src" );
1365
  $zoom = false;
@@ -1414,6 +1421,9 @@ if ( ! class_exists( 'ExactDN' ) ) {
1414
  } // End foreach().
1415
  } // End if();
1416
 
 
 
 
1417
  // Process <picture> elements in the page.
1418
  $content = $this->filter_picture_images( $content );
1419
 
@@ -1448,6 +1458,60 @@ if ( ! class_exists( 'ExactDN' ) ) {
1448
  return $content;
1449
  }
1450
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1451
  /**
1452
  * Parse page content for picture elements to rewrite.
1453
  *
@@ -2721,6 +2785,33 @@ if ( ! class_exists( 'ExactDN' ) ) {
2721
  return $image;
2722
  }
2723
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2724
  /**
2725
  * Handle direct image urls within Plugins.
2726
  *
@@ -2752,6 +2843,26 @@ if ( ! class_exists( 'ExactDN' ) ) {
2752
  return $image;
2753
  }
2754
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2755
  /**
2756
  * Handle images in legacy WooCommerce API endpoints.
2757
  *
@@ -2822,6 +2933,9 @@ if ( ! class_exists( 'ExactDN' ) ) {
2822
  * @return boolean True to skip the page, unchanged otherwise.
2823
  */
2824
  function skip_page( $skip = false, $uri = '' ) {
 
 
 
2825
  if ( false !== strpos( $uri, 'cornerstone=' ) || false !== strpos( $uri, 'cornerstone-endpoint' ) ) {
2826
  return true;
2827
  }
171
  add_filter( $this->prefix . 'filter_page_output', array( $this, 'filter_page_output' ), 5 );
172
 
173
  // Core image retrieval.
174
+ if ( defined( 'EIO_DISABLE_DEEP_INTEGRATION' ) && EIO_DISABLE_DEEP_INTEGRATION ) {
175
+ $this->debug_message( 'deep (image_downsize) integration disabled' );
176
+ } elseif ( ! function_exists( 'aq_resize' ) ) {
177
  add_filter( 'image_downsize', array( $this, 'filter_image_downsize' ), 10, 3 );
178
  } else {
179
  $this->debug_message( 'aq_resize detected, image_downsize filter disabled' );
202
 
203
  /* add_filter( 'fl_builder_render_assets_inline', '__return_true' ); */
204
 
205
+ // Filter for FacetWP JSON responses.
206
+ add_filter( 'facetwp_render_output', array( $this, 'filter_facetwp_json_output' ) );
 
207
 
208
  // Filter for Envira image URLs.
209
  add_filter( 'envira_gallery_output_item_data', array( $this, 'envira_gallery_output_item_data' ) );
210
  add_filter( 'envira_gallery_image_src', array( $this, 'plugin_get_image_url' ) );
211
 
212
+ // Filter for NextGEN image URLs within JS.
213
+ add_filter( 'ngg_pro_lightbox_images_queue', array( $this, 'ngg_pro_lightbox_images_queue' ) );
214
+ add_filter( 'ngg_get_image_url', array( $this, 'plugin_get_image_url' ) );
215
+
216
+ // Filter for Spotlight Social Media Feeds.
217
+ add_filter( 'spotlight/instagram/server/transform_item', array( $this, 'spotlight_instagram_response' ) );
218
+
219
  // Filter for legacy WooCommerce API endpoints.
220
  add_filter( 'woocommerce_api_product_response', array( $this, 'woocommerce_api_product_response' ) );
221
 
669
  $this->exactdn_domain = $domain;
670
  }
671
  }
672
+
673
  /**
674
  * Get the ExactDN option.
675
  *
798
  }
799
  }
800
  $this->user_exclusions[] = 'plugins/anti-captcha/';
 
 
 
801
  }
802
 
803
  /**
1365
  if ( ! empty( $exactdn_url ) ) {
1366
  $src = $exactdn_url;
1367
  }
1368
+ // This is just completely disabled now, no reason to do this with the lazy loader auto-scaling, and I don't know when it ever kicks in anymore...
1369
+ if ( false && ! is_feed() && $srcset_fill && ( ! defined( 'EXACTDN_PREVENT_SRCSET_FILL' ) || ! EXACTDN_PREVENT_SRCSET_FILL ) && false !== strpos( $src, $this->exactdn_domain ) ) {
1370
  if ( ! $this->get_attribute( $images['img_tag'][ $index ], $this->srcset_attr ) && ! $this->get_attribute( $images['img_tag'][ $index ], 'sizes' ) ) {
1371
  $this->debug_message( "srcset filling with $src" );
1372
  $zoom = false;
1421
  } // End foreach().
1422
  } // End if();
1423
 
1424
+ // Process <a> elements in the page for image URLs.
1425
+ $content = $this->filter_image_links( $content );
1426
+
1427
  // Process <picture> elements in the page.
1428
  $content = $this->filter_picture_images( $content );
1429
 
1458
  return $content;
1459
  }
1460
 
1461
+ /**
1462
+ * Parse the HTML for a/link elements to rewrite.
1463
+ *
1464
+ * @param string $content The HTML content to parse.
1465
+ * @return string The filtered HTML content.
1466
+ */
1467
+ function filter_image_links( $content ) {
1468
+ $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
1469
+ $elements = $this->get_elements_from_html( $content, 'a' );
1470
+ if ( $this->is_iterable( $elements ) ) {
1471
+ $args = array();
1472
+ if ( defined( 'EIO_PRESERVE_LINKED_IMAGES' ) && EIO_PRESERVE_LINKED_IMAGES ) {
1473
+ $args = array(
1474
+ 'lossy' => 0,
1475
+ 'strip' => 'none',
1476
+ );
1477
+ }
1478
+ foreach ( $elements as $index => $element ) {
1479
+ if ( false === strpos( $element, 'href' ) ) {
1480
+ continue;
1481
+ }
1482
+ $this->debug_message( 'parsing a link for hrefs' );
1483
+ $link_url = $this->get_attribute( $element, 'href' );
1484
+ if ( empty( $link_url ) ) {
1485
+ continue;
1486
+ }
1487
+ /** This filter is already documented in class-exactdn.php */
1488
+ if ( apply_filters( 'exactdn_skip_image', false, $link_url, $element ) ) {
1489
+ continue;
1490
+ }
1491
+ $full_link_url = $link_url;
1492
+ // Check for relative urls that start with a slash.
1493
+ if (
1494
+ '/' === substr( $link_url, 0, 1 ) &&
1495
+ '/' !== substr( $link_url, 1, 1 )
1496
+ ) {
1497
+ $full_link_url = '//' . $this->upload_domain . $link_url;
1498
+ }
1499
+ if ( $this->validate_image_url( $full_link_url ) ) {
1500
+ $exactdn_url = $this->generate_url( $full_link_url, $args );
1501
+ if ( $exactdn_url && $exactdn_url !== $link_url && false !== strpos( $exactdn_url, $this->exactdn_domain ) ) {
1502
+ $this->debug_message( 'updating link URL in element' );
1503
+ $element = str_replace( $link_url, $exactdn_url, $element );
1504
+ if ( $element && $element !== $elements[ $index ] ) {
1505
+ $this->debug_message( 'updating link element in content' );
1506
+ $content = str_replace( $elements[ $index ], $element, $content );
1507
+ }
1508
+ }
1509
+ }
1510
+ }
1511
+ }
1512
+ return $content;
1513
+ }
1514
+
1515
  /**
1516
  * Parse page content for picture elements to rewrite.
1517
  *
2785
  return $image;
2786
  }
2787
 
2788
+ /**
2789
+ * Parse template data from FacetWP that will be included in JSON response.
2790
+ * https://facetwp.com/documentation/developers/output/facetwp_render_output/
2791
+ *
2792
+ * @param array $output The full array of FacetWP data.
2793
+ * @return array The FacetWP data with Easy IO URLs.
2794
+ */
2795
+ function filter_facetwp_json_output( $output ) {
2796
+ $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
2797
+ if ( empty( $output['template'] ) || ! is_string( $output['template'] ) ) {
2798
+ $this->debug_message( 'no template data available' );
2799
+ if ( $this->function_exists( 'print_r' ) ) {
2800
+ $this->debug_message( print_r( $output, true ) );
2801
+ }
2802
+ return $output;
2803
+ }
2804
+ $this->filtering_the_page = true;
2805
+
2806
+ $template = $this->filter_the_content( $output['template'] );
2807
+ if ( $template ) {
2808
+ $this->debug_message( 'template data modified' );
2809
+ $output['template'] = $template;
2810
+ }
2811
+
2812
+ return $output;
2813
+ }
2814
+
2815
  /**
2816
  * Handle direct image urls within Plugins.
2817
  *
2843
  return $image;
2844
  }
2845
 
2846
+ /**
2847
+ * Handle images in Spotlight's Instagram response/endpoint.
2848
+ *
2849
+ * @param array $data The Instagram item data.
2850
+ * @return array The Instagram data with ExactDNified image urls.
2851
+ */
2852
+ function spotlight_instagram_response( $data ) {
2853
+ if ( is_array( $data ) && ! empty( $data['thumbnails']['s'] ) ) {
2854
+ if ( $this->validate_image_url( $data['thumbnails']['s'] ) ) {
2855
+ $data['thumbnails']['s'] = $this->generate_url( $data['thumbnails']['s'] );
2856
+ }
2857
+ }
2858
+ if ( is_array( $data ) && ! empty( $data['thumbnails']['m'] ) ) {
2859
+ if ( $this->validate_image_url( $data['thumbnails']['m'] ) ) {
2860
+ $data['thumbnails']['m'] = $this->generate_url( $data['thumbnails']['m'] );
2861
+ }
2862
+ }
2863
+ return $data;
2864
+ }
2865
+
2866
  /**
2867
  * Handle images in legacy WooCommerce API endpoints.
2868
  *
2933
  * @return boolean True to skip the page, unchanged otherwise.
2934
  */
2935
  function skip_page( $skip = false, $uri = '' ) {
2936
+ if ( false !== strpos( $uri, '?brizy-edit' ) ) {
2937
+ return true;
2938
+ }
2939
  if ( false !== strpos( $uri, 'cornerstone=' ) || false !== strpos( $uri, 'cornerstone-endpoint' ) ) {
2940
  return true;
2941
  }
common.php CHANGED
@@ -14,7 +14,7 @@ if ( ! defined( 'ABSPATH' ) ) {
14
  exit;
15
  }
16
 
17
- define( 'EWWW_IMAGE_OPTIMIZER_VERSION', '621' );
18
 
19
  // Initialize a couple globals.
20
  $eio_debug = '';
@@ -72,6 +72,8 @@ if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_noauto' ) ) {
72
  // Enables direct integration to the editor's save function.
73
  add_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 );
74
  }
 
 
75
  // Processes an image via the metadata after upload.
76
  add_filter( 'wp_generate_attachment_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15, 2 );
77
  // Add hook for PTE confirmation to make sure new resizes are optimized.
@@ -805,8 +807,6 @@ function ewww_image_optimizer_init() {
805
  if ( ! empty( $_GET['uncomplete_wizard'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'ewww_image_optimizer_options-options' ) ) {
806
  update_option( 'ewww_image_optimizer_wizard_complete', false, false );
807
  }
808
- // Resizes and auto-rotates images.
809
- add_filter( 'wp_handle_upload', 'ewww_image_optimizer_handle_upload' );
810
  if ( class_exists( 'S3_Uploads' ) || class_exists( 'S3_Uploads\Plugin' ) ) {
811
  ewwwio_debug_message( 's3-uploads detected, deferring resize_upload' );
812
  add_filter( 'ewww_image_optimizer_defer_resizing', '__return_true' );
@@ -1642,7 +1642,11 @@ function ewww_image_optimizer_install_table() {
1642
  }
1643
  // Make sure there are valid dates in updated column.
1644
  $wpdb->query( "UPDATE $wpdb->ewwwio_images SET updated = '1971-01-01 00:00:00' WHERE updated < '1001-01-01 00:00:01'" );
1645
- $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images ALTER updated SET DEFAULT CURRENT_TIMESTAMP" );
 
 
 
 
1646
  // Check the current collation and adjust it if necessary.
1647
  $column_collate = $wpdb->get_col_charset( $wpdb->ewwwio_images, 'path' );
1648
  if ( ! empty( $column_collate ) && ! is_wp_error( $column_collate ) && 'utf8mb4' !== $column_collate ) {
@@ -2611,7 +2615,7 @@ function ewww_image_optimizer_handle_upload( $params ) {
2611
  } else {
2612
  $mime_type = $params['type'];
2613
  }
2614
- if ( ( ! is_wp_error( $params ) ) && ewwwio_is_file( $file_path ) && in_array( $mime_type, array( 'image/png', 'image/gif', 'image/jpeg' ), true ) ) {
2615
  ewww_image_optimizer_resize_upload( $file_path );
2616
  }
2617
  }
@@ -8293,6 +8297,12 @@ function ewww_image_optimizer_lr_sync_update( $id ) {
8293
 
8294
  list( $file_path, $upload_path ) = ewww_image_optimizer_attachment_path( $meta, $id );
8295
  if ( ewww_image_optimizer_stream_wrapped( $file_path ) || ! ewwwio_is_file( $file_path ) ) {
 
 
 
 
 
 
8296
  return;
8297
  }
8298
  ewwwio_debug_message( "retrieved file path for lr sync image: $file_path" );
@@ -8312,34 +8322,35 @@ function ewww_image_optimizer_lr_sync_update( $id ) {
8312
  // Get a list of all the image files optimized for this attachment.
8313
  global $wpdb;
8314
  $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT id,path,image_size FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
8315
- if ( ! ewww_image_optimizer_iterable( $optimized_images ) ) {
8316
- return;
8317
- }
8318
- foreach ( $optimized_images as $optimized_image ) {
8319
- $image_path = ewww_image_optimizer_absolutize_path( $optimized_image['path'] );
8320
- $file_size = ewww_image_optimizer_filesize( $image_path );
8321
- if ( $file_size === (int) $optimized_image['image_size'] ) {
8322
- ewwwio_debug_message( "not resetting $image_path for lr sync" );
8323
- continue;
8324
- }
8325
- if ( ewwwio_is_file( $image_path . '.webp' ) ) {
8326
- ewwwio_debug_message( "removing WebP version of $image_path for lr sync" );
8327
- ewwwio_delete_file( $image_path . '.webp' );
 
 
 
 
 
 
 
 
8328
  }
8329
- $wpdb->update(
8330
- $wpdb->ewwwio_images,
8331
- array(
8332
- 'image_size' => 0,
8333
- ),
8334
- array(
8335
- 'id' => $optimized_image['id'],
8336
- )
8337
- );
8338
  }
8339
  if ( defined( 'EWWWIO_WPLR_AUTO' ) && EWWWIO_WPLR_AUTO ) {
 
8340
  $meta = ewww_image_optimizer_resize_from_meta_data( $meta, $id );
8341
  return;
8342
  }
 
8343
  update_option( 'ewww_image_optimizer_lr_sync', true, false );
8344
  }
8345
 
@@ -10437,11 +10448,12 @@ function ewww_image_optimizer_webp_unwrite() {
10437
  */
10438
  function ewww_image_optimizer_webp_rewrite_verify() {
10439
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
10440
- if ( ewww_image_optimizer_easy_active() ) {
10441
  if ( ewwwio_extract_from_markers( ewww_image_optimizer_htaccess_path(), 'EWWWIO' ) ) {
10442
- ewwwio_debug_message( 'removing htaccess webp to prevent ExactDN problems' );
10443
  insert_with_markers( ewww_image_optimizer_htaccess_path(), 'EWWWIO', '' );
10444
  }
 
10445
  }
10446
  if ( ewww_image_optimizer_wpfc_webp_enabled() ) {
10447
  return;
@@ -10620,7 +10632,7 @@ function ewwwio_ip_in_range( $ip, $range ) {
10620
  }
10621
 
10622
  /**
10623
- * Test if the site is hosted by Cloudflare.
10624
  *
10625
  * @return bool True if it is, false if it ain't.
10626
  */
@@ -10637,10 +10649,10 @@ function ewwwio_is_cf_host() {
10637
  '197.234.240.0/22',
10638
  '198.41.128.0/17',
10639
  '162.158.0.0/15',
10640
- '172.64.0.0/13',
10641
- '131.0.72.0/22',
10642
  '104.16.0.0/13',
10643
  '104.24.0.0/14',
 
 
10644
  );
10645
  if ( ! empty( $_SERVER['HTTP_CF_IPCOUNTRY'] ) ) {
10646
  ewwwio_debug_message( 'found Cloudflare host via HTTP_CF_IPCOUNTRY' );
@@ -11990,9 +12002,14 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
11990
  ),
11991
  'ewww_image_optimizer_options-options'
11992
  );
 
 
 
 
 
11993
  // Make sure .htaccess rules are terminated when ExactDN is enabled or if Cloudflare is detected.
11994
  $cf_host = ewwwio_is_cf_host();
11995
- if ( ewww_image_optimizer_easy_active() || $cf_host ) {
11996
  ewww_image_optimizer_webp_rewrite_verify();
11997
  }
11998
  $webp_available = ewww_image_optimizer_webp_available();
@@ -12088,7 +12105,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
12088
  </div><!-- end container general settings -->
12089
  <p class='submit'><input type='submit' class='button-primary' value='<?php esc_attr_e( 'Save Changes', 'ewww-image-optimizer' ); ?>' /></p>
12090
  </form>
12091
- </div><!-- end container wrap -->
12092
  <?php
12093
  return;
12094
  endif;
@@ -12514,7 +12531,8 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
12514
  <?php esc_html_e( 'WebP Delivery Method', 'ewww-image-optimizer' ); ?>
12515
  </th>
12516
  <td>
12517
- <?php if ( ! $cf_host && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) ) : ?>
 
12518
  <?php
12519
  printf(
12520
  /* translators: %s: documentation */
@@ -12527,36 +12545,41 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
12527
  <?php
12528
  if (
12529
  ! $cf_host &&
12530
- ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) &&
12531
  ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) &&
12532
  ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_picture_webp' )
12533
  ) :
12534
- if ( defined( 'PHP_SAPI' ) && false === strpos( PHP_SAPI, 'apache' ) && false === strpos( PHP_SAPI, 'litespeed' ) ) {
12535
- $false_positive_headers = esc_html( 'This may be a false positive. If so, the warning should go away once you implement the rewrite rules.' );
12536
- }
12537
- $header_error = '';
12538
- if ( ! apache_mod_loaded( 'mod_rewrite' ) ) {
12539
- /* translators: %s: mod_rewrite or mod_headers */
12540
- $header_error = '<p><strong>' . sprintf( esc_html__( 'Your site appears to be missing %s, please contact your webhost or system administrator to enable this Apache module.', 'ewww-image-optimizer' ), 'mod_rewrite' ) . "</strong><br>$false_positive_headers</p>\n";
12541
- }
12542
- if ( ! apache_mod_loaded( 'mod_headers' ) ) {
12543
- /* translators: %s: mod_rewrite or mod_headers */
12544
- $header_error = '<p><strong>' . sprintf( esc_html__( 'Your site appears to be missing %s, please contact your webhost or system administrator to enable this Apache module.', 'ewww-image-optimizer' ), 'mod_headers' ) . "</strong><br>$false_positive_headers</p>\n";
12545
- }
 
 
 
 
12546
 
12547
- $webp_mime_error = ewww_image_optimizer_test_webp_mime_error();
12548
- if ( $webp_mime_error ) {
12549
- echo wp_kses_post( $header_error );
12550
- }
12551
 
12552
- $webp_rewrite_verify = ! (bool) ewww_image_optimizer_webp_rewrite_verify();
 
12553
  if ( $webp_mime_error && $webp_rewrite_verify ) :
12554
  printf(
12555
  /* translators: %s: an error message from the WebP self-test */
12556
- '<p>' . esc_html__( 'WebP rules verified, but self-test failed: %s', 'ewww-image-optimizer' ) . '</p>',
12557
  esc_html( $webp_mime_error )
12558
  );
12559
- elseif ( ! $webp_mime_error || $webp_rewrite_verify ) :
12560
  ?>
12561
  <div id='ewww-webp-rewrite'>
12562
  <img id='ewww-webp-image' src='<?php echo esc_url( $test_png_image . '?m=' . time() ); ?>'>
@@ -12571,7 +12594,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
12571
  <?php endif; ?>
12572
  </div>
12573
  <?php else : ?>
12574
- <p>
12575
  <?php
12576
  printf(
12577
  /* translators: %s: documentation */
@@ -12587,7 +12610,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
12587
  RewriteCond %{REQUEST_FILENAME} (.*)\.(jpe?g|png|gif)$
12588
  RewriteCond %{REQUEST_FILENAME}\.webp -f
12589
  RewriteCond %{QUERY_STRING} !type=original
12590
- RewriteRule (.+)\.(jpe?g|png|gif)$ %{REQUEST_FILENAME}.webp [T=image/webp,L]
12591
  &lt;/IfModule&gt;
12592
  &lt;IfModule mod_headers.c&gt;
12593
  &lt;FilesMatch "\.(jpe?g|png|gif)$"&gt;
@@ -12604,7 +12627,9 @@ AddType image/webp .webp</pre>
12604
  </div>
12605
  <?php endif; ?>
12606
  <?php elseif ( $cf_host && ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) ) : ?>
12607
- <p><?php esc_html_e( 'Your site is using Cloudflare, please use JS WebP or <picture> WebP rewriting.', 'ewww-image-optimizer' ); ?></p>
 
 
12608
  <?php endif; ?>
12609
  </td>
12610
  </tr>
@@ -13128,7 +13153,7 @@ AddType image/webp .webp</pre>
13128
  <?php if ( 'network-singlesite' === $network ) : ?>
13129
  <p class='submit'><input type='submit' class='button-primary' value='<?php esc_attr_e( 'Save Changes', 'ewww-image-optimizer' ); ?>' /></p>
13130
  </form>
13131
- </div><!-- end container wrap -->
13132
  <?php
13133
  return;
13134
  endif;
@@ -13324,38 +13349,7 @@ AddType image/webp .webp</pre>
13324
  </div>
13325
  <p class='submit'><input type='submit' class='button-primary' value='<?php esc_attr_e( 'Save Changes', 'ewww-image-optimizer' ); ?>' /></p>
13326
  </form>
13327
-
13328
- <?php if ( ! ewww_image_optimizer_easy_active() && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) ) : ?>
13329
- <hr style='clear:both;'>
13330
- <h2><?php esc_html_e( "Shane's Recommendations", 'ewww-image-optimizer' ); ?></h2>
13331
- <p><?php esc_html_e( 'These are products I have personally used. An * indicates an affiliate link so you can support future development of EWWW IO.', 'ewww-image-optimizer' ); ?></p>
13332
- <h3><?php esc_html_e( 'Hosting', 'ewww-image-optimizer' ); ?></h3>
13333
- <p>
13334
- <a href='http://shareasale.com/r.cfm?b=917225&amp;u=1481701&amp;m=41388&amp;urllink=&amp;afftrack='>WP Engine</a>* -
13335
- <?php esc_html_e( 'ewww.io is powered by WP Engine, and their performance is worth every penny. This is "managed WordPress hosting" at it\'s finest. 20% discount off your first payment with our link.', 'ewww-image-optimizer' ); ?>
13336
- <br>
13337
- <a href="https://www.cloudways.com/en/?id=48939">Cloudways</a>* -
13338
- <?php esc_html_e( 'Simple, yet powerful, managed VPS hosting. I use their hosting for a few client sites and performance is crazy fast. Support has been great any time I\'ve needed their assistance.', 'ewww-image-optimizer' ); ?>
13339
- </p>
13340
- <h3><?php esc_html_e( 'Plugins and Services', 'ewww-image-optimizer' ); ?></h3>
13341
- <p>
13342
- <a href="https://easydigitaldownloads.com/?ref=4735">Easy Digital Downloads</a>* -
13343
- <?php esc_html_e( 'Sell digital products with a huge number of extensions for amazing flexibility. Naturally, this is how we sell our services and plugins.', 'ewww-image-optimizer' ); ?>
13344
- <br>
13345
- <a href="https://www.helpscout.net/referral/?code=SVhaTmZDSSt2WG4xYS9FRmZrNllUa3RSR25VTStXcGhmaStQQ21QQjBDVmdZdz09OnoyVTFIUzBnbldtM21VMEM.">Helpscout</a>* -
13346
- <?php esc_html_e( 'Treat your customers like people, not numbers, and keep them satisfied. Personal favorite feature is Traffic Cop that keeps you from sending a message if you receive another message from the customer while you are typing.', 'ewww-image-optimizer' ); ?>
13347
- <br>
13348
- <a href="http://eepurl.com/cLPIeD">MailChimp</a>* -
13349
- <?php esc_html_e( 'Mailing lists that just work plus automation features that work even when you\'re not.', 'ewww-image-optimizer' ); ?>
13350
- <br>
13351
- <a href="https://malcare.com?src=C600E7">MalCare</a>* -
13352
- <?php esc_html_e( 'Secure your site with a firewall, advanced heuristic scanning, and brute force login protection. Securing your site is not an option, it\'s a necessity.', 'ewww-image-optimizer' ); ?>
13353
- <br>
13354
- <a href="https://nodeping.com?rid=201407082225W862K">NodePing</a>* -
13355
- <?php esc_html_e( 'Monitor all the things, and make sure they stay online. They have a fantastic array of monitors and notifications that you can setup, they are cheap, simple, and have great support.', 'ewww-image-optimizer' ); ?>
13356
- </p>
13357
- <?php endif; ?>
13358
- </div><!-- end container wrap -->
13359
  <?php
13360
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help' ) ) {
13361
  $current_user = wp_get_current_user();
@@ -13526,7 +13520,11 @@ function ewww_image_optimizer_resize_detection_script() {
13526
  return;
13527
  }
13528
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_detection' ) ) {
13529
- $resize_detection_script = file_get_contents( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'includes/resize_detection.js' );
 
 
 
 
13530
  echo "<style>\n" .
13531
  "img.scaled-image {\n" .
13532
  "\tborder: 3px #3eadc9 dotted;\n" .
14
  exit;
15
  }
16
 
17
+ define( 'EWWW_IMAGE_OPTIMIZER_VERSION', '622' );
18
 
19
  // Initialize a couple globals.
20
  $eio_debug = '';
72
  // Enables direct integration to the editor's save function.
73
  add_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 );
74
  }
75
+ // Resizes and auto-rotates images.
76
+ add_filter( 'wp_handle_upload', 'ewww_image_optimizer_handle_upload' );
77
  // Processes an image via the metadata after upload.
78
  add_filter( 'wp_generate_attachment_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15, 2 );
79
  // Add hook for PTE confirmation to make sure new resizes are optimized.
807
  if ( ! empty( $_GET['uncomplete_wizard'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'ewww_image_optimizer_options-options' ) ) {
808
  update_option( 'ewww_image_optimizer_wizard_complete', false, false );
809
  }
 
 
810
  if ( class_exists( 'S3_Uploads' ) || class_exists( 'S3_Uploads\Plugin' ) ) {
811
  ewwwio_debug_message( 's3-uploads detected, deferring resize_upload' );
812
  add_filter( 'ewww_image_optimizer_defer_resizing', '__return_true' );
1642
  }
1643
  // Make sure there are valid dates in updated column.
1644
  $wpdb->query( "UPDATE $wpdb->ewwwio_images SET updated = '1971-01-01 00:00:00' WHERE updated < '1001-01-01 00:00:01'" );
1645
+ if ( get_option( 'ewww_image_optimizer_version' ) < 620 && false !== strpos( $mysql_version, '5.7' ) ) {
1646
+ $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images MODIFY updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" );
1647
+ } else {
1648
+ $wpdb->query( "ALTER TABLE $wpdb->ewwwio_images ALTER updated SET DEFAULT CURRENT_TIMESTAMP" );
1649
+ }
1650
  // Check the current collation and adjust it if necessary.
1651
  $column_collate = $wpdb->get_col_charset( $wpdb->ewwwio_images, 'path' );
1652
  if ( ! empty( $column_collate ) && ! is_wp_error( $column_collate ) && 'utf8mb4' !== $column_collate ) {
2615
  } else {
2616
  $mime_type = $params['type'];
2617
  }
2618
+ if ( ( ! is_wp_error( $params ) ) && ewwwio_is_file( $file_path ) && in_array( $mime_type, array( 'image/png', 'image/gif', 'image/jpeg', 'image/webp' ), true ) ) {
2619
  ewww_image_optimizer_resize_upload( $file_path );
2620
  }
2621
  }
8297
 
8298
  list( $file_path, $upload_path ) = ewww_image_optimizer_attachment_path( $meta, $id );
8299
  if ( ewww_image_optimizer_stream_wrapped( $file_path ) || ! ewwwio_is_file( $file_path ) ) {
8300
+ ewwwio_debug_message( "bailing early since no local file or stream wrapped $file_path" );
8301
+ // Still want to fire off the optimization.
8302
+ if ( defined( 'EWWWIO_WPLR_AUTO' ) && EWWWIO_WPLR_AUTO ) {
8303
+ ewwwio_debug_message( "auto optimizing $file_path" );
8304
+ $meta = ewww_image_optimizer_resize_from_meta_data( $meta, $id );
8305
+ }
8306
  return;
8307
  }
8308
  ewwwio_debug_message( "retrieved file path for lr sync image: $file_path" );
8322
  // Get a list of all the image files optimized for this attachment.
8323
  global $wpdb;
8324
  $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT id,path,image_size FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
8325
+ if ( ewww_image_optimizer_iterable( $optimized_images ) ) {
8326
+ foreach ( $optimized_images as $optimized_image ) {
8327
+ $image_path = ewww_image_optimizer_absolutize_path( $optimized_image['path'] );
8328
+ $file_size = ewww_image_optimizer_filesize( $image_path );
8329
+ if ( $file_size === (int) $optimized_image['image_size'] ) {
8330
+ ewwwio_debug_message( "not resetting $image_path for lr sync" );
8331
+ continue;
8332
+ }
8333
+ if ( ewwwio_is_file( $image_path . '.webp' ) ) {
8334
+ ewwwio_debug_message( "removing WebP version of $image_path for lr sync" );
8335
+ ewwwio_delete_file( $image_path . '.webp' );
8336
+ }
8337
+ $wpdb->update(
8338
+ $wpdb->ewwwio_images,
8339
+ array(
8340
+ 'image_size' => 0,
8341
+ ),
8342
+ array(
8343
+ 'id' => $optimized_image['id'],
8344
+ )
8345
+ );
8346
  }
 
 
 
 
 
 
 
 
 
8347
  }
8348
  if ( defined( 'EWWWIO_WPLR_AUTO' ) && EWWWIO_WPLR_AUTO ) {
8349
+ ewwwio_debug_message( "auto optimizing $file_path" );
8350
  $meta = ewww_image_optimizer_resize_from_meta_data( $meta, $id );
8351
  return;
8352
  }
8353
+ ewwwio_debug_message( 'no auto-opt, will show notice' );
8354
  update_option( 'ewww_image_optimizer_lr_sync', true, false );
8355
  }
8356
 
10448
  */
10449
  function ewww_image_optimizer_webp_rewrite_verify() {
10450
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
10451
+ if ( ewww_image_optimizer_easy_active() || ewwwio_is_cf_host() || isset( $_SERVER['cw_allowed_ip'] ) ) {
10452
  if ( ewwwio_extract_from_markers( ewww_image_optimizer_htaccess_path(), 'EWWWIO' ) ) {
10453
+ ewwwio_debug_message( 'removing htaccess webp to prevent EasyIO/Cloudflare/Clouways problems' );
10454
  insert_with_markers( ewww_image_optimizer_htaccess_path(), 'EWWWIO', '' );
10455
  }
10456
+ return;
10457
  }
10458
  if ( ewww_image_optimizer_wpfc_webp_enabled() ) {
10459
  return;
10632
  }
10633
 
10634
  /**
10635
+ * Test if the site is protected by Cloudflare.
10636
  *
10637
  * @return bool True if it is, false if it ain't.
10638
  */
10649
  '197.234.240.0/22',
10650
  '198.41.128.0/17',
10651
  '162.158.0.0/15',
 
 
10652
  '104.16.0.0/13',
10653
  '104.24.0.0/14',
10654
+ '172.64.0.0/13',
10655
+ '131.0.72.0/22',
10656
  );
10657
  if ( ! empty( $_SERVER['HTTP_CF_IPCOUNTRY'] ) ) {
10658
  ewwwio_debug_message( 'found Cloudflare host via HTTP_CF_IPCOUNTRY' );
12002
  ),
12003
  'ewww_image_optimizer_options-options'
12004
  );
12005
+
12006
+ $cloudways_host = false;
12007
+ if ( isset( $_SERVER['cw_allowed_ip'] ) ) {
12008
+ $cloudways_host = true;
12009
+ }
12010
  // Make sure .htaccess rules are terminated when ExactDN is enabled or if Cloudflare is detected.
12011
  $cf_host = ewwwio_is_cf_host();
12012
+ if ( ewww_image_optimizer_easy_active() || $cf_host || $cloudways_host ) {
12013
  ewww_image_optimizer_webp_rewrite_verify();
12014
  }
12015
  $webp_available = ewww_image_optimizer_webp_available();
12105
  </div><!-- end container general settings -->
12106
  <p class='submit'><input type='submit' class='button-primary' value='<?php esc_attr_e( 'Save Changes', 'ewww-image-optimizer' ); ?>' /></p>
12107
  </form>
12108
+ </div><!-- end container .wrap -->
12109
  <?php
12110
  return;
12111
  endif;
12531
  <?php esc_html_e( 'WebP Delivery Method', 'ewww-image-optimizer' ); ?>
12532
  </th>
12533
  <td>
12534
+ <!-- This will be handled further down now, with fully-functional rule inserter. -->
12535
+ <?php if ( false && ! $cf_host && ! $cloudways_host && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) ) : ?>
12536
  <?php
12537
  printf(
12538
  /* translators: %s: documentation */
12545
  <?php
12546
  if (
12547
  ! $cf_host &&
12548
+ ! $cloudways_host &&
12549
  ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) &&
12550
  ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_picture_webp' )
12551
  ) :
12552
+ $webp_mime_error = false;
12553
+ $webp_rewrite_verify = false;
12554
+ // Only check the rules for problems if WebP is enabled, otherwise this is a blank slate.
12555
+ if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) ) :
12556
+ if ( defined( 'PHP_SAPI' ) && false === strpos( PHP_SAPI, 'apache' ) && false === strpos( PHP_SAPI, 'litespeed' ) ) {
12557
+ $false_positive_headers = esc_html( 'This may be a false positive. If so, the warning should go away once you implement the rewrite rules.' );
12558
+ }
12559
+ $header_error = '';
12560
+ if ( ! apache_mod_loaded( 'mod_rewrite' ) ) {
12561
+ /* translators: %s: mod_rewrite or mod_headers */
12562
+ $header_error = '<p class="ewww-webp-rewrite-info"><strong>' . sprintf( esc_html__( 'Your site appears to be missing %s, please contact your webhost or system administrator to enable this Apache module.', 'ewww-image-optimizer' ), 'mod_rewrite' ) . "</strong><br>$false_positive_headers</p>\n";
12563
+ }
12564
+ if ( ! apache_mod_loaded( 'mod_headers' ) ) {
12565
+ /* translators: %s: mod_rewrite or mod_headers */
12566
+ $header_error = '<p class="ewww-webp-rewrite-info"><strong>' . sprintf( esc_html__( 'Your site appears to be missing %s, please contact your webhost or system administrator to enable this Apache module.', 'ewww-image-optimizer' ), 'mod_headers' ) . "</strong><br>$false_positive_headers</p>\n";
12567
+ }
12568
 
12569
+ $webp_mime_error = ewww_image_optimizer_test_webp_mime_error();
12570
+ if ( $webp_mime_error ) {
12571
+ echo wp_kses_post( $header_error );
12572
+ }
12573
 
12574
+ $webp_rewrite_verify = ! (bool) ewww_image_optimizer_webp_rewrite_verify();
12575
+ endif;
12576
  if ( $webp_mime_error && $webp_rewrite_verify ) :
12577
  printf(
12578
  /* translators: %s: an error message from the WebP self-test */
12579
+ '<p class="ewww-webp-rewrite-info">' . esc_html__( 'WebP rules verified, but self-test failed: %s', 'ewww-image-optimizer' ) . '</p>',
12580
  esc_html( $webp_mime_error )
12581
  );
12582
+ elseif ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) && ( ! $webp_mime_error || $webp_rewrite_verify ) ) :
12583
  ?>
12584
  <div id='ewww-webp-rewrite'>
12585
  <img id='ewww-webp-image' src='<?php echo esc_url( $test_png_image . '?m=' . time() ); ?>'>
12594
  <?php endif; ?>
12595
  </div>
12596
  <?php else : ?>
12597
+ <p class='ewww-webp-rewrite-info'>
12598
  <?php
12599
  printf(
12600
  /* translators: %s: documentation */
12610
  RewriteCond %{REQUEST_FILENAME} (.*)\.(jpe?g|png|gif)$
12611
  RewriteCond %{REQUEST_FILENAME}\.webp -f
12612
  RewriteCond %{QUERY_STRING} !type=original
12613
+ RewriteRule (.+)\.(jpe?g|png|gif)$ %{REQUEST_URI}.webp [T=image/webp,L]
12614
  &lt;/IfModule&gt;
12615
  &lt;IfModule mod_headers.c&gt;
12616
  &lt;FilesMatch "\.(jpe?g|png|gif)$"&gt;
12627
  </div>
12628
  <?php endif; ?>
12629
  <?php elseif ( $cf_host && ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) ) : ?>
12630
+ <p><?php esc_html_e( 'Your site is using Cloudflare, please use JS WebP or <picture> WebP rewriting to prevent broken images on older browsers.', 'ewww-image-optimizer' ); ?></p>
12631
+ <?php elseif ( $cloudways_host && ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) ) : ?>
12632
+ <p><?php esc_html_e( 'Cloudways sites should use JS WebP or <picture> WebP rewriting to prevent broken images on older browsers.', 'ewww-image-optimizer' ); ?></p>
12633
  <?php endif; ?>
12634
  </td>
12635
  </tr>
13153
  <?php if ( 'network-singlesite' === $network ) : ?>
13154
  <p class='submit'><input type='submit' class='button-primary' value='<?php esc_attr_e( 'Save Changes', 'ewww-image-optimizer' ); ?>' /></p>
13155
  </form>
13156
+ </div><!-- end container .wrap -->
13157
  <?php
13158
  return;
13159
  endif;
13349
  </div>
13350
  <p class='submit'><input type='submit' class='button-primary' value='<?php esc_attr_e( 'Save Changes', 'ewww-image-optimizer' ); ?>' /></p>
13351
  </form>
13352
+ </div><!-- end container .wrap -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13353
  <?php
13354
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help' ) ) {
13355
  $current_user = wp_get_current_user();
13520
  return;
13521
  }
13522
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_detection' ) ) {
13523
+ if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
13524
+ $resize_detection_script = file_get_contents( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'includes/resize-detection.js' );
13525
+ } else {
13526
+ $resize_detection_script = file_get_contents( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'includes/resize-detection.min.js' );
13527
+ }
13528
  echo "<style>\n" .
13529
  "img.scaled-image {\n" .
13530
  "\tborder: 3px #3eadc9 dotted;\n" .
ewww-image-optimizer.php CHANGED
@@ -13,7 +13,9 @@ 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.2.1
 
 
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.2.2
17
+ Requires at least: 5.4
18
+ Requires PHP: 7.1
19
  Author URI: https://ewww.io/
20
  License: GPLv3
21
  */
includes/lazysizes-post.js CHANGED
@@ -124,7 +124,8 @@ document.addEventListener('lazybeforeunveil', function(e){
124
  console.log('loading an image');
125
  console.log(target);
126
  var wrongSize = false;
127
- var srcset = target.getAttribute('data-srcset');
 
128
  if (target.naturalWidth && ! srcset) {
129
  console.log('we have an image with no srcset');
130
  if ((target.naturalWidth > 1) && (target.naturalHeight > 1)) {
124
  console.log('loading an image');
125
  console.log(target);
126
  var wrongSize = false;
127
+ var srcset = target.getAttribute('data-srcset');
128
+ console.log('natural width of ' + target.getAttribute('src') + ' is ' + target.naturalWidth);
129
  if (target.naturalWidth && ! srcset) {
130
  console.log('we have an image with no srcset');
131
  if ((target.naturalWidth > 1) && (target.naturalHeight > 1)) {
includes/lazysizes-pre.js CHANGED
@@ -14,6 +14,9 @@ function lazysizesWebP(feature, callback) {
14
  };
15
  img.src = "data:image/webp;base64," + kTestImages[feature];
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;
14
  };
15
  img.src = "data:image/webp;base64," + kTestImages[feature];
16
  }*/
17
+ if (typeof ewww_webp_supported === 'undefined') {
18
+ var ewww_webp_supported = false;
19
+ }
20
  window.lazySizesConfig = window.lazySizesConfig || {};
21
  /* window.lazySizesConfig.init = false; */
22
  window.lazySizesConfig.expand = document.documentElement.clientHeight > 500 && document.documentElement.clientWidth > 500 ? 1000 : 740;
includes/lazysizes.min.js CHANGED
@@ -1 +1 @@
1
- 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,g=u[2]-a;return 20<f||20<g?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.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(){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))}),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"),g=t.getAttribute("data-src-webp");if(ewww_webp_supported&&g&&-1==f.search("webp=1")&&(f=g),shouldAutoScale(t)&&shouldAutoScale(t.parentNode))if(window.lazySizes.hC(t,"et_pb_jt_filterable_grid_item_image")||window.lazySizes.hC(t,"ss-foreground-image")||window.lazySizes.hC(t,"img-crop"))h=constrainSrc(f,c,u,"img-crop");else h=constrainSrc(f,c,u,"img");else var h=!1;h&&f!=h&&t.setAttribute("data-src",h)}}if(ewww_webp_supported){if(a){var z=t.getAttribute("data-srcset-webp");z&&t.setAttribute("data-srcset",z)}if(!(g=t.getAttribute("data-src-webp")))return;t.setAttribute("data-src",g)}}),function(e,t){var a=function(i,g,n){"use strict";var h,z;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 z=i.lazySizesConfig||i.lazysizesConfig||{},t)e in z||(z[e]=t[e])}(),!g||!g.getElementsByClassName)return{init:function(){},cfg:z,noSupport:!0};var v=g.documentElement,r=i.HTMLPictureElement,o="addEventListener",m="getAttribute",e=i[o].bind(i),y=i.setTimeout,a=i.requestAnimationFrame||y,s=i.requestIdleCallback,p=/^picture$/i,l=["load","error","lazyincluded","_lazyloaded"],d={},b=Array.prototype.forEach,c=function(e,t){return d[t]||(d[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")),d[t].test(e[m]("class")||"")&&d[t]},w=function(e,t){c(e,t)||e.setAttribute("class",(e[m]("class")||"").trim()+" "+t)},_=function(e,t){var a;(a=c(e,t))&&e.setAttribute("class",(e[m]("class")||"").replace(a," "))},C=function(t,a,e){var i=e?o:"removeEventListener";e&&C(t,a),l.forEach(function(e){t[i](e,a)})},A=function(e,t,a,i,r){var n=g.createEvent("Event");return a||(a={}),a.instance=h,n.initEvent(t,!i,!r),n.detail=a,e.dispatchEvent(n),n},E=function(e,t){var a;!r&&(a=i.picturefill||z.pf)?(t&&t.src&&!e[m]("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<z.minSize&&t&&!e._lazysizesWidth;)a=t.offsetWidth,t=t.parentNode;return a},S=(_e=[],Ce=[],Ae=_e,Ee=function(){var e=Ae;for(Ae=_e.length?Ce:_e,we=!(be=!0);e.length;)e.shift()();be=!1},Se=function(e,t){be&&!t?e.apply(this,arguments):(Ae.push(e),we||(we=!0,(g.hidden?y: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)})}},x=function(e){var t,a,i=function(){t=null,e()},r=function(){var e=n.now()-a;e<99?y(r,99-e):(s||i)(i)};return function(){a=n.now(),t||(t=y(r,99))}},M=(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==J&&(J="hidden"==u(g.body,"visibility")),J||!("hidden"==u(e.parentNode,"visibility")&&"hidden"==u(e,"visibility"))},le=function(e,t){var a,i=e,r=se(e);for($-=t,U+=t,q-=t,j+=t;r&&(i=i.offsetParent)&&i!=g.body&&i!=v;)(r=0<(u(i,"opacity")||1))&&"visible"!=u(i,"overflow")&&(a=i.getBoundingClientRect(),r=j>a.left&&q<a.right&&U>a.top-1&&$<a.bottom+1);return r},de=function(){var e,t,a,i,r,n,o,s,l,d,c,u,f=h.elements;if((P=z.loadMode)&&re<8&&(e=f.length)){for(t=0,ne++;t<e;t++)if(f[t]&&!f[t]._lazyRace)if(!ae||h.prematureUnveil&&h.prematureUnveil(f[t]))ve(f[t]);else if((s=f[t][m]("data-expand"))&&(n=1*s)||(n=ie),d||(d=!z.expand||z.expand<1?500<v.clientHeight&&500<v.clientWidth?500:370:z.expand,h._defEx=d,c=d*z.expFactor,u=z.hFac,J=null,ie<c&&re<1&&2<ne&&2<P&&!g.hidden?(ie=c,ne=0):ie=1<P&&1<ne&&re<6?d:0),l!==n&&(O=innerWidth+n*u,I=innerHeight+n,o=-1*n,l=n),a=f[t].getBoundingClientRect(),(U=a.bottom)>=o&&($=a.top)<=I&&(j=a.right)>=o*u&&(q=a.left)<=O&&(U||j||q||$)&&(z.loadHidden||se(f[t]))&&(T&&re<3&&!s&&(P<3||ne<4)||le(f[t],n))){if(ve(f[t]),r=!0,9<re)break}else!r&&T&&!i&&re<4&&ne<4&&2<P&&(B[0]||z.preloadAfterLoad)&&(B[0]||!s&&(U||j||q||$||"auto"!=f[t][m](z.sizesAttr)))&&(i=B[0]||f[t]);i&&!r&&ve(i)}},G=de,Q=0,V=z.throttleDelay,X=z.ricTimeout,Y=function(){K=!1,Q=n.now(),G()},Z=s&&49<X?function(){s(Y,{timeout:X}),X!==z.ricTimeout&&(X=z.ricTimeout)}:t(function(){y(Y)},!0),ce=function(e){var t;(e=!0===e)&&(X=33),K||(K=!0,(t=V-(n.now()-Q))<0&&(t=0),e||t<9?Z():y(Z,t))},ue=function(e){var t=e.target;t._lazyCache?delete t._lazyCache:(oe(e),w(t,z.loadedClass),_(t,z.loadingClass),C(t,ge),A(t,"lazyloaded"))},fe=t(ue),ge=function(e){fe({target:e.target})},he=function(e){var t,a=e[m](z.srcsetAttr);(t=z.customMedia[e[m]("data-media")||e[m]("media")])&&e.setAttribute("media",t),a&&e.setAttribute("srcset",a)},ze=t(function(t,e,a,i,r){var n,o,s,l,d,c,u,f,g;(d=A(t,"lazybeforeunveil",e)).defaultPrevented||(i&&(a?w(t,z.autosizesClass):t.setAttribute("sizes",i)),o=t[m](z.srcsetAttr),n=t[m](z.srcAttr),r&&(s=t.parentNode,l=s&&p.test(s.nodeName||"")),c=e.firesLoad||"src"in t&&(o||n||l),d={target:t},w(t,z.loadingClass),c&&(clearTimeout(F),F=y(oe,2500),C(t,ge,!0)),l&&b.call(s.getElementsByTagName("source"),he),o?t.setAttribute("srcset",o):n&&!l&&(te.test(t.nodeName)?(f=n,0==(g=(u=t).getAttribute("data-load-mode")||z.iframeLoadMode)?u.contentWindow.location.replace(f):1==g&&(u.src=f)):t.src=n),r&&(o||l)&&E(t,{src:n})),t._lazyRace&&delete t._lazyRace,_(t,z.lazyClass),S(function(){var e=t.complete&&1<t.naturalWidth;c&&!e||(e&&w(t,z.fastLoadedClass),ue(d),t._lazyCache=!0,y(function(){"_lazyCache"in t&&delete t._lazyCache},9)),"lazy"==t.loading&&re--},!0)}),ve=function(e){if(!e._lazyRace){var t,a=ee.test(e.nodeName),i=a&&(e[m](z.sizesAttr)||e[m]("sizes")),r="auto"==i;(!r&&T||!a||!e[m]("src")&&!e.srcset||e.complete||c(e,z.errorClass)||!c(e,z.lazyClass))&&(t=A(e,"lazyunveilread").detail,r&&W.updateElem(e,!0,e.offsetWidth),e._lazyRace=!0,re++,ze(e,t,r,i,a))}},me=x(function(){z.loadMode=3,ce()}),ye=function(){3==z.loadMode&&(z.loadMode=2),me()},pe=function(){T||(n.now()-D<999?y(pe,999):(T=!0,z.loadMode=3,ce(),e("scroll",ye,!0)))},{_:function(){D=n.now(),h.elements=g.getElementsByClassName(z.lazyClass),B=g.getElementsByClassName(z.lazyClass+" "+z.preloadClass),e("scroll",ce,!0),e("resize",ce,!0),e("pageshow",function(e){if(e.persisted){var t=g.querySelectorAll("."+z.loadingClass);t.length&&t.forEach&&a(function(){t.forEach(function(e){e.complete&&ve(e)})})}}),i.MutationObserver?new MutationObserver(ce).observe(v,{childList:!0,subtree:!0,attributes:!0}):(v[o]("DOMNodeInserted",ce,!0),v[o]("DOMAttrModified",ce,!0),setInterval(ce,999)),e("hashchange",ce,!0),["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){g[o](e,ce,!0)}),/d$|^c/.test(g.readyState)?pe():(e("load",pe),g[o]("DOMContentLoaded",ce),y(pe,2e4)),h.elements.length?(de(),S._lsFlush()):ce()},checkElems:ce,unveil:ve,_aLSL:ye}),W=(H=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=A(e,"lazybeforesizes",{width:a,dataAttr:!!t})).defaultPrevented||(a=i.detail.width)&&a!==e._lazysizesWidth&&H(e,r,i,a))},k=x(function(){var e,t=N.length;if(t)for(e=0;e<t;e++)R(N[e])}),{_:function(){N=g.getElementsByClassName(z.autosizesClass),e("resize",k)},checkElems:k,updateElem:R}),L=function(){!L.i&&g.getElementsByClassName&&(L.i=!0,W._(),M._())};var N,H,R,k;var B,T,F,P,D,O,I,$,q,j,U,J,G,K,Q,V,X,Y,Z,ee,te,ae,ie,re,ne,oe,se,le,de,ce,ue,fe,ge,he,ze,ve,me,ye,pe;var be,we,_e,Ce,Ae,Ee,Se;return y(function(){z.init&&L()}),h={cfg:z,autoSizer:W,loader:M,init:L,uP:E,aC:w,rC:_,hC:c,fire:A,gW:f,rAF:S}}(e,e.document,Date);e.lazySizes=a,"object"==typeof module&&module.exports&&(module.exports=a)}("undefined"!=typeof window?window:{});
1
+ if(void 0===ewww_webp_supported)var ewww_webp_supported=!1;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,g=u[2]-a;return 20<f||20<g?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.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(){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)):n<300&&(n=430),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))}),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"),g=t.getAttribute("data-src-webp");if(ewww_webp_supported&&g&&-1==f.search("webp=1")&&(f=g),shouldAutoScale(t)&&shouldAutoScale(t.parentNode))if(window.lazySizes.hC(t,"et_pb_jt_filterable_grid_item_image")||window.lazySizes.hC(t,"ss-foreground-image")||window.lazySizes.hC(t,"img-crop"))h=constrainSrc(f,c,u,"img-crop");else h=constrainSrc(f,c,u,"img");else var h=!1;h&&f!=h&&t.setAttribute("data-src",h)}}if(ewww_webp_supported){if(a){var z=t.getAttribute("data-srcset-webp");z&&t.setAttribute("data-srcset",z)}if(!(g=t.getAttribute("data-src-webp")))return;t.setAttribute("data-src",g)}}),function(e,t){var a=function(i,g,n){"use strict";var h,z;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 z=i.lazySizesConfig||i.lazysizesConfig||{},t)e in z||(z[e]=t[e])}(),!g||!g.getElementsByClassName)return{init:function(){},cfg:z,noSupport:!0};var v=g.documentElement,r=i.HTMLPictureElement,o="addEventListener",m="getAttribute",e=i[o].bind(i),p=i.setTimeout,a=i.requestAnimationFrame||p,s=i.requestIdleCallback,y=/^picture$/i,l=["load","error","lazyincluded","_lazyloaded"],d={},b=Array.prototype.forEach,c=function(e,t){return d[t]||(d[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")),d[t].test(e[m]("class")||"")&&d[t]},w=function(e,t){c(e,t)||e.setAttribute("class",(e[m]("class")||"").trim()+" "+t)},_=function(e,t){var a;(a=c(e,t))&&e.setAttribute("class",(e[m]("class")||"").replace(a," "))},C=function(t,a,e){var i=e?o:"removeEventListener";e&&C(t,a),l.forEach(function(e){t[i](e,a)})},A=function(e,t,a,i,r){var n=g.createEvent("Event");return a||(a={}),a.instance=h,n.initEvent(t,!i,!r),n.detail=a,e.dispatchEvent(n),n},E=function(e,t){var a;!r&&(a=i.picturefill||z.pf)?(t&&t.src&&!e[m]("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<z.minSize&&t&&!e._lazysizesWidth;)a=t.offsetWidth,t=t.parentNode;return a},S=(_e=[],Ce=[],Ae=_e,Ee=function(){var e=Ae;for(Ae=_e.length?Ce:_e,we=!(be=!0);e.length;)e.shift()();be=!1},Se=function(e,t){be&&!t?e.apply(this,arguments):(Ae.push(e),we||(we=!0,(g.hidden?p: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)})}},x=function(e){var t,a,i=function(){t=null,e()},r=function(){var e=n.now()-a;e<99?p(r,99-e):(s||i)(i)};return function(){a=n.now(),t||(t=p(r,99))}},M=(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==J&&(J="hidden"==u(g.body,"visibility")),J||!("hidden"==u(e.parentNode,"visibility")&&"hidden"==u(e,"visibility"))},le=function(e,t){var a,i=e,r=se(e);for($-=t,U+=t,q-=t,j+=t;r&&(i=i.offsetParent)&&i!=g.body&&i!=v;)(r=0<(u(i,"opacity")||1))&&"visible"!=u(i,"overflow")&&(a=i.getBoundingClientRect(),r=j>a.left&&q<a.right&&U>a.top-1&&$<a.bottom+1);return r},de=function(){var e,t,a,i,r,n,o,s,l,d,c,u,f=h.elements;if((P=z.loadMode)&&re<8&&(e=f.length)){for(t=0,ne++;t<e;t++)if(f[t]&&!f[t]._lazyRace)if(!ae||h.prematureUnveil&&h.prematureUnveil(f[t]))ve(f[t]);else if((s=f[t][m]("data-expand"))&&(n=1*s)||(n=ie),d||(d=!z.expand||z.expand<1?500<v.clientHeight&&500<v.clientWidth?500:370:z.expand,h._defEx=d,c=d*z.expFactor,u=z.hFac,J=null,ie<c&&re<1&&2<ne&&2<P&&!g.hidden?(ie=c,ne=0):ie=1<P&&1<ne&&re<6?d:0),l!==n&&(O=innerWidth+n*u,I=innerHeight+n,o=-1*n,l=n),a=f[t].getBoundingClientRect(),(U=a.bottom)>=o&&($=a.top)<=I&&(j=a.right)>=o*u&&(q=a.left)<=O&&(U||j||q||$)&&(z.loadHidden||se(f[t]))&&(T&&re<3&&!s&&(P<3||ne<4)||le(f[t],n))){if(ve(f[t]),r=!0,9<re)break}else!r&&T&&!i&&re<4&&ne<4&&2<P&&(B[0]||z.preloadAfterLoad)&&(B[0]||!s&&(U||j||q||$||"auto"!=f[t][m](z.sizesAttr)))&&(i=B[0]||f[t]);i&&!r&&ve(i)}},G=de,Q=0,V=z.throttleDelay,X=z.ricTimeout,Y=function(){K=!1,Q=n.now(),G()},Z=s&&49<X?function(){s(Y,{timeout:X}),X!==z.ricTimeout&&(X=z.ricTimeout)}:t(function(){p(Y)},!0),ce=function(e){var t;(e=!0===e)&&(X=33),K||(K=!0,(t=V-(n.now()-Q))<0&&(t=0),e||t<9?Z():p(Z,t))},ue=function(e){var t=e.target;t._lazyCache?delete t._lazyCache:(oe(e),w(t,z.loadedClass),_(t,z.loadingClass),C(t,ge),A(t,"lazyloaded"))},fe=t(ue),ge=function(e){fe({target:e.target})},he=function(e){var t,a=e[m](z.srcsetAttr);(t=z.customMedia[e[m]("data-media")||e[m]("media")])&&e.setAttribute("media",t),a&&e.setAttribute("srcset",a)},ze=t(function(t,e,a,i,r){var n,o,s,l,d,c,u,f,g;(d=A(t,"lazybeforeunveil",e)).defaultPrevented||(i&&(a?w(t,z.autosizesClass):t.setAttribute("sizes",i)),o=t[m](z.srcsetAttr),n=t[m](z.srcAttr),r&&(s=t.parentNode,l=s&&y.test(s.nodeName||"")),c=e.firesLoad||"src"in t&&(o||n||l),d={target:t},w(t,z.loadingClass),c&&(clearTimeout(F),F=p(oe,2500),C(t,ge,!0)),l&&b.call(s.getElementsByTagName("source"),he),o?t.setAttribute("srcset",o):n&&!l&&(te.test(t.nodeName)?(f=n,0==(g=(u=t).getAttribute("data-load-mode")||z.iframeLoadMode)?u.contentWindow.location.replace(f):1==g&&(u.src=f)):t.src=n),r&&(o||l)&&E(t,{src:n})),t._lazyRace&&delete t._lazyRace,_(t,z.lazyClass),S(function(){var e=t.complete&&1<t.naturalWidth;c&&!e||(e&&w(t,z.fastLoadedClass),ue(d),t._lazyCache=!0,p(function(){"_lazyCache"in t&&delete t._lazyCache},9)),"lazy"==t.loading&&re--},!0)}),ve=function(e){if(!e._lazyRace){var t,a=ee.test(e.nodeName),i=a&&(e[m](z.sizesAttr)||e[m]("sizes")),r="auto"==i;(!r&&T||!a||!e[m]("src")&&!e.srcset||e.complete||c(e,z.errorClass)||!c(e,z.lazyClass))&&(t=A(e,"lazyunveilread").detail,r&&W.updateElem(e,!0,e.offsetWidth),e._lazyRace=!0,re++,ze(e,t,r,i,a))}},me=x(function(){z.loadMode=3,ce()}),pe=function(){3==z.loadMode&&(z.loadMode=2),me()},ye=function(){T||(n.now()-D<999?p(ye,999):(T=!0,z.loadMode=3,ce(),e("scroll",pe,!0)))},{_:function(){D=n.now(),h.elements=g.getElementsByClassName(z.lazyClass),B=g.getElementsByClassName(z.lazyClass+" "+z.preloadClass),e("scroll",ce,!0),e("resize",ce,!0),e("pageshow",function(e){if(e.persisted){var t=g.querySelectorAll("."+z.loadingClass);t.length&&t.forEach&&a(function(){t.forEach(function(e){e.complete&&ve(e)})})}}),i.MutationObserver?new MutationObserver(ce).observe(v,{childList:!0,subtree:!0,attributes:!0}):(v[o]("DOMNodeInserted",ce,!0),v[o]("DOMAttrModified",ce,!0),setInterval(ce,999)),e("hashchange",ce,!0),["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){g[o](e,ce,!0)}),/d$|^c/.test(g.readyState)?ye():(e("load",ye),g[o]("DOMContentLoaded",ce),p(ye,2e4)),h.elements.length?(de(),S._lsFlush()):ce()},checkElems:ce,unveil:ve,_aLSL:pe}),W=(H=t(function(e,t,a,i){var r,n,o;if(e._lazysizesWidth=i,i+="px",e.setAttribute("sizes",i),y.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=A(e,"lazybeforesizes",{width:a,dataAttr:!!t})).defaultPrevented||(a=i.detail.width)&&a!==e._lazysizesWidth&&H(e,r,i,a))},k=x(function(){var e,t=N.length;if(t)for(e=0;e<t;e++)R(N[e])}),{_:function(){N=g.getElementsByClassName(z.autosizesClass),e("resize",k)},checkElems:k,updateElem:R}),L=function(){!L.i&&g.getElementsByClassName&&(L.i=!0,W._(),M._())};var N,H,R,k;var B,T,F,P,D,O,I,$,q,j,U,J,G,K,Q,V,X,Y,Z,ee,te,ae,ie,re,ne,oe,se,le,de,ce,ue,fe,ge,he,ze,ve,me,pe,ye;var be,we,_e,Ce,Ae,Ee,Se;return p(function(){z.init&&L()}),h={cfg:z,autoSizer:W,loader:M,init:L,uP:E,aC:w,rC:_,hC:c,fire:A,gW:f,rAF:S}}(e,e.document,Date);e.lazySizes=a,"object"==typeof module&&module.exports&&(module.exports=a)}("undefined"!=typeof window?window:{});
includes/ls.unveilhooks.js CHANGED
@@ -53,6 +53,8 @@
53
  console.log('also has-parallax with data-bg');
54
  targetWidth = Math.round(window.screen.width * dPR);
55
  targetHeight = Math.round(window.screen.height * dPR);
 
 
56
  }
57
  bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover');
58
  } else if (window.lazySizes.hC(e.target,'elementor-bg')){
53
  console.log('also has-parallax with data-bg');
54
  targetWidth = Math.round(window.screen.width * dPR);
55
  targetHeight = Math.round(window.screen.height * dPR);
56
+ } else if (targetHeight<300) {
57
+ targetHeight = 430;
58
  }
59
  bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover');
60
  } else if (window.lazySizes.hC(e.target,'elementor-bg')){
includes/{resize_detection.js → resize-detection.js} RENAMED
@@ -27,6 +27,10 @@ function checkImageScale(img) {
27
  console.log('not checking size of SVG: ' + img.src);
28
  return;
29
  }
 
 
 
 
30
  console.log('checking size of: ' + img.src);
31
  if (img.naturalWidth) {
32
  if (img.naturalWidth > 25 && img.naturalHeight > 25 && img.clientWidth > 25 && img.clientHeight > 25) {
27
  console.log('not checking size of SVG: ' + img.src);
28
  return;
29
  }
30
+ if ('string' == typeof img.src && img.src.search(/data:image/) > -1) {
31
+ console.log('not checking size of data uri');
32
+ return;
33
+ }
34
  console.log('checking size of: ' + img.src);
35
  if (img.naturalWidth) {
36
  if (img.naturalWidth > 25 && img.naturalHeight > 25 && img.clientWidth > 25 && img.clientHeight > 25) {
includes/resize-detection.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function checkImageSizes(){var e=document.getElementsByTagName("img");for(i=0;i<e.length;i++)e[i].classList.remove("scaled-image"),checkImageScale(e[i]);return!1}function checkImageScale(e){if(e.src&&!("string"==typeof e.src&&-1<e.src.search(/\.svg/))&&!("string"==typeof e.src&&-1<e.src.search(/data:image/))&&e.naturalWidth&&25<e.naturalWidth&&25<e.naturalHeight&&25<e.clientWidth&&25<e.clientHeight){var t=window.devicePixelRatio||1,a=1.5*e.clientWidth*t<e.naturalWidth,i=1.5*e.clientHeight*t<e.naturalHeight;(a||i)&&(e.classList.add("scaled-image"),e.title="Forced to wrong size: "+e.clientWidth+"x"+e.clientHeight+", natural is "+e.naturalWidth+"x"+e.naturalHeight+"!")}}function clearScaledImages(){for(var e=document.querySelectorAll("img.scaled-image"),t=0,a=e.length;t<a;t++)e[t].classList.remove("scaled-image")}window.onload=function(){checkImageSizes();var e=document.getElementById("wp-admin-bar-resize-detection");e&&(e.onclick=function(){clearScaledImages(),checkImageSizes()})},document.addEventListener("lazyloaded",function(e){e.target.classList.remove("scaled-image"),0===e.target.title.search("Forced to wrong size")&&(e.target.title=""),checkImageScale(e.target)});
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: optimize, image, convert, webp, resize, compress, lazy load, optimization,
5
  Requires at least: 5.4
6
  Tested up to: 5.8
7
  Requires PHP: 7.1
8
- Stable tag: 6.2.1
9
  License: GPLv3
10
 
11
  Smaller Images, Faster Sites, Happier Visitors. Comprehensive image optimization that doesn't require a degree in rocket science.
@@ -114,7 +114,7 @@ See [https://docs.ewww.io/article/39-bulk-optimizer-failure](https://docs.ewww.i
114
 
115
  = What are the supported operating systems? =
116
 
117
- I've tested it on Windows (with Apache), Linux, Mac OSX, FreeBSD, and Solaris. The cloud API will work on any OS.
118
 
119
  = I want to know more about image optimization, and why you chose these options/tools. =
120
 
@@ -132,6 +132,19 @@ 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/b/features)
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.2.1 =
136
  * fixed: Lazy Load regression prevents above-the-fold CSS background images from loading
137
  * fixed: WebP Conversion for CMYK images leaves empty color profile attached
5
  Requires at least: 5.4
6
  Tested up to: 5.8
7
  Requires PHP: 7.1
8
+ Stable tag: 6.2.2
9
  License: GPLv3
10
 
11
  Smaller Images, Faster Sites, Happier Visitors. Comprehensive image optimization that doesn't require a degree in rocket science.
114
 
115
  = What are the supported operating systems? =
116
 
117
+ I've tested it on Windows (with Apache), Linux, Mac OSX, FreeBSD, and Solaris. The Compress API and Easy IO CDN will work on any OS.
118
 
119
  = I want to know more about image optimization, and why you chose these options/tools. =
120
 
132
  * Feature requests can be viewed and submitted on our [feedback portal](https://feedback.ewww.io/b/features)
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.2.2 =
136
+ * added: disable Easy IO's "deep" integration with image_downsize filter via EIO_DISABLE_DEEP_INTEGRATION override
137
+ * added: integration with JSON/AJAX respones from Spotlight Social Media Feeds plugin
138
+ * changed: PNG placeholders are now inlined for less HTTP requests and better auto-scaling
139
+ * changed: Bulk Optimizer processes images from oldest to newest for the Media Library
140
+ * changed: Resize Detection uses minified JS and console logging suppressed unless using SCRIPT_DEBUG
141
+ * fixed: Easy IO does not rewrite image (href) links if image_downsize integration has rewritten the img tag
142
+ * fixed: Lazy Load throws error when ewww_webp_supported not defined in edge cases
143
+ * fixed: front-end scripts loading for page builders when they shouldn't be
144
+ * fixed: when using WP/LR Sync, EWWWIO_WPLR_AUTO does not trigger optimization for new images
145
+ * fixed: img element search parsing JSON incorrectly
146
+ * fixed: WebP uploads not resized to max dimensions
147
+
148
  = 6.2.1 =
149
  * fixed: Lazy Load regression prevents above-the-fold CSS background images from loading
150
  * fixed: WebP Conversion for CMYK images leaves empty color profile attached
tests/test-utility.php CHANGED
@@ -129,10 +129,10 @@ class EWWWIO_Utility_Tests extends WP_UnitTestCase {
129
  '197.234.240.0/22',
130
  '198.41.128.0/17',
131
  '162.158.0.0/15',
132
- '172.64.0.0/13',
133
- '131.0.72.0/22',
134
  '104.16.0.0/13',
135
  '104.24.0.0/14',
 
 
136
  );
137
  foreach( $latest_ips as $key => $range ) {
138
  if ( empty( $range ) ) {
129
  '197.234.240.0/22',
130
  '198.41.128.0/17',
131
  '162.158.0.0/15',
 
 
132
  '104.16.0.0/13',
133
  '104.24.0.0/14',
134
+ '172.64.0.0/13',
135
+ '131.0.72.0/22',
136
  );
137
  foreach( $latest_ips as $key => $range ) {
138
  if ( empty( $range ) ) {