EWWW Image Optimizer - Version 4.7.0

Version Description

  • added: lazy load (on ExactDN tab for now)
  • added: JS WebP supports background images via lazy load (div elements only for now)
  • added: ExactDN supports compression of background images (div elements only for now)
  • added: compat with Google Cloud Storage via WP Offload Media
  • added: automatic PNG to JPG conversion for ExactDN
  • added: ExactDN parsing for legacy WooCommerce API (current API works as-is)
  • changed: responsive image 'sizes' attribute can be auto-calculated by lazy load
  • changed: JS WebP no longer requires jQuery
  • changed: ExactDN srcset multipliers include fullscreen value of 1920px
  • changed: force resize function to ignore filesize with ewww_image_optimizer_resize_filesize_ignore filter
  • changed: prevent .php script/style generators from going through ExactDN
  • changed: ExactDN sites can dismiss exec notice to disable local compression
  • changed: automatic compression disabled during WooCommerce regen with admin notice
  • changed: use wp_resource_hints filter to include ExactDN dns-prefetch earlier in the page header
  • changed: gather debugging information on settings page even when debugging is not enabled yet
  • fixed: Bulk Optimize scanner does not update queue in some cases
  • fixed: ExactDN does not handle themes that support wide and full-screen images in block editor
  • fixed: ExactDN constrains images to 640px in Twenty Nineteen theme
  • fixed: ExactDN mangles Flatsome lazy load placeholder image URL
  • fixed: empty attributes not recognized properly by HTML parser, resulting in broken markup
  • fixed: table nav button styling broken in WP 5.1
  • fixed: ExactDN applies resizing args during image_downsize() even when full/original image is too small
  • fixed: animated GIF resizing breaks the use of image_resize_dimensions filter in WP_Image_Editor_GD
  • fixed: NextGen bulk optimizer unable to decode meta_data
Download this release

Release Info

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

Code changes from version 4.6.3 to 4.7.0

aux-optimize.php CHANGED
@@ -56,12 +56,12 @@ function ewww_image_optimizer_aux_images() {
56
  '<div class="tablenav-pages ewww-aux-table">' .
57
  '<span class="displaying-num ewww-aux-table"></span>' . "\n" .
58
  '<span id="paginator" class="pagination-links ewww-aux-table">' . "\n" .
59
- '<a id="first-images" class="first-page" style="display:none">&laquo;</a>' . "\n" .
60
- '<a id="prev-images" class="prev-page" style="display:none">&lsaquo;</a>' . "\n";
61
  $output .= esc_html__( 'page', 'ewww-image-optimizer' ) . ' <span class="current-page"></span> ' . esc_html__( 'of', 'ewww-image-optimizer' ) . "\n";
62
  $output .= '<span class="total-pages"></span>' . "\n" .
63
- '<a id="next-images" class="next-page" style="display:none">&rsaquo;</a>' . "\n" .
64
- '<a id="last-images" class="last-page" style="display:none">&raquo;</a>' .
65
  '</span>' .
66
  '</div>' .
67
  '</div>' .
@@ -75,13 +75,13 @@ function ewww_image_optimizer_aux_images() {
75
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
76
  global $ewww_debug;
77
  ewww_image_optimizer_options( 'debug-silent' );
78
- $output .= '<p style="clear:both"><b>' . esc_html__( 'Debugging Information', 'ewww-image-optimizer' ) . ':</b> <button id="ewww-copy-debug" class="button button-secondary">' . esc_html__( 'Copy', 'ewww-image-optimizer' ) . '</button>';
79
  if ( is_file( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'debug.log' ) ) {
80
  $debug_log_url = plugins_url( '/debug.log', __FILE__ );
81
  $output .= "&emsp;<a href='$debug_log_url'>" . esc_html( 'View Debug Log', 'ewww-image-optimizer' ) . "</a> - <a href='admin.php?action=ewww_image_optimizer_delete_debug_log'>" . esc_html( 'Remove Debug Log', 'ewww-image-optimizer' ) . '</a>';
82
  }
83
  $output .= '</p>';
84
- $output .= '<div id="ewww-debug-info" style="background:#ffff99;margin-left:-20px;padding:10px" contenteditable="true">' . $ewww_debug . '</div>';
85
  $help_instructions = esc_html__( 'Debugging information will be included with your message automatically.', 'ewww-image-optimizer' ) . ' ' .
86
  esc_html__( 'This will allow us to assist you more quickly.', 'ewww-image-optimizer' );
87
  }
@@ -174,7 +174,7 @@ function ewww_image_optimizer_aux_images_table() {
174
  if ( DAY_IN_SECONDS * 30 + $updated_time < time() ) {
175
  $optimized_image['backup'] = '';
176
  }
177
- if ( strpos( $file, 's3' ) === 0 ) {
178
  // Retrieve the mimetype of the attachment.
179
  $type = esc_html__( 'Amazon S3 image', 'ewww-image-optimizer' );
180
  $file_size = ewww_image_optimizer_size_format( $optimized_image['image_size'] );
@@ -433,6 +433,7 @@ function ewww_image_optimizer_get_queued_attachments( $gallery, $limit = 100 ) {
433
  * @global object $wpdb
434
  */
435
  function ewww_image_optimizer_insert_unscanned( $ids, $gallery = 'media' ) {
 
436
  global $wpdb;
437
  $images = array();
438
  $id = array_shift( $ids );
@@ -462,27 +463,15 @@ function ewww_image_optimizer_insert_unscanned( $ids, $gallery = 'media' ) {
462
  * @global object $wpdb
463
  */
464
  function ewww_image_optimizer_update_scanned_images( $ids, $gallery = 'media' ) {
 
465
  if ( ! ewww_image_optimizer_iterable( $ids ) ) {
466
  return;
467
  }
468
  global $wpdb;
469
 
470
- /*
471
- $wpdb->update(
472
- $wpdb->ewwwio_queue,
473
- array(
474
- 'scanned' => 1,
475
- ),
476
- array(
477
- 'gallery' => $gallery,
478
- 'attachment_id' => (int) $id,
479
- ),
480
- array( '%d' ),
481
- array( '%s', '%d' )
482
- );
483
- */
484
  array_walk( $ids, 'intval' );
485
  $ids_sql = '(' . implode( ',', $ids ) . ')';
 
486
  $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->ewwwio_queue SET scanned = 1 WHERE gallery = %s AND attachment_id IN $ids_sql", $gallery ) ); // phpcs:ignore WordPress.DB.PreparedSQL
487
  }
488
 
@@ -496,23 +485,15 @@ function ewww_image_optimizer_update_scanned_images( $ids, $gallery = 'media' )
496
  * @global object $wpdb
497
  */
498
  function ewww_image_optimizer_delete_queued_images( $ids, $gallery = 'media' ) {
 
499
  if ( ! ewww_image_optimizer_iterable( $ids ) ) {
500
  return;
501
  }
502
  global $wpdb;
503
 
504
- /*
505
- $wpdb->delete(
506
- $wpdb->ewwwio_queue,
507
- array(
508
- 'gallery' => $gallery,
509
- 'attachment_id' => (int) $id,
510
- ),
511
- array( '%s', '%d' )
512
- );
513
- */
514
  array_walk( $ids, 'intval' );
515
  $ids_sql = '(' . implode( ',', $ids ) . ')';
 
516
  $wpdb->query( $wpdb->prepare( "DELETE from $wpdb->ewwwio_queue WHERE gallery = %s AND attachment_id IN $ids_sql", $gallery ) ); // phpcs:ignore WordPress.DB.PreparedSQL
517
  }
518
 
56
  '<div class="tablenav-pages ewww-aux-table">' .
57
  '<span class="displaying-num ewww-aux-table"></span>' . "\n" .
58
  '<span id="paginator" class="pagination-links ewww-aux-table">' . "\n" .
59
+ '<a id="first-images" class="tablenav-pages-navspan button first-page" style="display:none">&laquo;</a>' . "\n" .
60
+ '<a id="prev-images" class="tablenav-pages-navspan button prev-page" style="display:none">&lsaquo;</a>' . "\n";
61
  $output .= esc_html__( 'page', 'ewww-image-optimizer' ) . ' <span class="current-page"></span> ' . esc_html__( 'of', 'ewww-image-optimizer' ) . "\n";
62
  $output .= '<span class="total-pages"></span>' . "\n" .
63
+ '<a id="next-images" class="tablenav-pages-navspan button next-page" style="display:none">&rsaquo;</a>' . "\n" .
64
+ '<a id="last-images" class="tablenav-pages-navspan button last-page" style="display:none">&raquo;</a>' .
65
  '</span>' .
66
  '</div>' .
67
  '</div>' .
75
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
76
  global $ewww_debug;
77
  ewww_image_optimizer_options( 'debug-silent' );
78
+ $output .= '<p style="clear:both"><b>' . esc_html__( 'Debugging Information', 'ewww-image-optimizer' ) . ':</b> <button id="ewww-copy-debug" class="button button-secondary" type="button">' . esc_html__( 'Copy', 'ewww-image-optimizer' ) . '</button>';
79
  if ( is_file( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'debug.log' ) ) {
80
  $debug_log_url = plugins_url( '/debug.log', __FILE__ );
81
  $output .= "&emsp;<a href='$debug_log_url'>" . esc_html( 'View Debug Log', 'ewww-image-optimizer' ) . "</a> - <a href='admin.php?action=ewww_image_optimizer_delete_debug_log'>" . esc_html( 'Remove Debug Log', 'ewww-image-optimizer' ) . '</a>';
82
  }
83
  $output .= '</p>';
84
+ $output .= '<div id="ewww-debug-info" style="border:1px solid #e5e5e5;background:#fff;overflow:auto;height:300px;width:800px;" contenteditable="true">' . $ewww_debug . '</div>';
85
  $help_instructions = esc_html__( 'Debugging information will be included with your message automatically.', 'ewww-image-optimizer' ) . ' ' .
86
  esc_html__( 'This will allow us to assist you more quickly.', 'ewww-image-optimizer' );
87
  }
174
  if ( DAY_IN_SECONDS * 30 + $updated_time < time() ) {
175
  $optimized_image['backup'] = '';
176
  }
177
+ if ( ewww_image_optimizer_stream_wrapped( $file ) ) {
178
  // Retrieve the mimetype of the attachment.
179
  $type = esc_html__( 'Amazon S3 image', 'ewww-image-optimizer' );
180
  $file_size = ewww_image_optimizer_size_format( $optimized_image['image_size'] );
433
  * @global object $wpdb
434
  */
435
  function ewww_image_optimizer_insert_unscanned( $ids, $gallery = 'media' ) {
436
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
437
  global $wpdb;
438
  $images = array();
439
  $id = array_shift( $ids );
463
  * @global object $wpdb
464
  */
465
  function ewww_image_optimizer_update_scanned_images( $ids, $gallery = 'media' ) {
466
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
467
  if ( ! ewww_image_optimizer_iterable( $ids ) ) {
468
  return;
469
  }
470
  global $wpdb;
471
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
472
  array_walk( $ids, 'intval' );
473
  $ids_sql = '(' . implode( ',', $ids ) . ')';
474
+
475
  $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->ewwwio_queue SET scanned = 1 WHERE gallery = %s AND attachment_id IN $ids_sql", $gallery ) ); // phpcs:ignore WordPress.DB.PreparedSQL
476
  }
477
 
485
  * @global object $wpdb
486
  */
487
  function ewww_image_optimizer_delete_queued_images( $ids, $gallery = 'media' ) {
488
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
489
  if ( ! ewww_image_optimizer_iterable( $ids ) ) {
490
  return;
491
  }
492
  global $wpdb;
493
 
 
 
 
 
 
 
 
 
 
 
494
  array_walk( $ids, 'intval' );
495
  $ids_sql = '(' . implode( ',', $ids ) . ')';
496
+
497
  $wpdb->query( $wpdb->prepare( "DELETE from $wpdb->ewwwio_queue WHERE gallery = %s AND attachment_id IN $ids_sql", $gallery ) ); // phpcs:ignore WordPress.DB.PreparedSQL
498
  }
499
 
bulk.php CHANGED
@@ -218,41 +218,7 @@ function ewww_image_optimizer_count_optimized( $gallery ) {
218
  $attachment_query_count = 0;
219
  switch ( $gallery ) {
220
  case 'media':
221
- /*
222
- $ids = array();
223
- $resume = get_option( 'ewww_image_optimizer_bulk_resume' );
224
- // See if we were given attachment IDs to work with via GET/POST.
225
- if ( false && ! empty( $_REQUEST['ids'] ) || $resume ) {
226
- ewwwio_debug_message( 'we have received attachment ids via $_REQUEST' );
227
- // Retrieve the attachment IDs that were pre-loaded in the database.
228
- if ( 'scanning' == $resume ) {
229
- ewwwio_debug_message( 'still scanning media - phase 1' );
230
- $finished = (array) get_option( 'ewww_image_optimizer_bulk_attachments' );
231
- $remaining = (array) get_option( 'ewww_image_optimizer_scanning_attachments' );
232
- $attachment_ids = array_merge( $finished, $remaining );
233
- } elseif ( $resume ) {
234
- // This shouldn't ever happen, but doesn't hurt to account for the use case, just in case something changes in the future.
235
- ewwwio_debug_message( 'this is the improbable, but it happened' );
236
- $attachment_ids = get_option( 'ewww_image_optimizer_bulk_attachments' );
237
- } else {
238
- ewwwio_debug_message( 'we really did get attachments via $_REQUEST, or so we think' );
239
- $attachment_ids = get_option( 'ewww_image_optimizer_scanning_attachments' );
240
- }
241
- if ( ! empty( $attachment_ids ) ) {
242
- $full_count = count( $attachment_ids );
243
- } else {
244
- $full_count = $wpdb->get_var( "SELECT COUNT(ID) FROM $wpdb->posts WHERE (post_type = 'attachment' OR post_type = 'ims_image') AND (post_mime_type LIKE '%%image%%' OR post_mime_type LIKE '%%pdf%%')" );
245
- }
246
- } else {
247
- */
248
- /* $full_count = $wpdb->get_var( "SELECT COUNT(ID) FROM $wpdb->posts WHERE (post_type = 'attachment' OR post_type = 'ims_image') AND (post_mime_type LIKE '%%image%%' OR post_mime_type LIKE '%%pdf%%')" ); */
249
-
250
- /*
251
- $full_count = $wpdb->get_var( "SELECT COUNT(attachment_id) FROM $wpdb->ewwwio_queue WHERE gallery = 'media'" );
252
- }
253
- */
254
  return ewww_image_optimizer_count_attachments();
255
- /* return $full_count; */
256
  break;
257
  case 'ngg':
258
  // See if we were given attachment IDs to work with via GET/POST.
@@ -279,6 +245,8 @@ function ewww_image_optimizer_count_optimized( $gallery ) {
279
  if ( class_exists( 'Ngg_Serializable' ) ) {
280
  $serializer = new Ngg_Serializable();
281
  $meta = $serializer->unserialize( $attachment );
 
 
282
  } else {
283
  $meta = unserialize( $attachment );
284
  }
@@ -401,11 +369,6 @@ function ewww_image_optimizer_bulk_script( $hook ) {
401
  update_option( 'ewww_image_optimizer_bulk_resume', '' );
402
  update_option( 'ewww_image_optimizer_aux_resume', '' );
403
 
404
- /*
405
- REMOVE
406
- update_option( 'ewww_image_optimizer_scanning_attachments', '', false );
407
- update_option( 'ewww_image_optimizer_bulk_attachments', '', false );
408
- */
409
  ewww_image_optimizer_delete_queue_images();
410
  ewww_image_optimizer_delete_pending();
411
  }
@@ -417,11 +380,6 @@ function ewww_image_optimizer_bulk_script( $hook ) {
417
  $resume = get_option( 'ewww_image_optimizer_bulk_resume' );
418
  $scanning = get_option( 'ewww_image_optimizer_aux_resume' );
419
  if ( ! $resume && ! $scanning ) {
420
- /*
421
- REMOVE
422
- update_option( 'ewww_image_optimizer_scanning_attachments', '', false );
423
- update_option( 'ewww_image_optimizer_bulk_attachments', '', false );
424
- */
425
  ewwwio_debug_message( 'not resuming/scanning, so clearing any pending images in both tables' );
426
  ewww_image_optimizer_delete_queue_images();
427
  ewww_image_optimizer_delete_pending();
@@ -458,10 +416,6 @@ function ewww_image_optimizer_bulk_script( $hook ) {
458
  } elseif ( 'scanning' == $resume ) {
459
  ewwwio_debug_message( 'scanning, nothing doing' );
460
  // TODO: do nothing...
461
- // Retrieve the attachment IDs that have not been finished from the 'scanning attachments' option.
462
- /* $attachments = get_option( 'ewww_image_optimizer_scanning_attachments' ); */
463
-
464
- /* $attachment_count = ewww_image_optimizer_count_unscanned_attachments( 'media' ); */
465
  } elseif ( $scanning || $resume ) {
466
  ewwwio_debug_message( 'resuming, nothing doing' );
467
  /* $attachments = array(); */
@@ -765,13 +719,6 @@ function ewww_image_optimizer_media_scan( $hook = '' ) {
765
  }
766
  }
767
  if ( ! empty( $attachment_ids ) && is_array( $attachment_ids ) ) {
768
- /*
769
- $selected_ids = null;
770
- ewwwio_debug_message( 'remaining items: ' . count( $attachment_ids ) );
771
- // Retrieve the attachment IDs that were pre-loaded in the database.
772
- $selected_ids = array_splice( $attachment_ids, 0, $max_query );
773
- array_walk( $selected_ids, 'intval' );
774
- */
775
  ewwwio_debug_message( 'selected items: ' . count( $attachment_ids ) );
776
  $attachments_in = implode( ',', $attachment_ids );
777
  } else {
@@ -780,9 +727,6 @@ function ewww_image_optimizer_media_scan( $hook = '' ) {
780
  die( ewwwio_json_encode( array( 'error' => esc_html__( 'List of attachment IDs not found.', 'ewww-image-optimizer' ) ) ) );
781
  }
782
 
783
- // $selected_ids = $attachment_ids; // Might just be able to change everything over to $attachment_ids.
784
- /* $failsafe_selected_ids = $selected_ids; */
785
-
786
  $attachment_meta = ewww_image_optimizer_fetch_metadata_batch( $attachments_in );
787
  $attachments_in = null;
788
 
@@ -802,7 +746,6 @@ function ewww_image_optimizer_media_scan( $hook = '' ) {
802
  if ( 0 == $attachments_processed % 5 && ( microtime( true ) - $started > apply_filters( 'ewww_image_optimizer_timeout', 22 ) || ! ewwwio_check_memory_available( 2194304 ) ) ) {
803
  ewwwio_debug_message( 'time exceeded, or memory exceeded' );
804
  ewww_image_optimizer_debug_log();
805
- /* $attachment_ids = array_merge( $failsafe_selected_ids, $attachment_ids ); */
806
  if ( defined( 'WP_CLI' ) && WP_CLI ) {
807
  if ( is_array( $optimized_list ) ) {
808
  set_transient( 'ewww_image_optimizer_low_memory_mode', 'low_memory', 600 ); // Keep us in low memory mode for up to 10 minutes.
@@ -814,7 +757,6 @@ function ewww_image_optimizer_media_scan( $hook = '' ) {
814
  }
815
  }
816
  ewww_image_optimizer_debug_log();
817
- /* array_shift( $failsafe_selected_ids ); */
818
  clearstatcache();
819
  $pending = false;
820
  $remote_file = false;
@@ -882,15 +824,15 @@ function ewww_image_optimizer_media_scan( $hook = '' ) {
882
  list( $file_path, $upload_path ) = ewww_image_optimizer_attachment_path( $meta, $selected_id, $attached_file, false );
883
 
884
  // Run a quick fix for as3cf files.
885
- if ( class_exists( 'Amazon_S3_And_CloudFront' ) && strpos( $file_path, 's3' ) === 0 ) {
886
  ewww_image_optimizer_check_table_as3cf( $meta, $selected_id, $file_path );
887
  }
888
  ewww_image_optimizer_debug_log();
889
- if ( ( strpos( $file_path, 's3' ) === 0 || ! is_file( $file_path ) ) && ( class_exists( 'WindowsAzureStorageUtil' ) || class_exists( 'Amazon_S3_And_CloudFront' ) ) ) {
890
  // Construct a $file_path and proceed IF a supported CDN plugin is installed.
891
  ewwwio_debug_message( 'Azure or S3 detected and no local file found' );
892
  $file_path = get_attached_file( $selected_id );
893
- if ( strpos( $file_path, 's3' ) === 0 ) {
894
  $file_path = get_attached_file( $selected_id, true );
895
  }
896
  ewwwio_debug_message( "remote file possible: $file_path" );
@@ -1027,7 +969,7 @@ function ewww_image_optimizer_media_scan( $hook = '' ) {
1027
  foreach ( $attachment_images as $size => $file_path ) {
1028
  ewwwio_debug_message( "here is a path $file_path" );
1029
  ewww_image_optimizer_debug_log();
1030
- if ( ! $remote_file && strpos( $file_path, 's3' ) !== 0 && ! defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE' ) ) {
1031
  $file_path = realpath( $file_path );
1032
  }
1033
  if ( empty( $file_path ) ) {
@@ -1192,7 +1134,6 @@ function ewww_image_optimizer_media_scan( $hook = '' ) {
1192
  ewwwio_debug_message( 'found bad attachment, bailing to reset the counter' );
1193
  ewww_image_optimizer_debug_log();
1194
  if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
1195
- /* $attachment_ids = array_merge( $failsafe_selected_ids, $attachment_ids ); */
1196
  break 2;
1197
  }
1198
  }
@@ -1212,32 +1153,20 @@ function ewww_image_optimizer_media_scan( $hook = '' ) {
1212
  } // End while().
1213
  ewwwio_debug_message( 'done for this request, wrapping up' );
1214
  ewww_image_optimizer_debug_log();
 
1215
  if ( ! empty( $images ) ) {
1216
  ewww_image_optimizer_mass_insert( $wpdb->ewwwio_images, $images, $field_formats );
1217
  }
1218
  ewww_image_optimizer_reset_images( $reset_images );
 
 
 
1219
  if ( 250 > $attachments_processed ) { // in-memory table is too slow.
1220
  ewwwio_debug_message( 'using in-memory table is too slow, switching to plan b' );
1221
  set_transient( 'ewww_image_optimizer_low_memory_mode', 'slow_list', 600 ); // Put it in low memory mode for at least 10 minutes.
1222
  }
1223
  ewww_image_optimizer_debug_log();
1224
 
1225
- /*
1226
- REMOVE
1227
- update_option( 'ewww_image_optimizer_scanning_attachments', $attachment_ids, false );
1228
- if ( ! empty( $queued_ids ) ) {
1229
- $attachments_queued = get_option( 'ewww_image_optimizer_bulk_attachments' );
1230
- if ( empty( $attachments_queued ) || ! is_array( $attachments_queued ) ) {
1231
- ewwwio_debug_message( 'storing queued attachments in bulk_attachments' );
1232
- ewww_image_optimizer_debug_log();
1233
- update_option( 'ewww_image_optimizer_bulk_attachments', $queued_ids, false );
1234
- } else {
1235
- ewwwio_debug_message( 'storing queued attachments in bulk_attachments, merged with existing' );
1236
- ewww_image_optimizer_debug_log();
1237
- update_option( 'ewww_image_optimizer_bulk_attachments', array_merge( $attachments_queued, $queued_ids ), false );
1238
- }
1239
- }
1240
- */
1241
  $elapsed = microtime( true ) - $started;
1242
  ewwwio_debug_message( "counting images took $elapsed seconds" );
1243
  ewwwio_memory( __FUNCTION__ );
@@ -1723,7 +1652,7 @@ function ewww_image_optimizer_bulk_loop( $hook = '', $delay = 0 ) {
1723
  global $ewww_debug;
1724
  $debug_button = esc_html__( 'Show Debug Output', 'ewww-image-optimizer' );
1725
  $debug_id = uniqid();
1726
- $output['results'] .= "<button type='button' class='ewww-show-debug-meta button button-secondary' data-id='$debug_id'>$debug_button</button><div class='ewww-debug-meta-$debug_id' style='background-color:#ffff99;display:none;'>$ewww_debug</div>";
1727
  }
1728
  if ( ! empty( $next_image->file ) ) {
1729
  $next_file = esc_html( $next_image->file );
218
  $attachment_query_count = 0;
219
  switch ( $gallery ) {
220
  case 'media':
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  return ewww_image_optimizer_count_attachments();
 
222
  break;
223
  case 'ngg':
224
  // See if we were given attachment IDs to work with via GET/POST.
245
  if ( class_exists( 'Ngg_Serializable' ) ) {
246
  $serializer = new Ngg_Serializable();
247
  $meta = $serializer->unserialize( $attachment );
248
+ } elseif ( class_exists( 'C_NextGen_Serializable' ) ) {
249
+ $meta = C_NextGen_Serializable::unserialize( $attachment );
250
  } else {
251
  $meta = unserialize( $attachment );
252
  }
369
  update_option( 'ewww_image_optimizer_bulk_resume', '' );
370
  update_option( 'ewww_image_optimizer_aux_resume', '' );
371
 
 
 
 
 
 
372
  ewww_image_optimizer_delete_queue_images();
373
  ewww_image_optimizer_delete_pending();
374
  }
380
  $resume = get_option( 'ewww_image_optimizer_bulk_resume' );
381
  $scanning = get_option( 'ewww_image_optimizer_aux_resume' );
382
  if ( ! $resume && ! $scanning ) {
 
 
 
 
 
383
  ewwwio_debug_message( 'not resuming/scanning, so clearing any pending images in both tables' );
384
  ewww_image_optimizer_delete_queue_images();
385
  ewww_image_optimizer_delete_pending();
416
  } elseif ( 'scanning' == $resume ) {
417
  ewwwio_debug_message( 'scanning, nothing doing' );
418
  // TODO: do nothing...
 
 
 
 
419
  } elseif ( $scanning || $resume ) {
420
  ewwwio_debug_message( 'resuming, nothing doing' );
421
  /* $attachments = array(); */
719
  }
720
  }
721
  if ( ! empty( $attachment_ids ) && is_array( $attachment_ids ) ) {
 
 
 
 
 
 
 
722
  ewwwio_debug_message( 'selected items: ' . count( $attachment_ids ) );
723
  $attachments_in = implode( ',', $attachment_ids );
724
  } else {
727
  die( ewwwio_json_encode( array( 'error' => esc_html__( 'List of attachment IDs not found.', 'ewww-image-optimizer' ) ) ) );
728
  }
729
 
 
 
 
730
  $attachment_meta = ewww_image_optimizer_fetch_metadata_batch( $attachments_in );
731
  $attachments_in = null;
732
 
746
  if ( 0 == $attachments_processed % 5 && ( microtime( true ) - $started > apply_filters( 'ewww_image_optimizer_timeout', 22 ) || ! ewwwio_check_memory_available( 2194304 ) ) ) {
747
  ewwwio_debug_message( 'time exceeded, or memory exceeded' );
748
  ewww_image_optimizer_debug_log();
 
749
  if ( defined( 'WP_CLI' ) && WP_CLI ) {
750
  if ( is_array( $optimized_list ) ) {
751
  set_transient( 'ewww_image_optimizer_low_memory_mode', 'low_memory', 600 ); // Keep us in low memory mode for up to 10 minutes.
757
  }
758
  }
759
  ewww_image_optimizer_debug_log();
 
760
  clearstatcache();
761
  $pending = false;
762
  $remote_file = false;
824
  list( $file_path, $upload_path ) = ewww_image_optimizer_attachment_path( $meta, $selected_id, $attached_file, false );
825
 
826
  // Run a quick fix for as3cf files.
827
+ if ( class_exists( 'Amazon_S3_And_CloudFront' ) && ewww_image_optimizer_stream_wrapped( $file_path ) ) {
828
  ewww_image_optimizer_check_table_as3cf( $meta, $selected_id, $file_path );
829
  }
830
  ewww_image_optimizer_debug_log();
831
+ if ( ( ewww_image_optimizer_stream_wrapped( $file_path ) || ! is_file( $file_path ) ) && ( class_exists( 'WindowsAzureStorageUtil' ) || class_exists( 'Amazon_S3_And_CloudFront' ) ) ) {
832
  // Construct a $file_path and proceed IF a supported CDN plugin is installed.
833
  ewwwio_debug_message( 'Azure or S3 detected and no local file found' );
834
  $file_path = get_attached_file( $selected_id );
835
+ if ( ewww_image_optimizer_stream_wrapped( $file_path ) ) {
836
  $file_path = get_attached_file( $selected_id, true );
837
  }
838
  ewwwio_debug_message( "remote file possible: $file_path" );
969
  foreach ( $attachment_images as $size => $file_path ) {
970
  ewwwio_debug_message( "here is a path $file_path" );
971
  ewww_image_optimizer_debug_log();
972
+ if ( ! $remote_file && ! ewww_image_optimizer_stream_wrapped( $file_path ) && ! defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE' ) ) {
973
  $file_path = realpath( $file_path );
974
  }
975
  if ( empty( $file_path ) ) {
1134
  ewwwio_debug_message( 'found bad attachment, bailing to reset the counter' );
1135
  ewww_image_optimizer_debug_log();
1136
  if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
 
1137
  break 2;
1138
  }
1139
  }
1153
  } // End while().
1154
  ewwwio_debug_message( 'done for this request, wrapping up' );
1155
  ewww_image_optimizer_debug_log();
1156
+
1157
  if ( ! empty( $images ) ) {
1158
  ewww_image_optimizer_mass_insert( $wpdb->ewwwio_images, $images, $field_formats );
1159
  }
1160
  ewww_image_optimizer_reset_images( $reset_images );
1161
+ ewww_image_optimizer_update_scanned_images( $queued_ids );
1162
+ ewww_image_optimizer_delete_queued_images( $skipped_ids );
1163
+
1164
  if ( 250 > $attachments_processed ) { // in-memory table is too slow.
1165
  ewwwio_debug_message( 'using in-memory table is too slow, switching to plan b' );
1166
  set_transient( 'ewww_image_optimizer_low_memory_mode', 'slow_list', 600 ); // Put it in low memory mode for at least 10 minutes.
1167
  }
1168
  ewww_image_optimizer_debug_log();
1169
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1170
  $elapsed = microtime( true ) - $started;
1171
  ewwwio_debug_message( "counting images took $elapsed seconds" );
1172
  ewwwio_memory( __FUNCTION__ );
1652
  global $ewww_debug;
1653
  $debug_button = esc_html__( 'Show Debug Output', 'ewww-image-optimizer' );
1654
  $debug_id = uniqid();
1655
+ $output['results'] .= "<button type='button' class='ewww-show-debug-meta button button-secondary' data-id='$debug_id'>$debug_button</button><div class='ewww-debug-meta-$debug_id' style='background-color:#f1f1f1;display:none;'>$ewww_debug</div>";
1656
  }
1657
  if ( ! empty( $next_image->file ) ) {
1658
  $next_file = esc_html( $next_image->file );
changelog.txt CHANGED
@@ -1,3 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = 4.6.3 =
2
  * changed: folders to ignore setting applies to resizing also
3
  * fixed: lazy load placeholders have inconsistent URLs with ExactDN
1
+ = 4.7.0 =
2
+ * added: lazy load (on ExactDN tab for now)
3
+ * added: JS WebP supports background images via lazy load (div elements only for now)
4
+ * added: ExactDN supports compression of background images (div elements only for now)
5
+ * added: compat with Google Cloud Storage via WP Offload Media
6
+ * added: automatic PNG to JPG conversion for ExactDN
7
+ * added: ExactDN parsing for legacy WooCommerce API (current API works as-is)
8
+ * changed: responsive image 'sizes' attribute can be auto-calculated by lazy load
9
+ * changed: JS WebP no longer requires jQuery
10
+ * changed: ExactDN srcset multipliers include fullscreen value of 1920px
11
+ * changed: force resize function to ignore filesize with ewww_image_optimizer_resize_filesize_ignore filter
12
+ * changed: prevent .php script/style generators from going through ExactDN
13
+ * changed: ExactDN sites can dismiss exec notice to disable local compression
14
+ * changed: automatic compression disabled during WooCommerce regen with admin notice
15
+ * changed: use wp_resource_hints filter to include ExactDN dns-prefetch earlier in the page header
16
+ * changed: gather debugging information on settings page even when debugging is not enabled yet
17
+ * fixed: Bulk Optimize scanner does not update queue in some cases
18
+ * fixed: ExactDN does not handle themes that support wide and full-screen images in block editor
19
+ * fixed: ExactDN constrains images to 640px in Twenty Nineteen theme
20
+ * fixed: ExactDN mangles Flatsome lazy load placeholder image URL
21
+ * fixed: empty attributes not recognized properly by HTML parser, resulting in broken markup
22
+ * fixed: table nav button styling broken in WP 5.1
23
+ * fixed: ExactDN applies resizing args during image_downsize() even when full/original image is too small
24
+ * fixed: animated GIF resizing breaks the use of image_resize_dimensions filter in WP_Image_Editor_GD
25
+ * fixed: NextGen bulk optimizer unable to decode meta_data
26
+
27
  = 4.6.3 =
28
  * changed: folders to ignore setting applies to resizing also
29
  * fixed: lazy load placeholders have inconsistent URLs with ExactDN
classes/class-ewww-flag.php CHANGED
@@ -77,7 +77,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
77
  * Displays the bulk optimiizer html output.
78
  */
79
  function ewww_flag_bulk() {
80
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
81
  // If there is POST data, make sure bulkaction and doaction are the values we want.
82
  if ( ! empty( $_POST ) && empty( $_REQUEST['ewww_reset'] ) ) {
83
  // If there is no requested bulk action, do nothing.
@@ -179,7 +179,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
179
  * @param string $hook The hook value for the current page.
180
  */
181
  function ewww_flag_bulk_script( $hook ) {
182
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
183
  // Make sure we are being hooked from a valid location.
184
  if ( 'flagallery_page_flag-bulk-optimize' != $hook && 'flagallery_page_flag-manage-gallery' != $hook ) {
185
  return;
@@ -269,7 +269,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
269
  * @param object $image A Flag_Image object for the new upload.
270
  */
271
  function queue_new_image( $image ) {
272
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
273
  $image_id = $image->pid;
274
  global $ewwwio_flag_background;
275
  if ( ! class_exists( 'WP_Background_Process' ) ) {
@@ -292,7 +292,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
292
  * @param object $image A Flag_Image object for the new upload.
293
  */
294
  function ewww_added_new_image( $id, $image ) {
295
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
296
  global $ewww_defer;
297
  global $ewww_image;
298
  // Make sure the image path is set.
@@ -321,7 +321,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
321
  * @param object $image A Flag_Image object for the new upload.
322
  */
323
  function ewww_added_new_image_slow( $image ) {
324
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
325
  // Make sure the image path is set.
326
  if ( isset( $image->imagePath ) ) {
327
  global $ewww_image;
@@ -361,7 +361,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
361
  * Manually process an image from the gallery.
362
  */
363
  function ewww_flag_manual() {
364
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
365
  // Make sure the current user has appropriate permissions.
366
  $permissions = apply_filters( 'ewww_image_optimizer_manual_permissions', '' );
367
  if ( false === current_user_can( $permissions ) ) {
@@ -430,7 +430,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
430
  * Restore an image from the API.
431
  */
432
  function ewww_flag_cloud_restore() {
433
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
434
  // Check permission of current user.
435
  $permissions = apply_filters( 'ewww_image_optimizer_manual_permissions', '' );
436
  if ( false === current_user_can( $permissions ) ) {
@@ -470,7 +470,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
470
  * Initialize the bulk operation.
471
  */
472
  function ewww_flag_bulk_init() {
473
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
474
  $permissions = apply_filters( 'ewww_image_optimizer_bulk_permissions', '' );
475
  if ( ! wp_verify_nonce( $_REQUEST['ewww_wpnonce'], 'ewww-image-optimizer-bulk' ) || ! current_user_can( $permissions ) ) {
476
  ewwwio_ob_clean();
@@ -509,7 +509,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
509
  * @return string|bool The name of the first image in the queue, or false.
510
  */
511
  function ewww_flag_bulk_filename( $id ) {
512
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
513
  // Need this file to work with flag meta.
514
  require_once( WP_CONTENT_DIR . '/plugins/flash-album-gallery/lib/meta.php' );
515
  // Retrieve the meta for the current ID.
@@ -527,7 +527,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
527
  * Process each image during the bulk operation.
528
  */
529
  function ewww_flag_bulk_loop() {
530
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
531
  global $ewww_defer;
532
  $ewww_defer = false;
533
  $output = array();
@@ -615,7 +615,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
615
  * Finish the bulk operation, and clear out the bulk_flag options.
616
  */
617
  function ewww_flag_bulk_cleanup() {
618
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
619
  $permissions = apply_filters( 'ewww_image_optimizer_bulk_permissions', '' );
620
  if ( ! wp_verify_nonce( $_REQUEST['ewww_wpnonce'], 'ewww-image-optimizer-bulk' ) || ! current_user_can( $permissions ) ) {
621
  ewwwio_ob_clean();
@@ -635,7 +635,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
635
  * @param string $hook The hook value for the current page.
636
  */
637
  function ewww_flag_manual_actions_script( $hook ) {
638
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
639
  if ( 'flagallery_page_flag-manage-gallery' != $hook ) {
640
  return;
641
  }
@@ -674,7 +674,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
674
  * @param int $id The ID number of the image being displayed.
675
  */
676
  function ewww_manage_image_custom_column( $id ) {
677
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
678
  $output = "<div id='ewww-flag-status-$id'>";
679
  // Get the metadata.
680
  $meta = new flagMeta( $id );
@@ -682,7 +682,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
682
  $print_meta = print_r( $meta->image->meta_data, true );
683
  $print_meta = preg_replace( array( '/ /', '/\n+/' ), array( '&nbsp;', '<br />' ), esc_html( $print_meta ) );
684
  $debug_button = esc_html__( 'Show Metadata', 'ewww-image-optimizer' );
685
- echo "<button type='button' class='ewww-show-debug-meta button button-secondary' data-id='$id'>$debug_button</button><div id='ewww-debug-meta-$id' style='background-color:#ffff99;font-size: 10px;padding: 10px;margin:3px -10px 10px;line-height: 1.1em;display: none;'>$print_meta</div>";
686
  }
687
  // Get the image path from the meta.
688
  $file_path = $meta->image->imagePath;
77
  * Displays the bulk optimiizer html output.
78
  */
79
  function ewww_flag_bulk() {
80
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
81
  // If there is POST data, make sure bulkaction and doaction are the values we want.
82
  if ( ! empty( $_POST ) && empty( $_REQUEST['ewww_reset'] ) ) {
83
  // If there is no requested bulk action, do nothing.
179
  * @param string $hook The hook value for the current page.
180
  */
181
  function ewww_flag_bulk_script( $hook ) {
182
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
183
  // Make sure we are being hooked from a valid location.
184
  if ( 'flagallery_page_flag-bulk-optimize' != $hook && 'flagallery_page_flag-manage-gallery' != $hook ) {
185
  return;
269
  * @param object $image A Flag_Image object for the new upload.
270
  */
271
  function queue_new_image( $image ) {
272
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
273
  $image_id = $image->pid;
274
  global $ewwwio_flag_background;
275
  if ( ! class_exists( 'WP_Background_Process' ) ) {
292
  * @param object $image A Flag_Image object for the new upload.
293
  */
294
  function ewww_added_new_image( $id, $image ) {
295
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
296
  global $ewww_defer;
297
  global $ewww_image;
298
  // Make sure the image path is set.
321
  * @param object $image A Flag_Image object for the new upload.
322
  */
323
  function ewww_added_new_image_slow( $image ) {
324
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
325
  // Make sure the image path is set.
326
  if ( isset( $image->imagePath ) ) {
327
  global $ewww_image;
361
  * Manually process an image from the gallery.
362
  */
363
  function ewww_flag_manual() {
364
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
365
  // Make sure the current user has appropriate permissions.
366
  $permissions = apply_filters( 'ewww_image_optimizer_manual_permissions', '' );
367
  if ( false === current_user_can( $permissions ) ) {
430
  * Restore an image from the API.
431
  */
432
  function ewww_flag_cloud_restore() {
433
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
434
  // Check permission of current user.
435
  $permissions = apply_filters( 'ewww_image_optimizer_manual_permissions', '' );
436
  if ( false === current_user_can( $permissions ) ) {
470
  * Initialize the bulk operation.
471
  */
472
  function ewww_flag_bulk_init() {
473
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
474
  $permissions = apply_filters( 'ewww_image_optimizer_bulk_permissions', '' );
475
  if ( ! wp_verify_nonce( $_REQUEST['ewww_wpnonce'], 'ewww-image-optimizer-bulk' ) || ! current_user_can( $permissions ) ) {
476
  ewwwio_ob_clean();
509
  * @return string|bool The name of the first image in the queue, or false.
510
  */
511
  function ewww_flag_bulk_filename( $id ) {
512
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
513
  // Need this file to work with flag meta.
514
  require_once( WP_CONTENT_DIR . '/plugins/flash-album-gallery/lib/meta.php' );
515
  // Retrieve the meta for the current ID.
527
  * Process each image during the bulk operation.
528
  */
529
  function ewww_flag_bulk_loop() {
530
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
531
  global $ewww_defer;
532
  $ewww_defer = false;
533
  $output = array();
615
  * Finish the bulk operation, and clear out the bulk_flag options.
616
  */
617
  function ewww_flag_bulk_cleanup() {
618
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
619
  $permissions = apply_filters( 'ewww_image_optimizer_bulk_permissions', '' );
620
  if ( ! wp_verify_nonce( $_REQUEST['ewww_wpnonce'], 'ewww-image-optimizer-bulk' ) || ! current_user_can( $permissions ) ) {
621
  ewwwio_ob_clean();
635
  * @param string $hook The hook value for the current page.
636
  */
637
  function ewww_flag_manual_actions_script( $hook ) {
638
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
639
  if ( 'flagallery_page_flag-manage-gallery' != $hook ) {
640
  return;
641
  }
674
  * @param int $id The ID number of the image being displayed.
675
  */
676
  function ewww_manage_image_custom_column( $id ) {
677
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
678
  $output = "<div id='ewww-flag-status-$id'>";
679
  // Get the metadata.
680
  $meta = new flagMeta( $id );
682
  $print_meta = print_r( $meta->image->meta_data, true );
683
  $print_meta = preg_replace( array( '/ /', '/\n+/' ), array( '&nbsp;', '<br />' ), esc_html( $print_meta ) );
684
  $debug_button = esc_html__( 'Show Metadata', 'ewww-image-optimizer' );
685
+ echo "<button type='button' class='ewww-show-debug-meta button button-secondary' data-id='$id'>$debug_button</button><div id='ewww-debug-meta-$id' style='font-size: 10px;padding: 10px;margin:3px -10px 10px;line-height: 1.1em;display: none;'>$print_meta</div>";
686
  }
687
  // Get the image path from the meta.
688
  $file_path = $meta->image->imagePath;
classes/class-ewww-image.php CHANGED
@@ -122,7 +122,7 @@ class EWWW_Image {
122
  $ewwwdb = $wpdb;
123
  }
124
  $ewwwdb->flush();
125
- if ( $path && ( is_file( $path ) || 0 === strpos( $path, 's3://' ) ) ) {
126
  ewwwio_debug_message( "creating EWWW_Image with $path" );
127
  $new_image = ewww_image_optimizer_find_already_optimized( $path );
128
  if ( ! $new_image ) {
@@ -190,7 +190,7 @@ class EWWW_Image {
190
  * @param array $meta The attachment metadata.
191
  */
192
  public function update_converted_attachment( $meta ) {
193
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
194
  $this->url = wp_get_attachment_url( $this->attachment_id );
195
  if ( ewww_image_optimizer_function_exists( 'print_r' ) ) {
196
  ewwwio_debug_message( print_r( $this, true ) );
@@ -232,7 +232,7 @@ class EWWW_Image {
232
  * @return array $meta The updated attachment metadata.
233
  */
234
  public function convert_sizes( $meta ) {
235
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
236
 
237
  global $wpdb;
238
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
@@ -401,7 +401,7 @@ class EWWW_Image {
401
  * @return array $meta The updated attachment metadata.
402
  */
403
  private function restore_sizes( $meta ) {
404
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
405
 
406
  global $wpdb;
407
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
@@ -460,7 +460,7 @@ class EWWW_Image {
460
  * @param string $file The name of the non-retina file.
461
  */
462
  private function convert_retina( $file ) {
463
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
464
  $retina_path = ewww_image_optimizer_hidpi_optimize( $file, true );
465
  if ( ! $retina_path ) {
466
  return;
@@ -482,7 +482,7 @@ class EWWW_Image {
482
  * @return string The name of the new file.
483
  */
484
  public function convert( $file, $replace_url = true, $check_size = false ) {
485
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
486
  if ( empty( $file ) ) {
487
  ewwwio_debug_message( 'no file provided to convert' );
488
  return false;
@@ -771,7 +771,7 @@ class EWWW_Image {
771
  $suffix = '-' . $filenum;
772
  }
773
  // All done, let's reconstruct the filename.
774
- ewwwio_memory( __FUNCTION__ );
775
  $this->increment = $filenum;
776
  return $filename . $suffix . $dimensions . $hidpi_suffix . $fileext;
777
  }
@@ -785,7 +785,7 @@ class EWWW_Image {
785
  * @param string $old_path Optional. The url to the old version of the image.
786
  */
787
  public function replace_url( $new_path = '', $old_path = '' ) {
788
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
789
 
790
  $new = ( empty( $new_path ) ? $this->file : $new_path );
791
  $old = ( empty( $old_path ) ? $this->converted : $old_path );
@@ -941,7 +941,7 @@ class EWWW_Image {
941
  * @return int The number of seconds expected to compress the current image.
942
  */
943
  public function time_estimate() {
944
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
945
  $time = 0;
946
  $type = ewww_image_optimizer_quick_mimetype( $this->file );
947
  $image_size = ( empty( $this->opt_size ) ? $this->orig_size : $this->opt_size );
122
  $ewwwdb = $wpdb;
123
  }
124
  $ewwwdb->flush();
125
+ if ( $path && ( is_file( $path ) || ewww_image_optimizer_stream_wrapped( $path ) ) ) {
126
  ewwwio_debug_message( "creating EWWW_Image with $path" );
127
  $new_image = ewww_image_optimizer_find_already_optimized( $path );
128
  if ( ! $new_image ) {
190
  * @param array $meta The attachment metadata.
191
  */
192
  public function update_converted_attachment( $meta ) {
193
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
194
  $this->url = wp_get_attachment_url( $this->attachment_id );
195
  if ( ewww_image_optimizer_function_exists( 'print_r' ) ) {
196
  ewwwio_debug_message( print_r( $this, true ) );
232
  * @return array $meta The updated attachment metadata.
233
  */
234
  public function convert_sizes( $meta ) {
235
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
236
 
237
  global $wpdb;
238
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
401
  * @return array $meta The updated attachment metadata.
402
  */
403
  private function restore_sizes( $meta ) {
404
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
405
 
406
  global $wpdb;
407
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
460
  * @param string $file The name of the non-retina file.
461
  */
462
  private function convert_retina( $file ) {
463
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
464
  $retina_path = ewww_image_optimizer_hidpi_optimize( $file, true );
465
  if ( ! $retina_path ) {
466
  return;
482
  * @return string The name of the new file.
483
  */
484
  public function convert( $file, $replace_url = true, $check_size = false ) {
485
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
486
  if ( empty( $file ) ) {
487
  ewwwio_debug_message( 'no file provided to convert' );
488
  return false;
771
  $suffix = '-' . $filenum;
772
  }
773
  // All done, let's reconstruct the filename.
774
+ ewwwio_memory( __METHOD__ );
775
  $this->increment = $filenum;
776
  return $filename . $suffix . $dimensions . $hidpi_suffix . $fileext;
777
  }
785
  * @param string $old_path Optional. The url to the old version of the image.
786
  */
787
  public function replace_url( $new_path = '', $old_path = '' ) {
788
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
789
 
790
  $new = ( empty( $new_path ) ? $this->file : $new_path );
791
  $old = ( empty( $old_path ) ? $this->converted : $old_path );
941
  * @return int The number of seconds expected to compress the current image.
942
  */
943
  public function time_estimate() {
944
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
945
  $time = 0;
946
  $type = ewww_image_optimizer_quick_mimetype( $this->file );
947
  $image_size = ( empty( $this->opt_size ) ? $this->orig_size : $this->opt_size );
classes/class-ewww-nextcellent.php CHANGED
@@ -132,7 +132,7 @@ if ( ! class_exists( 'EWWW_Nextcellent' ) ) {
132
  * @param string $filename The name of the file generated.
133
  */
134
  function ewww_ngg_image_save( $filename ) {
135
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
136
  global $ewww_defer;
137
  global $ewww_image;
138
  if ( file_exists( $filename ) ) {
@@ -146,7 +146,7 @@ if ( ! class_exists( 'EWWW_Nextcellent' ) ) {
146
  ewww_image_optimizer( $filename );
147
  }
148
  ewww_image_optimizer_debug_log();
149
- ewwwio_memory( __FUNCTION__ );
150
  }
151
 
152
  /**
@@ -490,7 +490,7 @@ if ( ! class_exists( 'EWWW_Nextcellent' ) ) {
490
  * @param string $hook The hook identifier for the current page.
491
  */
492
  function ewww_ngg_bulk_script( $hook ) {
493
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
494
  $i18ngg = strtolower( __( 'Galleries', 'nggallery' ) );
495
  ewwwio_debug_message( "i18n string for galleries: $i18ngg" );
496
  // Make sure we are on a legitimate page and that we have the proper POST variables if necessary.
132
  * @param string $filename The name of the file generated.
133
  */
134
  function ewww_ngg_image_save( $filename ) {
135
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
136
  global $ewww_defer;
137
  global $ewww_image;
138
  if ( file_exists( $filename ) ) {
146
  ewww_image_optimizer( $filename );
147
  }
148
  ewww_image_optimizer_debug_log();
149
+ ewwwio_memory( __METHOD__ );
150
  }
151
 
152
  /**
490
  * @param string $hook The hook identifier for the current page.
491
  */
492
  function ewww_ngg_bulk_script( $hook ) {
493
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
494
  $i18ngg = strtolower( __( 'Galleries', 'nggallery' ) );
495
  ewwwio_debug_message( "i18n string for galleries: $i18ngg" );
496
  // Make sure we are on a legitimate page and that we have the proper POST variables if necessary.
classes/class-ewww-nextgen.php CHANGED
@@ -78,7 +78,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
78
  * @return array The image sizing parameters, sanitized.
79
  */
80
  function ewww_ngg_quality_param( $params, $size ) {
81
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
82
  $settings = C_NextGen_Settings::get_instance();
83
  if ( is_array( $params ) ) {
84
  ewwwio_debug_message( 'params is an array' );
@@ -129,7 +129,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
129
  * @param object $storage A nextgen storage object for finding metadata.
130
  */
131
  function queue_new_image( $image, $storage = null ) {
132
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
133
  if ( empty( $storage ) ) {
134
  // Creating the 'registry' object for working with nextgen.
135
  $registry = C_Component_Registry::get_instance();
@@ -167,7 +167,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
167
  * @return object The image object with any modifications necessary.
168
  */
169
  function ewww_added_new_image( $image, $storage = null ) {
170
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
171
  if ( empty( $storage ) ) {
172
  // Creating the 'registry' object for working with nextgen.
173
  $registry = C_Component_Registry::get_instance();
@@ -432,7 +432,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
432
  $print_meta = print_r( $image->meta_data, true );
433
  $print_meta = preg_replace( array( '/ /', '/\n+/' ), array( '&nbsp;', '<br />' ), esc_html( $print_meta ) );
434
  $debug_button = esc_html__( 'Show Metadata', 'ewww-image-optimizer' );
435
- $output .= "<button type='button' class='ewww-show-debug-meta button button-secondary' data-id='{$image->pid}' style='background-color:#a9c524;'>$debug_button</button><div id='ewww-debug-meta-{$image->pid}' style='background-color:#ffff99;font-size: 10px;padding: 10px;margin:3px -10px 10px;line-height: 1.1em;display: none;'>$print_meta</div>";
436
  }
437
  $msg = '';
438
  // Get the absolute path.
@@ -675,7 +675,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
675
  echo '</div></div>';
676
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
677
  global $ewww_debug;
678
- echo '<p><strong>' . esc_html__( 'Debugging Information', 'ewww-image-optimizer' ) . ':</strong></p><div style="background-color:#ffff99;">' . $ewww_debug . '</div>';
679
  }
680
  return;
681
  }
@@ -703,7 +703,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
703
  * @param string $hook Identifier for the page being loaded.
704
  */
705
  function ewww_ngg_bulk_script( $hook ) {
706
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
707
  ewwwio_debug_message( $hook );
708
  /* if ( strpos( $hook, 'ewww-ngg-bulk' ) === false && strpos( $hook, 'nggallery-manage-gallery' ) === false ) { */
709
  if ( strpos( $hook, 'ewww-ngg-bulk' ) === false ) {
@@ -980,7 +980,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
980
  * Handles the bulk actions POST.
981
  */
982
  function ewww_ngg_bulk_action_handler() {
983
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
984
  // If the requested page is blank, or not a bulk_optimize, do nothing.
985
  if ( empty( $_REQUEST['page'] ) || empty( $_REQUEST['bulkaction'] ) || 'bulk_optimize' != $_REQUEST['bulkaction'] ) {
986
  return;
@@ -1010,7 +1010,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
1010
  admin_url( 'admin.php' )
1011
  )
1012
  );
1013
- ewwwio_memory( __FUNCTION__ );
1014
  exit();
1015
  }
1016
  }
@@ -1033,7 +1033,7 @@ if ( ! empty( $_REQUEST['page'] ) && 'ngg_other_options' !== $_REQUEST['page'] &
1033
  * @param bool $skip_defaults I have no idea, ask the NextGEN devs...
1034
  */
1035
  function generate_image_size( $image, $size, $params = null, $skip_defaults = false ) {
1036
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1037
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_CLOUD' ) ) {
1038
  ewww_image_optimizer_cloud_init();
1039
  }
@@ -1046,7 +1046,7 @@ if ( ! empty( $_REQUEST['page'] ) && 'ngg_other_options' !== $_REQUEST['page'] &
1046
  ewwwio_debug_message( "optimized size: $image_size" );
1047
  }
1048
  ewww_image_optimizer_debug_log();
1049
- ewwwio_memory( __FUNCTION__ );
1050
  return $success;
1051
  }
1052
  }
78
  * @return array The image sizing parameters, sanitized.
79
  */
80
  function ewww_ngg_quality_param( $params, $size ) {
81
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
82
  $settings = C_NextGen_Settings::get_instance();
83
  if ( is_array( $params ) ) {
84
  ewwwio_debug_message( 'params is an array' );
129
  * @param object $storage A nextgen storage object for finding metadata.
130
  */
131
  function queue_new_image( $image, $storage = null ) {
132
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
133
  if ( empty( $storage ) ) {
134
  // Creating the 'registry' object for working with nextgen.
135
  $registry = C_Component_Registry::get_instance();
167
  * @return object The image object with any modifications necessary.
168
  */
169
  function ewww_added_new_image( $image, $storage = null ) {
170
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
171
  if ( empty( $storage ) ) {
172
  // Creating the 'registry' object for working with nextgen.
173
  $registry = C_Component_Registry::get_instance();
432
  $print_meta = print_r( $image->meta_data, true );
433
  $print_meta = preg_replace( array( '/ /', '/\n+/' ), array( '&nbsp;', '<br />' ), esc_html( $print_meta ) );
434
  $debug_button = esc_html__( 'Show Metadata', 'ewww-image-optimizer' );
435
+ $output .= "<button type='button' class='ewww-show-debug-meta button button-secondary' data-id='{$image->pid}' style='background-color:#a9c524;'>$debug_button</button><div id='ewww-debug-meta-{$image->pid}' style='font-size: 10px;padding: 10px;margin:3px -10px 10px;line-height: 1.1em;display: none;'>$print_meta</div>";
436
  }
437
  $msg = '';
438
  // Get the absolute path.
675
  echo '</div></div>';
676
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
677
  global $ewww_debug;
678
+ echo '<p><strong>' . esc_html__( 'Debugging Information', 'ewww-image-optimizer' ) . ':</strong></p><div style="border:1px solid #e5e5e5;background:#fff;overflow:auto;height:300px;width:800px;">' . $ewww_debug . '</div>';
679
  }
680
  return;
681
  }
703
  * @param string $hook Identifier for the page being loaded.
704
  */
705
  function ewww_ngg_bulk_script( $hook ) {
706
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
707
  ewwwio_debug_message( $hook );
708
  /* if ( strpos( $hook, 'ewww-ngg-bulk' ) === false && strpos( $hook, 'nggallery-manage-gallery' ) === false ) { */
709
  if ( strpos( $hook, 'ewww-ngg-bulk' ) === false ) {
980
  * Handles the bulk actions POST.
981
  */
982
  function ewww_ngg_bulk_action_handler() {
983
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
984
  // If the requested page is blank, or not a bulk_optimize, do nothing.
985
  if ( empty( $_REQUEST['page'] ) || empty( $_REQUEST['bulkaction'] ) || 'bulk_optimize' != $_REQUEST['bulkaction'] ) {
986
  return;
1010
  admin_url( 'admin.php' )
1011
  )
1012
  );
1013
+ ewwwio_memory( __METHOD__ );
1014
  exit();
1015
  }
1016
  }
1033
  * @param bool $skip_defaults I have no idea, ask the NextGEN devs...
1034
  */
1035
  function generate_image_size( $image, $size, $params = null, $skip_defaults = false ) {
1036
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
1037
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_CLOUD' ) ) {
1038
  ewww_image_optimizer_cloud_init();
1039
  }
1046
  ewwwio_debug_message( "optimized size: $image_size" );
1047
  }
1048
  ewww_image_optimizer_debug_log();
1049
+ ewwwio_memory( __METHOD__ );
1050
  return $success;
1051
  }
1052
  }
classes/class-ewwwio-alt-webp.php CHANGED
@@ -21,7 +21,7 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
21
  * @access private
22
  * @var string $inline_script
23
  */
24
- private $inline_script = 'var Arrive=function(c,e,w){"use strict";if(c.MutationObserver&&"undefined"!=typeof HTMLElement){var a,t,r=0,d=(a=HTMLElement.prototype.matches||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector,{matchesSelector:function(e,t){return e instanceof HTMLElement&&a.call(e,t)},addMethod:function(e,t,a){var r=e[t];e[t]=function(){return a.length==arguments.length?a.apply(this,arguments):"function"==typeof r?r.apply(this,arguments):void 0}},callCallbacks:function(e,t){t&&t.options.onceOnly&&1==t.firedElems.length&&(e=[e[0]]);for(var a,r=0;a=e[r];r++)a&&a.callback&&a.callback.call(a.elem,a.elem);t&&t.options.onceOnly&&1==t.firedElems.length&&t.me.unbindEventWithSelectorAndCallback.call(t.target,t.selector,t.callback)},checkChildNodesRecursively:function(e,t,a,r){for(var i,n=0;i=e[n];n++)a(i,t,r)&&r.push({callback:t.callback,elem:i}),0<i.childNodes.length&&d.checkChildNodesRecursively(i.childNodes,t,a,r)},mergeArrays:function(e,t){var a,r={};for(a in e)e.hasOwnProperty(a)&&(r[a]=e[a]);for(a in t)t.hasOwnProperty(a)&&(r[a]=t[a]);return r},toElementsArray:function(e){return void 0===e||"number"==typeof e.length&&e!==c||(e=[e]),e}}),u=((t=function(){this._eventsBucket=[],this._beforeAdding=null,this._beforeRemoving=null}).prototype.addEvent=function(e,t,a,r){var i={target:e,selector:t,options:a,callback:r,firedElems:[]};return this._beforeAdding&&this._beforeAdding(i),this._eventsBucket.push(i),i},t.prototype.removeEvent=function(e){for(var t,a=this._eventsBucket.length-1;t=this._eventsBucket[a];a--)if(e(t)){this._beforeRemoving&&this._beforeRemoving(t);var r=this._eventsBucket.splice(a,1);r&&r.length&&(r[0].callback=null)}},t.prototype.beforeAdding=function(e){this._beforeAdding=e},t.prototype.beforeRemoving=function(e){this._beforeRemoving=e},t),l=function(i,n){var l=new u,s=this,o={fireOnAttributesModification:!1};return l.beforeAdding(function(t){var e,a=t.target;a!==c.document&&a!==c||(a=document.getElementsByTagName("html")[0]),e=new MutationObserver(function(e){n.call(this,e,t)});var r=i(t.options);e.observe(a,r),t.observer=e,t.me=s}),l.beforeRemoving(function(e){e.observer.disconnect()}),this.bindEvent=function(e,t,a){t=d.mergeArrays(o,t);for(var r=d.toElementsArray(this),i=0;i<r.length;i++)l.addEvent(r[i],e,t,a)},this.unbindEvent=function(){var a=d.toElementsArray(this);l.removeEvent(function(e){for(var t=0;t<a.length;t++)if(this===w||e.target===a[t])return!0;return!1})},this.unbindEventWithSelectorOrCallback=function(a){var e,r=d.toElementsArray(this),i=a;e="function"==typeof a?function(e){for(var t=0;t<r.length;t++)if((this===w||e.target===r[t])&&e.callback===i)return!0;return!1}:function(e){for(var t=0;t<r.length;t++)if((this===w||e.target===r[t])&&e.selector===a)return!0;return!1},l.removeEvent(e)},this.unbindEventWithSelectorAndCallback=function(a,r){var i=d.toElementsArray(this);l.removeEvent(function(e){for(var t=0;t<i.length;t++)if((this===w||e.target===i[t])&&e.selector===a&&e.callback===r)return!0;return!1})},this},i=new function(){var o={fireOnAttributesModification:!1,onceOnly:!1,existing:!1};function n(e,t,a){return!(!d.matchesSelector(e,t.selector)||(e._id===w&&(e._id=r++),-1!=t.firedElems.indexOf(e._id))||(t.firedElems.push(e._id),0))}var c=(i=new l(function(e){var t={attributes:!1,childList:!0,subtree:!0};return e.fireOnAttributesModification&&(t.attributes=!0),t},function(e,i){e.forEach(function(e){var t=e.addedNodes,a=e.target,r=[];null!==t&&0<t.length?d.checkChildNodesRecursively(t,i,n,r):"attributes"===e.type&&n(a,i)&&r.push({callback:i.callback,elem:a}),d.callCallbacks(r,i)})})).bindEvent;return i.bindEvent=function(e,t,a){void 0===a?(a=t,t=o):t=d.mergeArrays(o,t);var r=d.toElementsArray(this);if(t.existing){for(var i=[],n=0;n<r.length;n++)for(var l=r[n].querySelectorAll(e),s=0;s<l.length;s++)i.push({callback:a,elem:l[s]});if(t.onceOnly&&i.length)return a.call(i[0].elem,i[0].elem);setTimeout(d.callCallbacks,1,i)}c.call(this,e,t,a)},i},s=new function(){var r={};function i(e,t){return d.matchesSelector(e,t.selector)}var n=(s=new l(function(){return{childList:!0,subtree:!0}},function(e,r){e.forEach(function(e){var t=e.removedNodes,a=[];null!==t&&0<t.length&&d.checkChildNodesRecursively(t,r,i,a),d.callCallbacks(a,r)})})).bindEvent;return s.bindEvent=function(e,t,a){void 0===a?(a=t,t=r):t=d.mergeArrays(r,t),n.call(this,e,t,a)},s};e&&h(e.fn),h(HTMLElement.prototype),h(NodeList.prototype),h(HTMLCollection.prototype),h(HTMLDocument.prototype),h(Window.prototype);var n={};return o(i,n,"unbindAllArrive"),o(s,n,"unbindAllLeave"),n}function o(e,t,a){d.addMethod(t,a,e.unbindEvent),d.addMethod(t,a,e.unbindEventWithSelectorOrCallback),d.addMethod(t,a,e.unbindEventWithSelectorAndCallback)}function h(e){e.arrive=i.bindEvent,o(i,e,"unbindArrive"),e.leave=s.bindEvent,o(s,e,"unbindLeave")}}(window,"undefined"==typeof jQuery?null:jQuery,void 0);function check_webp_feature(e,t){var a=new Image;a.onload=function(){var e=0<a.width&&0<a.height;t(e)},a.onerror=function(){t(!1)},a.src="data:image/webp;base64,"+{alpha:"UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",animation:"UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"}[e]}function ewww_load_images(t){!function(n){n.fn.extend({ewwwattr:function(e,t){return void 0!==t&&!1!==t&&this.attr(e,t),this}});t&&(n(".batch-image img, .image-wrapper a, .ngg-pro-masonry-item a, .ngg-galleria-offscreen-seo-wrapper a").each(function(){n(this).ewwwattr("data-src",n(this).attr("data-webp")),n(this).ewwwattr("data-thumbnail",n(this).attr("data-webp-thumbnail"))}),n(".image-wrapper a, .ngg-pro-masonry-item a").each(function(){n(this).ewwwattr("href",n(this).attr("data-webp"))}),n(".rev_slider ul li").each(function(){n(this).ewwwattr("data-thumb",n(this).attr("data-webp-thumb"));for(var e=1;e<11;)n(this).ewwwattr("data-param"+e,n(this).attr("data-webp-param"+e)),e++}),n(".rev_slider img").each(function(){n(this).ewwwattr("data-lazyload",n(this).attr("data-webp-lazyload"))}),n("div.woocommerce-product-gallery__image").each(function(){n(this).ewwwattr("data-thumb",n(this).attr("data-webp-thumb"))})),n("video").each(function(){t?n(this).ewwwattr("poster",n(this).attr("data-poster-webp")):n(this).ewwwattr("poster",n(this).attr("data-poster-image"))}),n("img.ewww_webp_lazy_load").each(function(){if(t){n(this).ewwwattr("data-lazy-srcset",n(this).attr("data-lazy-srcset-webp")),n(this).ewwwattr("data-srcset",n(this).attr("data-srcset-webp")),n(this).ewwwattr("data-lazy-src",n(this).attr("data-lazy-src-webp")),n(this).ewwwattr("data-src",n(this).attr("data-src-webp")),n(this).ewwwattr("data-orig-file",n(this).attr("data-webp-orig-file")),n(this).ewwwattr("data-medium-file",n(this).attr("data-webp-medium-file")),n(this).ewwwattr("data-large-file",n(this).attr("data-webp-large-file"));var e=n(this).attr("srcset");void 0!==e&&!1!==e&&e.includes("R0lGOD")&&n(this).ewwwattr("src",n(this).attr("data-lazy-src-webp"))}n(this).removeClass("ewww_webp_lazy_load")}),n(".ewww_webp").each(function(){var e=document.createElement("img");t?(n(e).ewwwattr("src",n(this).attr("data-webp")),n(e).ewwwattr("srcset",n(this).attr("data-srcset-webp")),n(e).ewwwattr("data-orig-file",n(this).attr("data-orig-file")),n(e).ewwwattr("data-orig-file",n(this).attr("data-webp-orig-file")),n(e).ewwwattr("data-medium-file",n(this).attr("data-medium-file")),n(e).ewwwattr("data-medium-file",n(this).attr("data-webp-medium-file")),n(e).ewwwattr("data-large-file",n(this).attr("data-large-file")),n(e).ewwwattr("data-large-file",n(this).attr("data-webp-large-file")),n(e).ewwwattr("data-large_image",n(this).attr("data-large_image")),n(e).ewwwattr("data-large_image",n(this).attr("data-webp-large_image")),n(e).ewwwattr("data-src",n(this).attr("data-src")),n(e).ewwwattr("data-src",n(this).attr("data-webp-src"))):(n(e).ewwwattr("src",n(this).attr("data-img")),n(e).ewwwattr("srcset",n(this).attr("data-srcset-img")),n(e).ewwwattr("data-orig-file",n(this).attr("data-orig-file")),n(e).ewwwattr("data-medium-file",n(this).attr("data-medium-file")),n(e).ewwwattr("data-large-file",n(this).attr("data-large-file")),n(e).ewwwattr("data-large_image",n(this).attr("data-large_image")),n(e).ewwwattr("data-src",n(this).attr("data-src"))),e=function(e,t){for(var a=["align","alt","border","crossorigin","height","hspace","ismap","longdesc","usemap","vspace","width","accesskey","class","contenteditable","contextmenu","dir","draggable","dropzone","hidden","id","lang","spellcheck","style","tabindex","title","translate","sizes","data-caption","data-attachment-id","data-permalink","data-orig-size","data-comments-opened","data-image-meta","data-image-title","data-image-description","data-event-trigger","data-highlight-color","data-highlight-opacity","data-highlight-border-color","data-highlight-border-width","data-highlight-border-opacity","data-no-lazy","data-lazy","data-large_image_width","data-large_image_height"],r=0,i=a.length;r<i;r++)n(t).ewwwattr(a[r],n(e).attr("data-"+a[r]));return t}(this,e),n(this).after(e),n(this).removeClass("ewww_webp")})}(jQuery),jQuery.fn.isotope&&jQuery.fn.imagesLoaded&&(jQuery(".fusion-posts-container-infinite").imagesLoaded(function(){jQuery(".fusion-posts-container-infinite").hasClass("isotope")&&jQuery(".fusion-posts-container-infinite").isotope()}),jQuery(".fusion-portfolio:not(.fusion-recent-works) .fusion-portfolio-wrapper").imagesLoaded(function(){jQuery(".fusion-portfolio:not(.fusion-recent-works) .fusion-portfolio-wrapper").isotope()}))}var ewww_jquery_waiting_timer=0;function ewww_ngg_plus_parse_galleries(e){e&&jQuery.each(galleries,function(e,t){galleries[e].images_list=ewww_ngg_plus_parse_image_list(t.images_list)})}function ewww_ngg_plus_load_galleries(e){var i;e&&((i=jQuery)(window).on("ngg.galleria.themeadded",function(e,t){window.ngg_galleria._create_backup=window.ngg_galleria.create,window.ngg_galleria.create=function(e,t){var a=i(e).data("id");return galleries["gallery_"+a].images_list=ewww_ngg_plus_parse_image_list(galleries["gallery_"+a].images_list),window.ngg_galleria._create_backup(e,t)}}),i(window).on("override_nplModal_methods",function(e,r){r._set_events_backup=r.set_events,r.set_events=function(){return i("#npl_content").bind("npl_images_ready",function(e,t){var a=r.fetch_images.gallery_image_cache[t];a=ewww_ngg_plus_parse_image_list(a)}),r._set_events_backup()}}))}function ewww_ngg_plus_parse_image_list(i){var e;return(e=jQuery).each(i,function(a,r){void 0!==r["image-webp"]&&(i[a].image=r["image-webp"],delete i[a]["image-webp"]),void 0!==r["thumb-webp"]&&(i[a].thumb=r["thumb-webp"],delete i[a]["thumb-webp"]),void 0!==r.full_image_webp&&(i[a].full_image=r.full_image_webp,delete i[a].full_image_webp),void 0!==r.srcsets&&e.each(r.srcsets,function(e,t){void 0!==r.srcsets[e+"-webp"]&&(i[a].srcsets[e]=r.srcsets[e+"-webp"],delete i[a].srcsets[e+"-webp"])}),void 0!==r.full_srcsets&&e.each(r.full_srcsets,function(e,t){void 0!==r.full_srcsets[e+"-webp"]&&(i[a].full_srcsets[e]=r.full_srcsets[e+"-webp"],delete i[a].full_srcsets[e+"-webp"])})}),i}ewww_jquery_waiting=setInterval(function(){if(window.jQuery){check_webp_feature("alpha",ewww_load_images),check_webp_feature("alpha",ewww_ngg_plus_load_galleries),document.arrive(".ewww_webp",function(){check_webp_feature("alpha",ewww_load_images)});var e=0,t=setInterval(function(){"undefined"!=typeof galleries&&(check_webp_feature("alpha",ewww_ngg_plus_parse_galleries),clearInterval(t)),1e3<(e+=25)&&clearInterval(t)},25);clearInterval(ewww_jquery_waiting)}1e4<(ewww_jquery_waiting_timer+=100)&&clearInterval(ewww_jquery_waiting)},100);';
25
 
26
  /**
27
  * Indicates if we are filtering ExactDN urls.
@@ -51,10 +51,14 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
51
  return false;
52
  }
53
  // Start an output buffer before any output starts.
54
- add_action( 'template_redirect', array( $this, 'buffer_start' ), 0 );
 
55
  // Filter for NextGEN image urls within JS.
56
  add_filter( 'ngg_pro_lightbox_images_queue', array( $this, 'ngg_pro_lightbox_images_queue' ), 11 );
57
 
 
 
 
58
  $this->home_url = trailingslashit( get_site_url() );
59
  ewwwio_debug_message( "home url: $this->home_url" );
60
  $this->relative_home_url = preg_replace( '/https?:/', '', $this->home_url );
@@ -82,12 +86,7 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
82
  // Load the minified, non-inline version of the webp rewrite script.
83
  add_action( 'wp_enqueue_scripts', array( $this, 'min_external_script' ) );
84
  } else {
85
- // Loads jQuery and the minified inline webp rewrite script.
86
- if ( function_exists( 'wp_add_inline_script' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_inline_fallback' ) ) {
87
- add_action( 'wp_enqueue_scripts', array( $this, 'load_jquery' ) );
88
- } else {
89
- add_action( 'wp_head', array( $this, 'inline_script' ) );
90
- }
91
  }
92
  }
93
 
@@ -284,35 +283,55 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
284
  * @return string The altered buffer containing the full page with WebP images inserted.
285
  */
286
  function filter_page_output( $buffer ) {
287
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
288
- // If this is an admin page, don't filter it.
289
- if ( ( empty( $buffer ) || is_admin() ) ) {
290
- return $buffer;
291
- }
292
- // If Cache Enabler's WebP option is enabled, don't filter it.
293
- if ( ewww_image_optimizer_ce_webp_enabled() ) {
294
- return $buffer;
295
- }
296
  $uri = $_SERVER['REQUEST_URI'];
297
- // Based on the uri, if this is a cornerstone editing page, don't filter the response.
298
- if ( ! empty( $_GET['cornerstone'] ) || strpos( $uri, 'cornerstone-endpoint' ) !== false ) {
299
- return $buffer;
300
- }
301
- if ( ! empty( $_GET['et_fb'] ) ) {
302
- return $buffer;
303
- }
304
- if ( ! empty( $_GET['tatsu'] ) ) {
305
- return $buffer;
306
- }
307
- if ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === $_POST['action'] ) {
308
- return $buffer;
309
- }
310
- // If this is XML (not XHTML), don't modify the page.
311
- if ( preg_match( '/<\?xml/', $buffer ) ) {
312
- return $buffer;
313
- }
314
- if ( strpos( $buffer, 'amp-boilerplate' ) ) {
315
- ewwwio_debug_message( 'AMP page processing' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
  return $buffer;
317
  }
318
 
@@ -344,7 +363,7 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
344
  $buffer = str_replace( $image, $new_image, $buffer );
345
  }
346
  } elseif ( $this->validate_image_url( $file ) && false === strpos( $image, 'lazyload' ) ) {
347
- // If a CDN path match was found, or .webp image existsence is confirmed, and this is not a lazy-load 'dummy' image.
348
  ewwwio_debug_message( 'found a webp image or forced path' );
349
  $nscript = '<noscript>';
350
  $this->set_attribute( $nscript, 'data-img', $file );
@@ -387,7 +406,7 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
387
  $this->set_attribute( $new_image, 'class', $this->get_attribute( $new_image, 'class' ) . ' ewww_webp_lazy_load', true );
388
  $buffer = str_replace( $image, $new_image, $buffer );
389
  }
390
- } elseif ( ! empty( $file ) && strpos( $image, 'data-src=' ) && strpos( $image, 'data-lazy-type="image' ) ) {
391
  // a3 Lazy Load.
392
  $new_image = $image;
393
  $real_file = $this->get_attribute( $new_image, 'data-src' );
@@ -407,6 +426,20 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
407
  $this->set_attribute( $new_image, 'class', $this->get_attribute( $new_image, 'class' ) . ' ewww_webp_lazy_load', true );
408
  $buffer = str_replace( $image, $new_image, $buffer );
409
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  }
411
  // Rev Slider data-lazyload attribute on image elements.
412
  if ( $this->get_attribute( $image, 'data-lazyload' ) ) {
@@ -422,6 +455,38 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
422
  }
423
  } // End foreach().
424
  } // End if().
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
  // Look for images to parse WP Retina Lazy Load.
426
  if ( class_exists( 'Meow_WR2X_Core' ) && strpos( $buffer, ' lazyload' ) ) {
427
  $images = $this->get_elements_from_html( $buffer, 'img' );
@@ -454,7 +519,11 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
454
  if ( ewww_image_optimizer_iterable( $sources ) ) {
455
  foreach ( $sources as $source ) {
456
  ewwwio_debug_message( "parsing a picture source: $source" );
457
- $srcset = $this->get_attribute( $source, 'srcset' );
 
 
 
 
458
  if ( $srcset ) {
459
  $srcset_webp = $this->srcset_replace( $srcset );
460
  if ( $srcset_webp ) {
@@ -539,7 +608,16 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
539
  ewwwio_debug_message( "checking webp for WC data-thumb: $thumb" );
540
  if ( $this->validate_image_url( $thumb ) ) {
541
  $this->set_attribute( $div, 'data-webp-thumb', $this->generate_url( $thumb ) );
542
- ewwwio_debug_message( "found webp for WC data-thumb: $thumb" );
 
 
 
 
 
 
 
 
 
543
  $buffer = str_replace( $divs[ $index ], $div, $buffer );
544
  }
545
  }
@@ -577,7 +655,7 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
577
  * @return array The array of images with WebP versions added.
578
  */
579
  function ngg_pro_lightbox_images_queue( $images ) {
580
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
581
  if ( ewww_image_optimizer_iterable( $images ) ) {
582
  foreach ( $images as $index => $image ) {
583
  if ( ! empty( $image['image'] ) && $this->validate_image_url( $image['image'] ) ) {
@@ -616,7 +694,11 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
616
  */
617
  function validate_image_url( $image ) {
618
  ewwwio_debug_message( "webp validation for $image" );
619
- if ( strpos( $image, 'assets/images/dummy.png' ) || strpos( $image, 'base64,R0lGOD' ) || strpos( $image, 'lazy-load/images/1x1' ) || strpos( $image, 'assets/images/transparent.png' ) || strpos( $image, 'assets/images/lazy' ) ) {
 
 
 
 
620
  ewwwio_debug_message( 'lazy load placeholder' );
621
  return false;
622
  }
@@ -672,7 +754,7 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
672
  */
673
  function debug_script() {
674
  if ( ! ewww_image_optimizer_ce_webp_enabled() ) {
675
- wp_enqueue_script( 'ewww-webp-load-script', plugins_url( '/includes/load_webp.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array( 'jquery' ), EWWW_IMAGE_OPTIMIZER_VERSION );
676
  }
677
  }
678
 
@@ -681,19 +763,8 @@ class EWWWIO_Alt_Webp extends EWWWIO_Page_Parser {
681
  */
682
  function min_external_script() {
683
  if ( ! ewww_image_optimizer_ce_webp_enabled() ) {
684
- wp_enqueue_script( 'ewww-webp-load-script', plugins_url( '/includes/load_webp.min.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array( 'jquery' ), EWWW_IMAGE_OPTIMIZER_VERSION );
685
- }
686
- }
687
-
688
- /**
689
- * Enqueue script dependency for alt webp rewriting when running inline.
690
- */
691
- function load_jquery() {
692
- if ( ! wp_script_is( 'jquery', 'done' ) ) {
693
- wp_enqueue_script( 'jquery' );
694
  }
695
- ewwwio_debug_message( 'loading webp script with wp_add_inline_script' );
696
- wp_add_inline_script( 'jquery-core', $this->inline_script );
697
  }
698
 
699
  /**
21
  * @access private
22
  * @var string $inline_script
23
  */
24
+ private $inline_script = '';
25
 
26
  /**
27
  * Indicates if we are filtering ExactDN urls.
51
  return false;
52
  }
53
  // Start an output buffer before any output starts.
54
+ /* add_action( 'template_redirect', array( $this, 'buffer_start' ), 0 ); */
55
+ add_filter( 'ewww_image_optimizer_filter_page_output', array( $this, 'filter_page_output' ), 20 );
56
  // Filter for NextGEN image urls within JS.
57
  add_filter( 'ngg_pro_lightbox_images_queue', array( $this, 'ngg_pro_lightbox_images_queue' ), 11 );
58
 
59
+ // Load up the minified script so we can inline it.
60
+ $this->inline_script = file_get_contents( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'includes/load_webp.min.js' );
61
+
62
  $this->home_url = trailingslashit( get_site_url() );
63
  ewwwio_debug_message( "home url: $this->home_url" );
64
  $this->relative_home_url = preg_replace( '/https?:/', '', $this->home_url );
86
  // Load the minified, non-inline version of the webp rewrite script.
87
  add_action( 'wp_enqueue_scripts', array( $this, 'min_external_script' ) );
88
  } else {
89
+ add_action( 'wp_head', array( $this, 'inline_script' ) );
 
 
 
 
 
90
  }
91
  }
92
 
283
  * @return string The altered buffer containing the full page with WebP images inserted.
284
  */
285
  function filter_page_output( $buffer ) {
286
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
287
+ // If any of this is true, don't filter the page.
 
 
 
 
 
 
 
288
  $uri = $_SERVER['REQUEST_URI'];
289
+ if (
290
+ empty( $buffer ) ||
291
+ is_admin() ||
292
+ ! empty( $_GET['cornerstone'] ) ||
293
+ strpos( $uri, 'cornerstone-endpoint' ) !== false ||
294
+ ! empty( $_GET['et_fb'] ) ||
295
+ ! empty( $_GET['tatsu'] ) ||
296
+ ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === $_POST['action'] ) ||
297
+ is_feed() ||
298
+ is_preview() ||
299
+ ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ||
300
+ preg_match( '/<\?xml/', $buffer )
301
+ ) {
302
+ if ( empty( $buffer ) ) {
303
+ ewwwio_debug_message( 'empty buffer' );
304
+ }
305
+ if ( is_admin() ) {
306
+ ewwwio_debug_message( 'is_admin' );
307
+ }
308
+ if ( ! empty( $_GET['cornerstone'] ) || strpos( $uri, 'cornerstone-endpoint' ) !== false ) {
309
+ ewwwio_debug_message( 'cornerstone editor' );
310
+ }
311
+ if ( ! empty( $_GET['et_fb'] ) ) {
312
+ ewwwio_debug_message( 'et_fb' );
313
+ }
314
+ if ( ! empty( $_GET['tatsu'] ) || ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === $_POST['action'] ) ) {
315
+ ewwwio_debug_message( 'tatsu' );
316
+ }
317
+ if ( is_feed() ) {
318
+ ewwwio_debug_message( 'is_feed' );
319
+ }
320
+ if ( is_preview() ) {
321
+ ewwwio_debug_message( 'is_preview' );
322
+ }
323
+ if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
324
+ ewwwio_debug_message( 'rest request' );
325
+ }
326
+ if ( preg_match( '/<\?xml/', $buffer ) ) {
327
+ ewwwio_debug_message( 'not html, xml tag found' );
328
+ }
329
+ if ( strpos( $buffer, 'amp-boilerplate' ) ) {
330
+ ewwwio_debug_message( 'AMP page processing' );
331
+ }
332
+ if ( ewww_image_optimizer_ce_webp_enabled() ) {
333
+ ewwwio_debug_message( 'Cache Enabler WebP enabled' );
334
+ }
335
  return $buffer;
336
  }
337
 
363
  $buffer = str_replace( $image, $new_image, $buffer );
364
  }
365
  } elseif ( $this->validate_image_url( $file ) && false === strpos( $image, 'lazyload' ) ) {
366
+ // If a CDN path match was found, or .webp image existence is confirmed, and this is not a lazy-load 'dummy' image.
367
  ewwwio_debug_message( 'found a webp image or forced path' );
368
  $nscript = '<noscript>';
369
  $this->set_attribute( $nscript, 'data-img', $file );
406
  $this->set_attribute( $new_image, 'class', $this->get_attribute( $new_image, 'class' ) . ' ewww_webp_lazy_load', true );
407
  $buffer = str_replace( $image, $new_image, $buffer );
408
  }
409
+ } elseif ( ! empty( $file ) && strpos( $image, 'data-src=' ) && ( strpos( $image, 'data-lazy-type="image' ) || strpos( $image, 'lazyload' ) ) ) {
410
  // a3 Lazy Load.
411
  $new_image = $image;
412
  $real_file = $this->get_attribute( $new_image, 'data-src' );
426
  $this->set_attribute( $new_image, 'class', $this->get_attribute( $new_image, 'class' ) . ' ewww_webp_lazy_load', true );
427
  $buffer = str_replace( $image, $new_image, $buffer );
428
  }
429
+ } elseif ( ! empty( $file ) && strpos( $image, 'data-lazysrc=' ) && strpos( $image, '/essential-grid' ) ) {
430
+ // Essential Grid.
431
+ $new_image = $image;
432
+ $real_file = $this->get_attribute( $new_image, 'data-lazysrc' );
433
+ ewwwio_debug_message( "checking webp for EG Lazy Load data-lazysrc: $real_file" );
434
+ if ( $this->validate_image_url( $real_file ) ) {
435
+ ewwwio_debug_message( "found webp for Lazy Load: $real_file" );
436
+ $this->set_attribute( $new_image, 'data-lazysrc-webp', $this->generate_url( $real_file ) );
437
+ }
438
+ // TODO: should we be using the class, or will that be moot point?
439
+ if ( $new_image !== $image ) {
440
+ $this->set_attribute( $new_image, 'class', $this->get_attribute( $new_image, 'class' ) . ' ewww_webp_lazy_load', true );
441
+ $buffer = str_replace( $image, $new_image, $buffer );
442
+ }
443
  }
444
  // Rev Slider data-lazyload attribute on image elements.
445
  if ( $this->get_attribute( $image, 'data-lazyload' ) ) {
455
  }
456
  } // End foreach().
457
  } // End if().
458
+ // Now we will look for any lazy images that don't have a src attribute (this search returns ALL img elements though).
459
+ $images = $this->get_images_from_html( preg_replace( '/<noscript.*?\/noscript>/', '', $buffer ), false, false );
460
+ if ( ewww_image_optimizer_iterable( $images[0] ) ) {
461
+ ewwwio_debug_message( 'parsing images without requiring src' );
462
+ foreach ( $images[0] as $index => $image ) {
463
+ if ( $this->get_attribute( $image, 'src' ) ) {
464
+ continue;
465
+ }
466
+ ewwwio_debug_message( 'found img without src' );
467
+ if ( strpos( $image, 'data-src=' ) && strpos( $image, 'data-srcset=' ) && strpos( $image, 'lazyload' ) ) {
468
+ // EWWW IO Lazy Load.
469
+ $new_image = $image;
470
+ $real_file = $this->get_attribute( $new_image, 'data-src' );
471
+ ewwwio_debug_message( "checking webp for Lazy Load data-src: $real_file" );
472
+ if ( $this->validate_image_url( $real_file ) ) {
473
+ ewwwio_debug_message( 'found webp for Lazy Load' );
474
+ $this->set_attribute( $new_image, 'data-src-webp', $this->generate_url( $real_file ) );
475
+ }
476
+ $srcset = $this->get_attribute( $new_image, 'data-srcset' );
477
+ if ( $srcset ) {
478
+ $srcset_webp = $this->srcset_replace( $srcset );
479
+ if ( $srcset_webp ) {
480
+ $this->set_attribute( $new_image, 'data-srcset-webp', $srcset_webp );
481
+ }
482
+ }
483
+ if ( $new_image !== $image ) {
484
+ $this->set_attribute( $new_image, 'class', $this->get_attribute( $new_image, 'class' ) . ' ewww_webp_lazy_load', true );
485
+ $buffer = str_replace( $image, $new_image, $buffer );
486
+ }
487
+ }
488
+ } // End foreach().
489
+ } // End if().
490
  // Look for images to parse WP Retina Lazy Load.
491
  if ( class_exists( 'Meow_WR2X_Core' ) && strpos( $buffer, ' lazyload' ) ) {
492
  $images = $this->get_elements_from_html( $buffer, 'img' );
519
  if ( ewww_image_optimizer_iterable( $sources ) ) {
520
  foreach ( $sources as $source ) {
521
  ewwwio_debug_message( "parsing a picture source: $source" );
522
+ $srcset_attr_name = 'srcset';
523
+ if ( false !== strpos( $source, 'base64,R0lGOD' ) && false !== strpos( $source, 'data-srcset=' ) ) {
524
+ $srcset_attr_name = 'data-srcset';
525
+ }
526
+ $srcset = $this->get_attribute( $source, $srcset_attr_name );
527
  if ( $srcset ) {
528
  $srcset_webp = $this->srcset_replace( $srcset );
529
  if ( $srcset_webp ) {
608
  ewwwio_debug_message( "checking webp for WC data-thumb: $thumb" );
609
  if ( $this->validate_image_url( $thumb ) ) {
610
  $this->set_attribute( $div, 'data-webp-thumb', $this->generate_url( $thumb ) );
611
+ ewwwio_debug_message( 'found webp for WC data-thumb' );
612
+ $buffer = str_replace( $divs[ $index ], $div, $buffer );
613
+ }
614
+ }
615
+ $bg_image = $this->get_attribute( $div, 'data-bg' );
616
+ if ( $div_class && $bg_image && false !== strpos( $div_class, 'lazyload' ) ) {
617
+ ewwwio_debug_message( "checking webp for LL data-bg: $bg_image" );
618
+ if ( $this->validate_image_url( $bg_image ) ) {
619
+ $this->set_attribute( $div, 'data-bg-webp', $this->generate_url( $bg_image ) );
620
+ ewwwio_debug_message( 'found webp for LL data-bg' );
621
  $buffer = str_replace( $divs[ $index ], $div, $buffer );
622
  }
623
  }
655
  * @return array The array of images with WebP versions added.
656
  */
657
  function ngg_pro_lightbox_images_queue( $images ) {
658
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
659
  if ( ewww_image_optimizer_iterable( $images ) ) {
660
  foreach ( $images as $index => $image ) {
661
  if ( ! empty( $image['image'] ) && $this->validate_image_url( $image['image'] ) ) {
694
  */
695
  function validate_image_url( $image ) {
696
  ewwwio_debug_message( "webp validation for $image" );
697
+ if (
698
+ strpos( $image, 'base64,R0lGOD' ) ||
699
+ strpos( $image, 'lazy-load/images/1x1' ) ||
700
+ strpos( $image, '/assets/images/' )
701
+ ) {
702
  ewwwio_debug_message( 'lazy load placeholder' );
703
  return false;
704
  }
754
  */
755
  function debug_script() {
756
  if ( ! ewww_image_optimizer_ce_webp_enabled() ) {
757
+ wp_enqueue_script( 'ewww-webp-load-script', plugins_url( '/includes/load_webp.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION );
758
  }
759
  }
760
 
763
  */
764
  function min_external_script() {
765
  if ( ! ewww_image_optimizer_ce_webp_enabled() ) {
766
+ wp_enqueue_script( 'ewww-webp-load-script', plugins_url( '/includes/load_webp.min.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION );
 
 
 
 
 
 
 
 
 
767
  }
 
 
768
  }
769
 
770
  /**
classes/class-ewwwio-gd-editor.php CHANGED
@@ -26,7 +26,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
26
  * @return WP_Error| array The full path, base filename, width, height, and mimetype.
27
  */
28
  protected function _save( $image, $filename = null, $mime_type = null ) {
29
- ewwwio_debug_message( '<b>wp_image_editor_gd(agr)::' . __FUNCTION__ . '()</b>' );
30
  global $ewww_defer;
31
  global $ewww_preempt_editor;
32
  if ( ! empty( $ewww_preempt_editor ) ) {
@@ -83,7 +83,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
83
  }
84
  ewww_image_optimizer_debug_log();
85
  }
86
- ewwwio_memory( __FUNCTION__ );
87
  return $saved;
88
  }
89
  /**
@@ -130,7 +130,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
130
  }
131
  }
132
  ewww_image_optimizer_debug_log();
133
- ewwwio_memory( __FUNCTION__ );
134
  return $metadata;
135
  }
136
  }
@@ -150,7 +150,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
150
  * @return WP_Error| array The full path, base filename, width, height, and mimetype.
151
  */
152
  protected function _save( $image, $filename = null, $mime_type = null ) {
153
- ewwwio_debug_message( '<b>wp_image_editor_gd(wpthumb)::' . __FUNCTION__ . '()</b>' );
154
  global $ewww_defer;
155
  global $ewww_preempt_editor;
156
  if ( ! empty( $ewww_preempt_editor ) ) {
@@ -207,7 +207,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
207
  }
208
  ewww_image_optimizer_debug_log();
209
  }
210
- ewwwio_memory( __FUNCTION__ );
211
  return $saved;
212
  }
213
  }
@@ -227,7 +227,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
227
  * @return WP_Error| array The full path, base filename, width, height, and mimetype.
228
  */
229
  protected function _save( $image, $filename = null, $mime_type = null ) {
230
- ewwwio_debug_message( '<b>wp_image_editor_gd(bfi)::' . __FUNCTION__ . '()</b>' );
231
  global $ewww_defer;
232
  global $ewww_preempt_editor;
233
  if ( ! empty( $ewww_preempt_editor ) ) {
@@ -284,7 +284,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
284
  }
285
  ewww_image_optimizer_debug_log();
286
  }
287
- ewwwio_memory( __FUNCTION__ );
288
  return $saved;
289
  }
290
  }
@@ -310,10 +310,14 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
310
  * @return bool|WP_Error
311
  */
312
  protected function _resize( $max_w, $max_h, $crop = false ) {
313
- ewwwio_debug_message( '<b>wp_image_editor_gd::' . __FUNCTION__ . '()</b>' );
314
- if ( ( ! $max_w || $max_w >= $this->size['width'] ) && ( ! $max_h || $max_h >= $this->size['height'] ) ) {
315
- return new WP_Error( 'image_resize_error', __( 'Image resize failed.' ) );
 
316
  }
 
 
 
317
  if ( defined( 'EWWWIO_EDITOR_AGR' ) && ! EWWWIO_EDITOR_AGR ) {
318
  ewwwio_debug_message( 'AGR disabled' );
319
  return parent::_resize( $max_w, $max_h, $crop );
@@ -326,7 +330,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
326
  ewww_image_optimizer_cloud_init();
327
  }
328
  $ewww_status = get_transient( 'ewww_image_optimizer_cloud_status' );
329
- if ( 'image/gif' === $this->mime_type && function_exists( 'ewww_image_optimizer_path_check' ) ) {
330
  ewww_image_optimizer_path_check( false, false, true, false, false, false );
331
  }
332
  if ( 'image/gif' === $this->mime_type && ( ! defined( 'EWWW_IMAGE_OPTIMIZER_GIFSICLE' ) || ! EWWW_IMAGE_OPTIMIZER_GIFSICLE ) ) {
@@ -352,11 +356,11 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
352
  ewwwio_debug_message( 'GIF already altered, leave it alone' );
353
  return parent::_resize( $max_w, $max_h, $crop );
354
  }
355
- if ( ! $this->file || 0 === strpos( $this->file, 's3' ) || 0 === strpos( $this->file, 'http' ) || 0 === strpos( $this->file, 'ftp' ) || ! is_file( $this->file ) ) {
356
  ewwwio_debug_message( 'could not load original file, or remote path detected' );
357
  return parent::_resize( $max_w, $max_h, $crop );
358
  }
359
- $resize_result = ewww_image_optimizer_better_resize( $this->file, $max_w, $max_h, $crop );
360
  if ( is_wp_error( $resize_result ) ) {
361
  return $resize_result;
362
  }
@@ -366,7 +370,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
366
  return new WP_Error( 'image_resize_error', __( 'Image resize failed.' ) );
367
  }
368
  $this->update_size( $new_size[0], $new_size[1] );
369
- ewwwio_memory( __FUNCTION__ );
370
  return $resize_result;
371
  }
372
 
@@ -386,7 +390,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
386
  * @return true|WP_Error
387
  */
388
  public function resize( $max_w, $max_h, $crop = false ) {
389
- ewwwio_debug_message( '<b>wp_image_editor_gd::' . __FUNCTION__ . '()</b>' );
390
  if ( ( $this->size['width'] == $max_w ) && ( $this->size['height'] == $max_h ) ) {
391
  return true;
392
  }
@@ -432,7 +436,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
432
  * @return array An array of resized images' metadata by size.
433
  */
434
  public function multi_resize( $sizes ) {
435
- ewwwio_debug_message( '<b>wp_image_editor_gd::' . __FUNCTION__ . '()</b>' );
436
  $metadata = array();
437
  $orig_size = $this->size;
438
  foreach ( $sizes as $size => $size_data ) {
@@ -534,7 +538,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
534
  * @return WP_Error|array The full path, base filename, and mimetype.
535
  */
536
  protected function _save_ewwwio_file( $image, $filename = null, $mime_type = null ) {
537
- ewwwio_debug_message( '<b>wp_image_editor_gd::' . __FUNCTION__ . '()</b>' );
538
  list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type );
539
  if ( ! $filename ) {
540
  $filename = $this->generate_filename( null, null, $extension );
@@ -573,7 +577,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
573
  $perms = $stat['mode'] & 0000666; // Same permissions as parent folder with executable bits stripped.
574
  chmod( $filename, $perms );
575
  }
576
- ewwwio_memory( __FUNCTION__ );
577
  return array(
578
  'path' => $filename,
579
  'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $filename ) ),
@@ -582,7 +586,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
582
  'mime-type' => $mime_type,
583
  );
584
  }
585
- ewwwio_memory( __FUNCTION__ );
586
  return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
587
  }
588
 
@@ -597,7 +601,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
597
  * @return WP_Error|array The full path, base filename, and mimetype.
598
  */
599
  protected function _save( $image, $filename = null, $mime_type = null ) {
600
- ewwwio_debug_message( '<b>wp_image_editor_gd::' . __FUNCTION__ . '()</b>' );
601
  global $ewww_defer;
602
  global $ewww_preempt_editor;
603
  if ( ! empty( $this->ewww_image ) && empty( $this->modified ) ) {
@@ -657,7 +661,7 @@ if ( class_exists( 'Bbpp_Animated_Gif' ) ) {
657
  }
658
  ewww_image_optimizer_debug_log();
659
  }
660
- ewwwio_memory( __FUNCTION__ );
661
  return $saved;
662
  }
663
  }
26
  * @return WP_Error| array The full path, base filename, width, height, and mimetype.
27
  */
28
  protected function _save( $image, $filename = null, $mime_type = null ) {
29
+ ewwwio_debug_message( '<b>(agr)' . __METHOD__ . '()</b>' );
30
  global $ewww_defer;
31
  global $ewww_preempt_editor;
32
  if ( ! empty( $ewww_preempt_editor ) ) {
83
  }
84
  ewww_image_optimizer_debug_log();
85
  }
86
+ ewwwio_memory( __METHOD__ );
87
  return $saved;
88
  }
89
  /**
130
  }
131
  }
132
  ewww_image_optimizer_debug_log();
133
+ ewwwio_memory( __METHOD__ );
134
  return $metadata;
135
  }
136
  }
150
  * @return WP_Error| array The full path, base filename, width, height, and mimetype.
151
  */
152
  protected function _save( $image, $filename = null, $mime_type = null ) {
153
+ ewwwio_debug_message( '<b>(wpthumb)' . __METHOD__ . '()</b>' );
154
  global $ewww_defer;
155
  global $ewww_preempt_editor;
156
  if ( ! empty( $ewww_preempt_editor ) ) {
207
  }
208
  ewww_image_optimizer_debug_log();
209
  }
210
+ ewwwio_memory( __METHOD__ );
211
  return $saved;
212
  }
213
  }
227
  * @return WP_Error| array The full path, base filename, width, height, and mimetype.
228
  */
229
  protected function _save( $image, $filename = null, $mime_type = null ) {
230
+ ewwwio_debug_message( '<b>(bfi)::' . __METHOD__ . '()</b>' );
231
  global $ewww_defer;
232
  global $ewww_preempt_editor;
233
  if ( ! empty( $ewww_preempt_editor ) ) {
284
  }
285
  ewww_image_optimizer_debug_log();
286
  }
287
+ ewwwio_memory( __METHOD__ );
288
  return $saved;
289
  }
290
  }
310
  * @return bool|WP_Error
311
  */
312
  protected function _resize( $max_w, $max_h, $crop = false ) {
313
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
314
+ $dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop );
315
+ if ( ! $dims ) {
316
+ return new WP_Error( 'error_getting_dimensions', __( 'Could not calculate resized image dimensions' ), $this->file );
317
  }
318
+ list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;
319
+ ewwwio_debug_message( "dst_x $dst_x, dst_y $dst_y, src_x $src_x, src_y $src_y, dst_w $dst_w, dst_h $dst_h, src_w $src_w, src_h $src_h" );
320
+
321
  if ( defined( 'EWWWIO_EDITOR_AGR' ) && ! EWWWIO_EDITOR_AGR ) {
322
  ewwwio_debug_message( 'AGR disabled' );
323
  return parent::_resize( $max_w, $max_h, $crop );
330
  ewww_image_optimizer_cloud_init();
331
  }
332
  $ewww_status = get_transient( 'ewww_image_optimizer_cloud_status' );
333
+ if ( 'image/gif' === $this->mime_type && function_exists( 'ewww_image_optimizer_path_check' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) ) {
334
  ewww_image_optimizer_path_check( false, false, true, false, false, false );
335
  }
336
  if ( 'image/gif' === $this->mime_type && ( ! defined( 'EWWW_IMAGE_OPTIMIZER_GIFSICLE' ) || ! EWWW_IMAGE_OPTIMIZER_GIFSICLE ) ) {
356
  ewwwio_debug_message( 'GIF already altered, leave it alone' );
357
  return parent::_resize( $max_w, $max_h, $crop );
358
  }
359
+ if ( ! $this->file || ewww_image_optimizer_stream_wrapped( $this->file ) || 0 === strpos( $this->file, 'http' ) || 0 === strpos( $this->file, 'ftp' ) || ! is_file( $this->file ) ) {
360
  ewwwio_debug_message( 'could not load original file, or remote path detected' );
361
  return parent::_resize( $max_w, $max_h, $crop );
362
  }
363
+ $resize_result = ewww_image_optimizer_better_resize( $this->file, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h );
364
  if ( is_wp_error( $resize_result ) ) {
365
  return $resize_result;
366
  }
370
  return new WP_Error( 'image_resize_error', __( 'Image resize failed.' ) );
371
  }
372
  $this->update_size( $new_size[0], $new_size[1] );
373
+ ewwwio_memory( __METHOD__ );
374
  return $resize_result;
375
  }
376
 
390
  * @return true|WP_Error
391
  */
392
  public function resize( $max_w, $max_h, $crop = false ) {
393
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
394
  if ( ( $this->size['width'] == $max_w ) && ( $this->size['height'] == $max_h ) ) {
395
  return true;
396
  }
436
  * @return array An array of resized images' metadata by size.
437
  */
438
  public function multi_resize( $sizes ) {
439
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
440
  $metadata = array();
441
  $orig_size = $this->size;
442
  foreach ( $sizes as $size => $size_data ) {
538
  * @return WP_Error|array The full path, base filename, and mimetype.
539
  */
540
  protected function _save_ewwwio_file( $image, $filename = null, $mime_type = null ) {
541
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
542
  list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type );
543
  if ( ! $filename ) {
544
  $filename = $this->generate_filename( null, null, $extension );
577
  $perms = $stat['mode'] & 0000666; // Same permissions as parent folder with executable bits stripped.
578
  chmod( $filename, $perms );
579
  }
580
+ ewwwio_memory( __METHOD__ );
581
  return array(
582
  'path' => $filename,
583
  'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $filename ) ),
586
  'mime-type' => $mime_type,
587
  );
588
  }
589
+ ewwwio_memory( __METHOD__ );
590
  return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
591
  }
592
 
601
  * @return WP_Error|array The full path, base filename, and mimetype.
602
  */
603
  protected function _save( $image, $filename = null, $mime_type = null ) {
604
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
605
  global $ewww_defer;
606
  global $ewww_preempt_editor;
607
  if ( ! empty( $this->ewww_image ) && empty( $this->modified ) ) {
661
  }
662
  ewww_image_optimizer_debug_log();
663
  }
664
+ ewwwio_memory( __METHOD__ );
665
  return $saved;
666
  }
667
  }
classes/class-ewwwio-hs-beacon.php CHANGED
@@ -32,7 +32,7 @@ class EWWWIO_HS_Beacon {
32
  * @return bool The unaltered setting.
33
  */
34
  public function check_for_settings_optin( $input ) {
35
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
36
  if ( isset( $_POST['ewww_image_optimizer_enable_help'] ) && $_POST['ewww_image_optimizer_enable_help'] ) {
37
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_tracking_notice', 1 );
38
  }
@@ -43,7 +43,7 @@ class EWWWIO_HS_Beacon {
43
  * Check for a new opt-in via the admin notice
44
  */
45
  public function check_for_optin() {
46
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
47
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_enable_help', 1 );
48
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_enable_help_notice', 1 );
49
  wp_redirect( remove_query_arg( 'action', wp_get_referer() ) );
@@ -54,7 +54,7 @@ class EWWWIO_HS_Beacon {
54
  * Check for a new opt-out via the admin notice
55
  */
56
  public function check_for_optout() {
57
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
58
  delete_option( 'ewww_image_optimizer_enable_help' );
59
  delete_network_option( null, 'ewww_image_optimizer_enable_help' );
60
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_enable_help_notice', 1 );
@@ -70,7 +70,7 @@ class EWWWIO_HS_Beacon {
70
  * @return void
71
  */
72
  public function admin_notice( $network_class = '' ) {
73
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
74
  $hide_notice = ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help_notice' );
75
  if ( 'network-multisite' == $network_class && get_site_option( 'ewww_image_optimizer_allow_multisite_override' ) ) {
76
  return;
32
  * @return bool The unaltered setting.
33
  */
34
  public function check_for_settings_optin( $input ) {
35
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
36
  if ( isset( $_POST['ewww_image_optimizer_enable_help'] ) && $_POST['ewww_image_optimizer_enable_help'] ) {
37
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_tracking_notice', 1 );
38
  }
43
  * Check for a new opt-in via the admin notice
44
  */
45
  public function check_for_optin() {
46
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
47
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_enable_help', 1 );
48
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_enable_help_notice', 1 );
49
  wp_redirect( remove_query_arg( 'action', wp_get_referer() ) );
54
  * Check for a new opt-out via the admin notice
55
  */
56
  public function check_for_optout() {
57
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
58
  delete_option( 'ewww_image_optimizer_enable_help' );
59
  delete_network_option( null, 'ewww_image_optimizer_enable_help' );
60
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_enable_help_notice', 1 );
70
  * @return void
71
  */
72
  public function admin_notice( $network_class = '' ) {
73
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
74
  $hide_notice = ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help_notice' );
75
  if ( 'network-multisite' == $network_class && get_site_option( 'ewww_image_optimizer_allow_multisite_override' ) ) {
76
  return;
classes/class-ewwwio-imagick-editor.php CHANGED
@@ -378,9 +378,7 @@ if ( class_exists( 'WP_Thumb_Image_Editor_Imagick' ) ) {
378
  }
379
  list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;
380
 
381
- $crop = $crop ? $dims : false;
382
-
383
- $resized = $this->_resize( $dst_w, $dst_h, $crop );
384
 
385
  if ( is_string( $resized ) ) {
386
  $this->ewww_image = $resized;
@@ -398,39 +396,44 @@ if ( class_exists( 'WP_Thumb_Image_Editor_Imagick' ) ) {
398
  *
399
  * @since 4.6.0
400
  *
401
- * @param int|null $max_w Image width.
402
- * @param int|null $max_h Image height.
403
- * @param array $crop Optional. Scale by default, crop if true. Will contain all
404
- * parameters necessary for crop method.
 
 
 
 
 
 
 
 
 
405
  * @return bool|WP_Error
406
  */
407
- protected function _resize( $max_w, $max_h, $crop = false ) {
408
  ewwwio_debug_message( '<b>wp_image_editor_gd::' . __FUNCTION__ . '()</b>' );
409
- if ( ( ! $max_w || $max_w >= $this->size['width'] ) && ( ! $max_h || $max_h >= $this->size['height'] ) ) {
410
- return new WP_Error( 'image_resize_error', __( 'Image resize failed.' ) );
411
- }
412
  if ( defined( 'EWWWIO_EDITOR_AGR' ) && ! EWWWIO_EDITOR_AGR ) {
413
  ewwwio_debug_message( 'AGR disabled' );
414
  if ( $crop ) {
415
- list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $crop;
416
  return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h );
417
  }
418
- return $this->thumbnail_image( $max_w, $max_h );
419
  }
420
  if ( defined( 'EWWWIO_EDITOR_BETTER_RESIZE' ) && ! EWWW_IO_EDITOR_BETTER_RESIZE ) {
421
  ewwwio_debug_message( 'API resize disabled' );
422
  if ( $crop ) {
423
- list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $crop;
424
  return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h );
425
  }
426
- return $this->thumbnail_image( $max_w, $max_h );
427
  }
428
  $return_parent = false; // An indicator for whether we should short-circuit and use the parent thumbnail_image method.
429
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_CLOUD' ) ) {
430
  ewww_image_optimizer_cloud_init();
431
  }
432
  $ewww_status = get_transient( 'ewww_image_optimizer_cloud_status' );
433
- if ( 'image/gif' === $this->mime_type && function_exists( 'ewww_image_optimizer_path_check' ) ) {
434
  ewww_image_optimizer_path_check( false, false, true, false, false, false );
435
  }
436
  if ( 'image/gif' === $this->mime_type && ( ! defined( 'EWWW_IMAGE_OPTIMIZER_GIFSICLE' ) || ! EWWW_IMAGE_OPTIMIZER_GIFSICLE ) ) {
@@ -456,18 +459,17 @@ if ( class_exists( 'WP_Thumb_Image_Editor_Imagick' ) ) {
456
  ewwwio_debug_message( 'GIF already altered, leave it alone' );
457
  $return_parent = true;
458
  }
459
- if ( ! $this->file || 0 === strpos( $this->file, 's3' ) || 0 === strpos( $this->file, 'http' ) || 0 === strpos( $this->file, 'ftp' ) || ! is_file( $this->file ) ) {
460
  ewwwio_debug_message( 'could not load original file, or remote path detected' );
461
  $return_parent = true;
462
  }
463
  if ( $return_parent ) {
464
  if ( $crop ) {
465
- list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $crop;
466
  return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h );
467
  }
468
- return $this->thumbnail_image( $max_w, $max_h );
469
  }
470
- $resize_result = ewww_image_optimizer_better_resize( $this->file, $max_w, $max_h, $crop );
471
  if ( is_wp_error( $resize_result ) ) {
472
  return $resize_result;
473
  }
378
  }
379
  list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;
380
 
381
+ $resized = $this->_resize( $dims, $crop );
 
 
382
 
383
  if ( is_string( $resized ) ) {
384
  $this->ewww_image = $resized;
396
  *
397
  * @since 4.6.0
398
  *
399
+ * @param array $dims {
400
+ * All parameters necessary for resizing.
401
+ *
402
+ * @type int $dst_x X-coordinate of destination image (usually 0).
403
+ * @type int $dst_y Y-coordinate of destination image (usually 0).
404
+ * @type int $src_x X-coordinate of source image (usually 0 unless cropping).
405
+ * @type int $src_y Y-coordinate of source image (usually 0 unless cropping).
406
+ * @type int $dst_w Desired image width.
407
+ * @type int $dst_h Desired image height.
408
+ * @type int $src_w Source width.
409
+ * @type int $src_h Source height.
410
+ * }
411
+ * @param bool $crop Should we crop or should we scale.
412
  * @return bool|WP_Error
413
  */
414
+ protected function _resize( $dims, $crop ) {
415
  ewwwio_debug_message( '<b>wp_image_editor_gd::' . __FUNCTION__ . '()</b>' );
416
+ list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;
 
 
417
  if ( defined( 'EWWWIO_EDITOR_AGR' ) && ! EWWWIO_EDITOR_AGR ) {
418
  ewwwio_debug_message( 'AGR disabled' );
419
  if ( $crop ) {
 
420
  return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h );
421
  }
422
+ return $this->thumbnail_image( $dst_w, $dst_h );
423
  }
424
  if ( defined( 'EWWWIO_EDITOR_BETTER_RESIZE' ) && ! EWWW_IO_EDITOR_BETTER_RESIZE ) {
425
  ewwwio_debug_message( 'API resize disabled' );
426
  if ( $crop ) {
 
427
  return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h );
428
  }
429
+ return $this->thumbnail_image( $dst_w, $dst_h );
430
  }
431
  $return_parent = false; // An indicator for whether we should short-circuit and use the parent thumbnail_image method.
432
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_CLOUD' ) ) {
433
  ewww_image_optimizer_cloud_init();
434
  }
435
  $ewww_status = get_transient( 'ewww_image_optimizer_cloud_status' );
436
+ if ( 'image/gif' === $this->mime_type && function_exists( 'ewww_image_optimizer_path_check' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) ) {
437
  ewww_image_optimizer_path_check( false, false, true, false, false, false );
438
  }
439
  if ( 'image/gif' === $this->mime_type && ( ! defined( 'EWWW_IMAGE_OPTIMIZER_GIFSICLE' ) || ! EWWW_IMAGE_OPTIMIZER_GIFSICLE ) ) {
459
  ewwwio_debug_message( 'GIF already altered, leave it alone' );
460
  $return_parent = true;
461
  }
462
+ if ( ! $this->file || ewww_image_optimizer_stream_wrapped( $this->file ) || 0 === strpos( $this->file, 'http' ) || 0 === strpos( $this->file, 'ftp' ) || ! is_file( $this->file ) ) {
463
  ewwwio_debug_message( 'could not load original file, or remote path detected' );
464
  $return_parent = true;
465
  }
466
  if ( $return_parent ) {
467
  if ( $crop ) {
 
468
  return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h );
469
  }
470
+ return $this->thumbnail_image( $dst_w, $dst_h );
471
  }
472
+ $resize_result = ewww_image_optimizer_better_resize( $this->file, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h );
473
  if ( is_wp_error( $resize_result ) ) {
474
  return $resize_result;
475
  }
classes/class-ewwwio-lazy-load.php ADDED
@@ -0,0 +1,417 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Implements Lazy Loading using page parsing and JS functionality.
4
+ *
5
+ * @link https://ewww.io
6
+ * @package EWWW_Image_Optimizer
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * Enables EWWW IO to filter the page content and replace img elements with Lazy Load markup.
15
+ */
16
+ class EWWWIO_Lazy_Load extends EWWWIO_Page_Parser {
17
+
18
+ /**
19
+ * Base64 encoded placeholder image.
20
+ *
21
+ * @access protected
22
+ * @var string $placeholder_src
23
+ */
24
+ protected $placeholder_src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
25
+
26
+ /**
27
+ * Indicates if we are filtering ExactDN urls.
28
+ *
29
+ * @access protected
30
+ * @var bool $parsing_exactdn
31
+ */
32
+ protected $parsing_exactdn = false;
33
+
34
+ /**
35
+ * Register (once) actions and filters for Lazy Load.
36
+ */
37
+ function __construct() {
38
+ ewwwio_debug_message( 'firing up lazy load' );
39
+ global $ewwwio_lazy_load;
40
+ if ( is_object( $ewwwio_lazy_load ) ) {
41
+ ewwwio_debug_message( 'you are doing it wrong' );
42
+ return 'you are doing it wrong';
43
+ }
44
+ // Start an output buffer before any output starts.
45
+ /* add_action( 'template_redirect', array( $this, 'buffer_start' ), 1 ); */
46
+ add_filter( 'ewww_image_optimizer_filter_page_output', array( $this, 'filter_page_output' ), 15 );
47
+
48
+ if ( class_exists( 'ExactDN' ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) {
49
+ global $exactdn;
50
+ $this->exactdn_domain = $exactdn->get_exactdn_domain();
51
+ if ( $this->exactdn_domain ) {
52
+ $this->parsing_exactdn = true;
53
+ ewwwio_debug_message( 'parsing an exactdn page' );
54
+ }
55
+ }
56
+
57
+ // Filter early, so that others at the default priority take precendence.
58
+ add_filter( 'ewww_image_optimizer_use_lqip', array( $this, 'maybe_lqip' ), 9 );
59
+
60
+ // Load the appropriate JS.
61
+ if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
62
+ // Load the non-minified and separate versions of the lazy load scripts.
63
+ add_action( 'wp_enqueue_scripts', array( $this, 'debug_script' ) );
64
+ } else {
65
+ // Load the minified, combined version of the lazy load script.
66
+ add_action( 'wp_enqueue_scripts', array( $this, 'min_script' ) );
67
+ }
68
+ }
69
+
70
+
71
+ /**
72
+ * Starts an output buffer and registers the callback function to do WebP replacement.
73
+ */
74
+ function buffer_start() {
75
+ ob_start( array( $this, 'filter_page_output' ) );
76
+ }
77
+
78
+ /**
79
+ * Replaces images within a srcset attribute, just a placeholder at the moment.
80
+ *
81
+ * @param string $srcset A valid srcset attribute from an img element.
82
+ * @return bool|string False if no changes were made, or the new srcset if any WebP images replaced the originals.
83
+ */
84
+ function srcset_replace( $srcset ) {
85
+ return $srcset;
86
+ }
87
+
88
+ /**
89
+ * Search for img elements and rewrite them for Lazy Load with fallback to noscript elements.
90
+ *
91
+ * @param string $buffer The full HTML page generated since the output buffer was started.
92
+ * @return string The altered buffer containing the full page with Lazy Load attributes.
93
+ */
94
+ function filter_page_output( $buffer ) {
95
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
96
+ // Don't lazy load in these cases...
97
+ $uri = $_SERVER['REQUEST_URI'];
98
+ if (
99
+ empty( $buffer ) ||
100
+ is_admin() ||
101
+ ! empty( $_GET['cornerstone'] ) ||
102
+ strpos( $uri, 'cornerstone-endpoint' ) !== false ||
103
+ ! empty( $_GET['et_fb'] ) ||
104
+ ! empty( $_GET['tatsu'] ) ||
105
+ ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === $_POST['action'] ) ||
106
+ ! apply_filters( 'ewww_image_optimizer_do_lazyload', true ) ||
107
+ is_feed() ||
108
+ is_preview() ||
109
+ ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ||
110
+ wp_script_is( 'twentytwenty-twentytwenty', 'enqueued' ) ||
111
+ preg_match( '/<\?xml/', $buffer )
112
+ ) {
113
+ if ( empty( $buffer ) ) {
114
+ ewwwio_debug_message( 'empty buffer' );
115
+ }
116
+ if ( is_admin() ) {
117
+ ewwwio_debug_message( 'is_admin' );
118
+ }
119
+ if ( ! empty( $_GET['cornerstone'] ) || strpos( $uri, 'cornerstone-endpoint' ) !== false ) {
120
+ ewwwio_debug_message( 'cornerstone editor' );
121
+ }
122
+ if ( ! empty( $_GET['et_fb'] ) ) {
123
+ ewwwio_debug_message( 'et_fb' );
124
+ }
125
+ if ( ! empty( $_GET['tatsu'] ) || ( ! empty( $_POST['action'] ) && 'tatsu_get_concepts' === $_POST['action'] ) ) {
126
+ ewwwio_debug_message( 'tatsu' );
127
+ }
128
+ if ( ! apply_filters( 'ewww_image_optimizer_do_lazyload', true ) ) {
129
+ ewwwio_debug_message( 'do_lazyload short-circuit' );
130
+ }
131
+ if ( is_feed() ) {
132
+ ewwwio_debug_message( 'is_feed' );
133
+ }
134
+ if ( is_preview() ) {
135
+ ewwwio_debug_message( 'is_preview' );
136
+ }
137
+ if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
138
+ ewwwio_debug_message( 'rest request' );
139
+ }
140
+ if ( wp_script_is( 'twentytwenty-twentytwenty', 'enqueued' ) ) {
141
+ ewwwio_debug_message( 'twentytwenty enqueued' );
142
+ }
143
+ if ( preg_match( '/<\?xml/', $buffer ) ) {
144
+ ewwwio_debug_message( 'not html, xml tag found' );
145
+ }
146
+ if ( strpos( $buffer, 'amp-boilerplate' ) ) {
147
+ ewwwio_debug_message( 'AMP page processing' );
148
+ }
149
+ return $buffer;
150
+ }
151
+
152
+ $above_the_fold = apply_filters( 'ewww_image_optimizer_lazy_fold', 0 );
153
+ $images_processed = 0;
154
+
155
+ $images = $this->get_images_from_html( preg_replace( '/<noscript.*?\/noscript>/', '', $buffer ), false );
156
+ if ( ewww_image_optimizer_iterable( $images[0] ) ) {
157
+ foreach ( $images[0] as $index => $image ) {
158
+ $images_processed++;
159
+ if ( $images_processed <= $above_the_fold ) {
160
+ continue;
161
+ }
162
+ $file = $images['img_url'][ $index ];
163
+ ewwwio_debug_message( "parsing an image: $file" );
164
+ if ( $this->validate_image_tag( $image ) ) {
165
+ ewwwio_debug_message( 'found a valid image tag' );
166
+ $orig_img = $image;
167
+ $noscript = '<noscript>' . $orig_img . '</noscript>';
168
+ $this->set_attribute( $image, 'data-src', $file, true );
169
+ $srcset = $this->get_attribute( $image, 'srcset' );
170
+
171
+ $placeholder_src = $this->placeholder_src;
172
+ if ( false === strpos( $file, 'nggid' ) && apply_filters( 'ewww_image_optimizer_use_lqip', true ) && $this->parsing_exactdn && strpos( $file, $this->exactdn_domain ) ) {
173
+ $placeholder_src = add_query_arg( array( 'lazy' => 1 ), $file );
174
+ ewwwio_debug_message( "current placeholder is $placeholder_src" );
175
+ }
176
+
177
+ if ( $srcset ) {
178
+ if ( strpos( $placeholder_src, '64,R0lGOD' ) ) {
179
+ $this->set_attribute( $image, 'srcset', $placeholder_src, true );
180
+ $this->remove_attribute( $image, 'src' );
181
+ } else {
182
+ $this->set_attribute( $image, 'src', $placeholder_src, true );
183
+ $this->remove_attribute( $image, 'srcset' );
184
+ }
185
+ $this->set_attribute( $image, 'data-srcset', $srcset, true );
186
+ $srcset_sizes = $this->get_attribute( $image, 'sizes' );
187
+ // Return false on this filter to disable automatic sizes calculation,
188
+ // or use the sizes value passed via the filter to conditionally disable it.
189
+ if ( apply_filters( 'ewww_image_optimizer_lazy_responsive', $srcset_sizes ) ) {
190
+ $this->set_attribute( $image, 'data-sizes', 'auto', true );
191
+ $this->remove_attribute( $image, 'sizes' );
192
+ }
193
+ } else {
194
+ $this->set_attribute( $image, 'src', $placeholder_src, true );
195
+ }
196
+ $this->set_attribute( $image, 'class', $this->get_attribute( $image, 'class' ) . ' lazyload', true );
197
+ $buffer = str_replace( $orig_img, $image . $noscript, $buffer );
198
+ }
199
+ } // End foreach().
200
+ } // End if().
201
+ // Process background images on 'div' elements.
202
+ $divs = $this->get_elements_from_html( $buffer, 'div' );
203
+ if ( ewww_image_optimizer_iterable( $divs ) ) {
204
+ $lazy_class = 'lazyload';
205
+ foreach ( $divs as $index => $div ) {
206
+ ewwwio_debug_message( 'parsing a div' );
207
+ if ( false === strpos( $div, 'background:' ) && false === strpos( $div, 'background-image:' ) ) {
208
+ continue;
209
+ }
210
+ if ( false !== strpos( $div, $lazy_class ) ) {
211
+ continue;
212
+ }
213
+ if ( ! $this->validate_bgimage_tag( $div ) ) {
214
+ continue;
215
+ }
216
+ $style = $this->get_attribute( $div, 'style' );
217
+ if ( empty( $style ) ) {
218
+ continue;
219
+ }
220
+ ewwwio_debug_message( "checking style attr for background-image: $style" );
221
+ $bg_image_url = $this->get_background_image_url( $style );
222
+ if ( $bg_image_url ) {
223
+ $this->set_attribute( $div, 'class', $this->get_attribute( $div, 'class' ) . " $lazy_class", true );
224
+ $this->set_attribute( $div, 'data-bg', $bg_image_url );
225
+ $new_style = $this->remove_background_image( $style );
226
+ if ( $style !== $new_style ) {
227
+ $div = str_replace( $style, $new_style, $div );
228
+ }
229
+ }
230
+ if ( $div !== $divs[ $index ] ) {
231
+ $buffer = str_replace( $divs[ $index ], $div, $buffer );
232
+ }
233
+ }
234
+ }
235
+ // Images listed as picture/source elements. Mostly for NextGEN, but should work anywhere.
236
+ $pictures = $this->get_picture_tags_from_html( $buffer );
237
+ if ( ewww_image_optimizer_iterable( $pictures ) ) {
238
+ foreach ( $pictures as $index => $picture ) {
239
+ $sources = $this->get_elements_from_html( $picture, 'source' );
240
+ if ( ewww_image_optimizer_iterable( $sources ) ) {
241
+ foreach ( $sources as $source ) {
242
+ if ( false !== strpos( $source, 'data-src' ) ) {
243
+ continue;
244
+ }
245
+ ewwwio_debug_message( "parsing a picture source: $source" );
246
+ $srcset = $this->get_attribute( $source, 'srcset' );
247
+ if ( $srcset ) {
248
+ ewwwio_debug_message( 'found srcset in source' );
249
+ $lazy_source = $source;
250
+ $this->set_attribute( $lazy_source, 'data-srcset', $srcset );
251
+ $this->set_attribute( $lazy_source, 'srcset', $this->placeholder_src, true );
252
+ $picture = str_replace( $source, $lazy_source, $picture );
253
+ }
254
+ }
255
+ if ( $picture != $pictures[ $index ] ) {
256
+ ewwwio_debug_message( 'lazified sources for picture element' );
257
+ $buffer = str_replace( $pictures[ $index ], $picture, $buffer );
258
+ }
259
+ }
260
+ }
261
+ }
262
+ // Video elements, looking for poster attributes that are images.
263
+ /* $videos = $this->get_elements_from_html( $buffer, 'video' ); */
264
+ $videos = '';
265
+ if ( ewww_image_optimizer_iterable( $videos ) ) {
266
+ foreach ( $videos as $index => $video ) {
267
+ ewwwio_debug_message( 'parsing a video element' );
268
+ $file = $this->get_attribute( $video, 'poster' );
269
+ if ( $file ) {
270
+ ewwwio_debug_message( "checking webp for video poster: $file" );
271
+ if ( $this->validate_image_tag( $file ) ) {
272
+ $this->set_attribute( $video, 'data-poster-webp', $this->placeholder_src );
273
+ $this->set_attribute( $video, 'data-poster-image', $file );
274
+ $this->remove_attribute( $video, 'poster' );
275
+ ewwwio_debug_message( "found webp for video poster: $file" );
276
+ $buffer = str_replace( $videos[ $index ], $video, $buffer );
277
+ }
278
+ }
279
+ }
280
+ }
281
+ ewwwio_debug_message( 'all done parsing page for lazy' );
282
+ if ( true ) { // Set to true for extra logging.
283
+ ewww_image_optimizer_debug_log();
284
+ }
285
+ return $buffer;
286
+ }
287
+
288
+ /**
289
+ * Checks if the tag is allowed to be lazy loaded.
290
+ *
291
+ * @param string $image The image (img) tag.
292
+ * @return bool True if the tag is allowed, false otherwise.
293
+ */
294
+ function validate_image_tag( $image ) {
295
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
296
+ if (
297
+ strpos( $image, 'base64,R0lGOD' ) ||
298
+ strpos( $image, 'lazy-load/images/1x1' ) ||
299
+ strpos( $image, '/assets/images/' )
300
+ ) {
301
+ ewwwio_debug_message( 'lazy load placeholder detected' );
302
+ return false;
303
+ }
304
+
305
+ // Skip inline data URIs.
306
+ if ( strpos( $image, "src='data:image" ) || strpos( $image, 'src="data:image' ) ) {
307
+ return false;
308
+ }
309
+ // Ignore 0-size Pinterest schema images.
310
+ if ( strpos( $image, 'data-pin-description=' ) && strpos( $image, 'width="0" height="0"' ) ) {
311
+ return false;
312
+ }
313
+ $exclusions = apply_filters(
314
+ 'ewww_image_optimizer_lazy_exclusions',
315
+ array(
316
+ 'class="ls-bg',
317
+ 'class="ls-l',
318
+ 'class="rev-slidebg',
319
+ 'data-bgposition=',
320
+ 'data-envira-src=',
321
+ 'data-lazy=',
322
+ 'data-lazy-original=',
323
+ 'data-lazy-src=',
324
+ 'data-lazy-srcset=',
325
+ 'data-lazyload=',
326
+ 'data-lazysrc=',
327
+ 'data-no-lazy=',
328
+ 'data-src=',
329
+ 'data-srcset=',
330
+ 'ewww_webp_lazy_load',
331
+ 'fullurl=',
332
+ 'gazette-featured-content-thumbnail',
333
+ 'lazy-slider-img=',
334
+ 'skip-lazy',
335
+ 'timthumb.php?',
336
+ 'wpcf7_captcha/',
337
+ ),
338
+ $image
339
+ );
340
+ foreach ( $exclusions as $exclusion ) {
341
+ if ( false !== strpos( $image, $exclusion ) ) {
342
+ return false;
343
+ }
344
+ }
345
+ return true;
346
+ }
347
+
348
+ /**
349
+ * Checks if a tag with a background image is allowed to be lazy loaded.
350
+ *
351
+ * @param string $tag The tag.
352
+ * @return bool True if the tag is allowed, false otherwise.
353
+ */
354
+ function validate_bgimage_tag( $tag ) {
355
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
356
+ $exclusions = apply_filters(
357
+ 'ewww_image_optimizer_lazy_bg_image_exclusions',
358
+ array(),
359
+ $tag
360
+ );
361
+ foreach ( $exclusions as $exclusion ) {
362
+ if ( false !== strpos( $image, $exclusion ) ) {
363
+ return false;
364
+ }
365
+ }
366
+ return true;
367
+ }
368
+
369
+ /**
370
+ * Check if LQIP should be used, but allow filters to alter the option.
371
+ *
372
+ * @param bool $use_lqip Whether LL should use low-quality image placeholders.
373
+ * @return bool True to use LQIP, false to skip them.
374
+ */
375
+ function maybe_lqip( $use_lqip ) {
376
+ if ( defined( 'EWWW_IMAGE_OPTIMIZER_USE_LQIP' ) && ! EWWW_IMAGE_OPTIMIZER_USE_LQIP ) {
377
+ return false;
378
+ }
379
+ return $use_lqip;
380
+ }
381
+
382
+ /**
383
+ * Load full lazysizes script when SCRIPT_DEBUG is enabled.
384
+ */
385
+ function debug_script() {
386
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
387
+ wp_enqueue_script( 'ewww-lazy-load-pre', plugins_url( '/includes/lazysizes-pre.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION );
388
+ wp_enqueue_script( 'ewww-lazy-load', plugins_url( '/includes/lazysizes.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION );
389
+ wp_enqueue_script( 'ewww-lazy-load-post', plugins_url( '/includes/lazysizes-post.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION );
390
+ wp_enqueue_script( 'ewww-lazy-load-uvh', plugins_url( '/includes/ls.unveilhooks.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION );
391
+ wp_localize_script(
392
+ 'ewww-lazy-load',
393
+ 'ewww_lazy_vars',
394
+ array(
395
+ 'exactdn_domain' => ( $this->parsing_exactdn ? $this->exactdn_domain : '' ),
396
+ )
397
+ );
398
+ }
399
+
400
+ /**
401
+ * Load minified lazysizes script.
402
+ */
403
+ function min_script() {
404
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
405
+ wp_enqueue_script( 'ewww-lazy-load', plugins_url( '/includes/lazysizes.min.js', EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ), array(), EWWW_IMAGE_OPTIMIZER_VERSION );
406
+ wp_localize_script(
407
+ 'ewww-lazy-load',
408
+ 'ewww_lazy_vars',
409
+ array(
410
+ 'exactdn_domain' => ( $this->parsing_exactdn ? $this->exactdn_domain : '' ),
411
+ )
412
+ );
413
+ }
414
+ }
415
+
416
+ global $ewwwio_lazy_load;
417
+ $ewwwio_lazy_load = new EWWWIO_Lazy_Load();
classes/class-ewwwio-page-parser.php CHANGED
@@ -17,20 +17,25 @@ class EWWWIO_Page_Parser {
17
  /**
18
  * Match all images and any relevant <a> tags in a block of HTML.
19
  *
 
 
20
  * @param string $content Some HTML.
21
  * @param bool $hyperlinks Default true. Should we include encasing hyperlinks in our search.
 
22
  * @return array An array of $images matches, where $images[0] is
23
  * an array of full matches, and the link_url, img_tag,
24
  * and img_url keys are arrays of those matches.
25
  */
26
- function get_images_from_html( $content, $hyperlinks = true ) {
27
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
28
  $images = array();
29
 
30
  if ( $hyperlinks ) {
31
- $search_pattern = '#(?:<a[^>]+?href\s*=\s*["\'](?P<link_url>[^\s]+?)["\'][^>]*?>\s*)?(?P<img_tag><img[^>]*?\s+?src\s*=\s*["\'](?P<img_url>[^\s]+?)["\'].*?>){1}(?:\s*</a>)?#is';
32
- } else {
33
  $search_pattern = '#(?P<img_tag><img[^>]*?\s+?src\s*=\s*["\'](?P<img_url>[^\s]+?)["\'].*?>)#is';
 
 
34
  }
35
  if ( preg_match_all( $search_pattern, $content, $images ) ) {
36
  foreach ( $images as $key => $unused ) {
@@ -53,7 +58,7 @@ class EWWWIO_Page_Parser {
53
  * and img_url keys are arrays of those matches.
54
  */
55
  function get_noscript_images_from_html( $content ) {
56
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
57
  $images = array();
58
 
59
  if ( preg_match_all( '#(?P<noscript_tag><noscript[^>]*?>\s*)(?P<img_tag><img[^>]*?\s+?src\s*=\s*["\'](?P<img_url>[^\s]+?)["\'].*?>){1}(?:\s*</noscript>)?#is', $content, $images ) ) {
@@ -75,7 +80,7 @@ class EWWWIO_Page_Parser {
75
  * @return array An array of $pictures matches, containing full elements with ending tags.
76
  */
77
  function get_picture_tags_from_html( $content ) {
78
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
79
  $pictures = array();
80
  if ( preg_match_all( '#(?:<picture[^>]*?>\s*)(?:<source[^>]*?>)+(?:.*?</picture>)?#is', $content, $pictures ) ) {
81
  return $pictures[0];
@@ -91,7 +96,7 @@ class EWWWIO_Page_Parser {
91
  * @return array An array of $elements.
92
  */
93
  function get_elements_from_html( $content, $tag_name ) {
94
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
95
  if ( ! ctype_alpha( $tag_name ) ) {
96
  return array();
97
  }
@@ -108,7 +113,7 @@ class EWWWIO_Page_Parser {
108
  * @return array An array consisting of width and height.
109
  */
110
  function get_dimensions_from_filename( $src ) {
111
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
112
  $width_height_string = array();
113
  ewwwio_debug_message( "looking for dimensions in $src" );
114
  if ( preg_match( '#-(\d+)x(\d+)(@2x)?\.(?:' . implode( '|', $this->extensions ) . '){1}(?:\?.+)?$#i', $src, $width_height_string ) ) {
@@ -135,13 +140,14 @@ class EWWWIO_Page_Parser {
135
  * @return string The value of the attribute, or an empty string if not found.
136
  */
137
  function get_attribute( $element, $name ) {
138
- if ( preg_match( '#' . $name . '\s*=\s*(["\'])([^\1]+?)\1#is', $element, $attr_matches ) ) {
 
139
  if ( ! empty( $attr_matches[2] ) ) {
140
  return $attr_matches[2];
141
  }
142
  }
143
- // If there were not any matches with quotes, look for unquoted attributes, no spaces allowed.
144
- if ( preg_match( '#' . $name . '\s*=\s*([^\s]+?)#is', $element, $attr_matches ) ) {
145
  if ( ! empty( $attr_matches[1] ) ) {
146
  return $attr_matches[1];
147
  }
@@ -149,6 +155,21 @@ class EWWWIO_Page_Parser {
149
  return '';
150
  }
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  /**
153
  * Set an attribute on an HTML element.
154
  *
@@ -158,13 +179,18 @@ class EWWWIO_Page_Parser {
158
  * @param bool $replace Default false. True to replace, false to append.
159
  */
160
  function set_attribute( &$element, $name, $value, $replace = false ) {
 
 
 
 
161
  if ( $replace ) {
162
- $new_element = preg_replace( '#' . $name . '\s*=\s*(["\'])([^\1]+?)\1#is', "$name=$1$value$1", $element );
 
163
  if ( strpos( $new_element, "$name=" ) ) {
164
  $element = $new_element;
165
  return;
166
  }
167
- $element = preg_replace( '#' . $name . '\s*=\s*([^\s]+?)#is', '', $element );
168
  }
169
  $closing = ' />';
170
  if ( false === strpos( $element, '/>' ) ) {
@@ -184,8 +210,25 @@ class EWWWIO_Page_Parser {
184
  * @param string $name The name of the attribute to remove.
185
  */
186
  function remove_attribute( &$element, $name ) {
187
- $element = preg_replace( '#' . $name . '\s*=\s*(["\'])([^\1]+?)\1#is', '', $element );
188
- $element = preg_replace( '#' . $name . '\s*=\s*([^\s]+?)#is', '', $element );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  }
190
 
191
  /**
17
  /**
18
  * Match all images and any relevant <a> tags in a block of HTML.
19
  *
20
+ * The hyperlinks param implies that the src attribute is required, but not the other way around.
21
+ *
22
  * @param string $content Some HTML.
23
  * @param bool $hyperlinks Default true. Should we include encasing hyperlinks in our search.
24
+ * @param bool $src_required Default true. Should we look only for images with src attributes.
25
  * @return array An array of $images matches, where $images[0] is
26
  * an array of full matches, and the link_url, img_tag,
27
  * and img_url keys are arrays of those matches.
28
  */
29
+ function get_images_from_html( $content, $hyperlinks = true, $src_required = true ) {
30
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
31
  $images = array();
32
 
33
  if ( $hyperlinks ) {
34
+ $search_pattern = '#(?:<figure[^>]+?class\s*=\s*["\'](?P<figure_class>[\w\s-]+?)["\'][^>]*?>\s*)?(?:<a[^>]+?href\s*=\s*["\'](?P<link_url>[^\s]+?)["\'][^>]*?>\s*)?(?P<img_tag><img[^>]*?\s+?src\s*=\s*["\'](?P<img_url>[^\s]+?)["\'].*?>){1}(?:\s*</a>)?#is';
35
+ } elseif ( $src_required ) {
36
  $search_pattern = '#(?P<img_tag><img[^>]*?\s+?src\s*=\s*["\'](?P<img_url>[^\s]+?)["\'].*?>)#is';
37
+ } else {
38
+ $search_pattern = '#(?P<img_tag><img.*?>)#is';
39
  }
40
  if ( preg_match_all( $search_pattern, $content, $images ) ) {
41
  foreach ( $images as $key => $unused ) {
58
  * and img_url keys are arrays of those matches.
59
  */
60
  function get_noscript_images_from_html( $content ) {
61
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
62
  $images = array();
63
 
64
  if ( preg_match_all( '#(?P<noscript_tag><noscript[^>]*?>\s*)(?P<img_tag><img[^>]*?\s+?src\s*=\s*["\'](?P<img_url>[^\s]+?)["\'].*?>){1}(?:\s*</noscript>)?#is', $content, $images ) ) {
80
  * @return array An array of $pictures matches, containing full elements with ending tags.
81
  */
82
  function get_picture_tags_from_html( $content ) {
83
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
84
  $pictures = array();
85
  if ( preg_match_all( '#(?:<picture[^>]*?>\s*)(?:<source[^>]*?>)+(?:.*?</picture>)?#is', $content, $pictures ) ) {
86
  return $pictures[0];
96
  * @return array An array of $elements.
97
  */
98
  function get_elements_from_html( $content, $tag_name ) {
99
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
100
  if ( ! ctype_alpha( $tag_name ) ) {
101
  return array();
102
  }
113
  * @return array An array consisting of width and height.
114
  */
115
  function get_dimensions_from_filename( $src ) {
116
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
117
  $width_height_string = array();
118
  ewwwio_debug_message( "looking for dimensions in $src" );
119
  if ( preg_match( '#-(\d+)x(\d+)(@2x)?\.(?:' . implode( '|', $this->extensions ) . '){1}(?:\?.+)?$#i', $src, $width_height_string ) ) {
140
  * @return string The value of the attribute, or an empty string if not found.
141
  */
142
  function get_attribute( $element, $name ) {
143
+ // Don't forget, back references cannot be used in character classes.
144
+ if ( preg_match( '#[\s"\']' . $name . '\s*=\s*(["\'])([^"\']+?)\1#is', $element, $attr_matches ) ) {
145
  if ( ! empty( $attr_matches[2] ) ) {
146
  return $attr_matches[2];
147
  }
148
  }
149
+ // If there were not any matches with quotes, look for unquoted attributes, no spaces or quotes allowed.
150
+ if ( preg_match( '#[\s"\']' . $name . '\s*=\s*([^\s"\']+?)#is', $element, $attr_matches ) ) {
151
  if ( ! empty( $attr_matches[1] ) ) {
152
  return $attr_matches[1];
153
  }
155
  return '';
156
  }
157
 
158
+ /**
159
+ * Get a CSS background-image URL.
160
+ *
161
+ * @param string $attribute An element's style attribute. Do not pass a full HTML element.
162
+ * @return string The URL from the background/background-image property.
163
+ */
164
+ function get_background_image_url( $attribute ) {
165
+ if ( ( false !== strpos( $attribute, 'background:' ) || false !== strpos( $attribute, 'background-image:' ) ) && false !== strpos( $attribute, 'url(' ) ) {
166
+ if ( preg_match( '#url\(([^)]+)\)#', $attribute, $prop_match ) ) {
167
+ return trim( $prop_match[1], "'\"\t\n\r " );
168
+ }
169
+ }
170
+ return '';
171
+ }
172
+
173
  /**
174
  * Set an attribute on an HTML element.
175
  *
179
  * @param bool $replace Default false. True to replace, false to append.
180
  */
181
  function set_attribute( &$element, $name, $value, $replace = false ) {
182
+ if ( 'class' === $name && false !== strpos( $element, " $name " ) && false === strpos( $element, " $name =" ) ) {
183
+ $element = str_replace( " $name ", ' ', $element );
184
+ }
185
+ $value = trim( $value );
186
  if ( $replace ) {
187
+ // Don't forget, back references cannot be used in character classes.
188
+ $new_element = preg_replace( '# ' . $name . '\s*=\s*(["\'])[^"\']*?\1#is', " $name=$1$value$1", $element );
189
  if ( strpos( $new_element, "$name=" ) ) {
190
  $element = $new_element;
191
  return;
192
  }
193
+ $element = preg_replace( '# ' . $name . '\s*=\s*[^\s"\']+?#is', ' ', $element );
194
  }
195
  $closing = ' />';
196
  if ( false === strpos( $element, '/>' ) ) {
210
  * @param string $name The name of the attribute to remove.
211
  */
212
  function remove_attribute( &$element, $name ) {
213
+ // Don't forget, back references cannot be used in character classes.
214
+ $element = preg_replace( '# ' . $name . '\s*=\s*(["\'])[^"\']+?\1#is', ' ', $element );
215
+ $element = preg_replace( '# ' . $name . '\s*=\s*[^\s"\']+?#is', ' ', $element );
216
+ }
217
+
218
+ /**
219
+ * Remove the background image URL from a style attribute.
220
+ *
221
+ * @param string $attribute The element's style attribute to modify.
222
+ * @return string The style attribute with any image url removed.
223
+ */
224
+ function remove_background_image( $attribute ) {
225
+ if ( false !== strpos( $attribute, 'background:' ) && false !== strpos( $attribute, 'url(' ) ) {
226
+ $attribute = preg_replace( '#\s?url\([^)]+\)#', '', $attribute );
227
+ }
228
+ if ( false !== strpos( $attribute, 'background-image:' ) && false !== strpos( $attribute, 'url(' ) ) {
229
+ $attribute = preg_replace( '#background-image:\s*url\([^)]+\);?#', '', $attribute );
230
+ }
231
+ return $attribute;
232
  }
233
 
234
  /**
classes/class-ewwwio-relative-migration.php CHANGED
@@ -49,7 +49,7 @@ class EWWWIO_Relative_Migration {
49
  * Retrieves a batch of records based on the current offset.
50
  */
51
  private function get_records() {
52
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
53
  global $wpdb;
54
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
55
  ewww_image_optimizer_db_init();
@@ -71,7 +71,7 @@ class EWWWIO_Relative_Migration {
71
  * Called via wp_cron to initiate the migration effort.
72
  */
73
  public function migrate() {
74
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
75
  $this->started = time();
76
  $this->offset = (int) get_option( 'ewww_image_optimizer_relative_migration_offset' );
77
  $records = $this->get_records();
@@ -124,7 +124,7 @@ class EWWWIO_Relative_Migration {
124
  * @param array $record Includes a relative path, the ID, and the updated timestamp.
125
  */
126
  private function update_relative_record( $record ) {
127
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
128
  global $wpdb;
129
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
130
  ewww_image_optimizer_db_init();
@@ -148,7 +148,7 @@ class EWWWIO_Relative_Migration {
148
  * Schedule the migration.
149
  */
150
  private function maybe_schedule() {
151
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
152
  // Create 5 minute wp_cron schedule.
153
  add_filter( 'cron_schedules', array( $this, 'add_migration_schedule' ) );
154
  add_action( 'ewww_image_optimizer_relative_migration', array( $this, 'migrate' ) );
@@ -162,7 +162,7 @@ class EWWWIO_Relative_Migration {
162
  * Clean up the scheduled event.
163
  */
164
  private function unschedule() {
165
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
166
  $timestamp = wp_next_scheduled( 'ewww_image_optimizer_relative_migration' );
167
  if ( $timestamp ) {
168
  wp_unschedule_event( $timestamp, 'ewww_image_optimizer_relative_migration' );
@@ -176,7 +176,7 @@ class EWWWIO_Relative_Migration {
176
  * @param array $schedules An array of custom cron schedules.
177
  */
178
  public function add_migration_schedule( $schedules ) {
179
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
180
  $schedules['ewwwio_relative_migration_interval'] = array(
181
  'interval' => MINUTE_IN_SECONDS * 5,
182
  'display' => 'Every 5 Minutes',
49
  * Retrieves a batch of records based on the current offset.
50
  */
51
  private function get_records() {
52
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
53
  global $wpdb;
54
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
55
  ewww_image_optimizer_db_init();
71
  * Called via wp_cron to initiate the migration effort.
72
  */
73
  public function migrate() {
74
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
75
  $this->started = time();
76
  $this->offset = (int) get_option( 'ewww_image_optimizer_relative_migration_offset' );
77
  $records = $this->get_records();
124
  * @param array $record Includes a relative path, the ID, and the updated timestamp.
125
  */
126
  private function update_relative_record( $record ) {
127
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
128
  global $wpdb;
129
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
130
  ewww_image_optimizer_db_init();
148
  * Schedule the migration.
149
  */
150
  private function maybe_schedule() {
151
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
152
  // Create 5 minute wp_cron schedule.
153
  add_filter( 'cron_schedules', array( $this, 'add_migration_schedule' ) );
154
  add_action( 'ewww_image_optimizer_relative_migration', array( $this, 'migrate' ) );
162
  * Clean up the scheduled event.
163
  */
164
  private function unschedule() {
165
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
166
  $timestamp = wp_next_scheduled( 'ewww_image_optimizer_relative_migration' );
167
  if ( $timestamp ) {
168
  wp_unschedule_event( $timestamp, 'ewww_image_optimizer_relative_migration' );
176
  * @param array $schedules An array of custom cron schedules.
177
  */
178
  public function add_migration_schedule( $schedules ) {
179
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
180
  $schedules['ewwwio_relative_migration_interval'] = array(
181
  'interval' => MINUTE_IN_SECONDS * 5,
182
  'display' => 'Every 5 Minutes',
classes/class-ewwwio-tracking.php CHANGED
@@ -57,7 +57,7 @@ class EWWWIO_Tracking {
57
  * @return void
58
  */
59
  private function setup_data() {
60
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
61
  $data = array();
62
 
63
  // Retrieve current theme info.
@@ -186,7 +186,7 @@ class EWWWIO_Tracking {
186
  if ( ! $this->tracking_allowed() && ! $override ) {
187
  return false;
188
  }
189
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
190
 
191
  // Send a maximum of once per week.
192
  $last_send = $this->get_last_send();
@@ -227,7 +227,7 @@ class EWWWIO_Tracking {
227
  * @return bool The unaltered setting.
228
  */
229
  public function check_for_settings_optin( $input ) {
230
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
231
  // Send an intial check in on settings save.
232
  if ( isset( $_POST['ewww_image_optimizer_allow_tracking'] ) && $_POST['ewww_image_optimizer_allow_tracking'] ) {
233
  $this->send_checkin( true );
@@ -240,7 +240,7 @@ class EWWWIO_Tracking {
240
  * Check for a new opt-in via the admin notice
241
  */
242
  public function check_for_optin() {
243
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
244
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_allow_tracking', 1 );
245
  $this->send_checkin( true );
246
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_tracking_notice', 1 );
@@ -252,7 +252,7 @@ class EWWWIO_Tracking {
252
  * Check for a new opt-out via the admin notice
253
  */
254
  public function check_for_optout() {
255
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
256
  delete_option( 'ewww_image_optimizer_allow_tracking' );
257
  delete_network_option( null, 'ewww_image_optimizer_allow_tracking' );
258
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_tracking_notice', 1 );
@@ -267,7 +267,7 @@ class EWWWIO_Tracking {
267
  * @return false|string
268
  */
269
  private function get_last_send() {
270
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
271
  return ewww_image_optimizer_get_option( 'ewww_image_optimizer_tracking_last_send' );
272
  }
273
 
@@ -275,7 +275,7 @@ class EWWWIO_Tracking {
275
  * Schedule a weekly checkin.
276
  */
277
  public function schedule_send() {
278
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
279
  if ( is_multisite() ) {
280
  if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
281
  // Need to include the plugin library for the is_plugin_active function.
@@ -335,7 +335,7 @@ class EWWWIO_Tracking {
335
  if ( ! current_user_can( 'manage_options' ) ) {
336
  return;
337
  }
338
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
339
 
340
  if ( ! function_exists( 'is_plugin_active_for_network' ) && is_multisite() ) {
341
  // Need to include the plugin library for the is_plugin_active function.
57
  * @return void
58
  */
59
  private function setup_data() {
60
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
61
  $data = array();
62
 
63
  // Retrieve current theme info.
186
  if ( ! $this->tracking_allowed() && ! $override ) {
187
  return false;
188
  }
189
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
190
 
191
  // Send a maximum of once per week.
192
  $last_send = $this->get_last_send();
227
  * @return bool The unaltered setting.
228
  */
229
  public function check_for_settings_optin( $input ) {
230
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
231
  // Send an intial check in on settings save.
232
  if ( isset( $_POST['ewww_image_optimizer_allow_tracking'] ) && $_POST['ewww_image_optimizer_allow_tracking'] ) {
233
  $this->send_checkin( true );
240
  * Check for a new opt-in via the admin notice
241
  */
242
  public function check_for_optin() {
243
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
244
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_allow_tracking', 1 );
245
  $this->send_checkin( true );
246
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_tracking_notice', 1 );
252
  * Check for a new opt-out via the admin notice
253
  */
254
  public function check_for_optout() {
255
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
256
  delete_option( 'ewww_image_optimizer_allow_tracking' );
257
  delete_network_option( null, 'ewww_image_optimizer_allow_tracking' );
258
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_tracking_notice', 1 );
267
  * @return false|string
268
  */
269
  private function get_last_send() {
270
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
271
  return ewww_image_optimizer_get_option( 'ewww_image_optimizer_tracking_last_send' );
272
  }
273
 
275
  * Schedule a weekly checkin.
276
  */
277
  public function schedule_send() {
278
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
279
  if ( is_multisite() ) {
280
  if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
281
  // Need to include the plugin library for the is_plugin_active function.
335
  if ( ! current_user_can( 'manage_options' ) ) {
336
  return;
337
  }
338
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
339
 
340
  if ( ! function_exists( 'is_plugin_active_for_network' ) && is_multisite() ) {
341
  // Need to include the plugin library for the is_plugin_active function.
classes/class-exactdn.php CHANGED
@@ -114,7 +114,7 @@ class ExactDN extends EWWWIO_Page_Parser {
114
  * Register (once) actions and filters for ExactDN. If you want to use this class, use the global.
115
  */
116
  function __construct() {
117
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
118
  global $exactdn;
119
  if ( is_object( $exactdn ) ) {
120
  return 'you are doing it wrong';
@@ -137,7 +137,8 @@ class ExactDN extends EWWWIO_Page_Parser {
137
  // Images in post content and galleries.
138
  add_filter( 'the_content', array( $this, 'filter_the_content' ), 999999 );
139
  // Start an output buffer before any output starts.
140
- add_action( 'template_redirect', array( $this, 'buffer_start' ), 1 );
 
141
 
142
  // Core image retrieval.
143
  if ( ! function_exists( 'aq_resize' ) ) {
@@ -147,7 +148,7 @@ class ExactDN extends EWWWIO_Page_Parser {
147
  }
148
  // Disable image_downsize filter during themify_get_image().
149
  add_action( 'themify_before_post_image', array( $this, 'disable_image_downsize' ) );
150
- if ( ewww_image_optimizer_get_option( 'exactdn_image_downsize_scale' ) ) {
151
  add_action( 'exactdn_image_downsize_array', array( $this, 'image_downsize_scale' ) );
152
  }
153
 
@@ -170,8 +171,11 @@ class ExactDN extends EWWWIO_Page_Parser {
170
  add_filter( 'ngg_pro_lightbox_images_queue', array( $this, 'ngg_pro_lightbox_images_queue' ) );
171
  add_filter( 'ngg_get_image_url', array( $this, 'ngg_get_image_url' ) );
172
 
 
 
 
173
  // DNS prefetching.
174
- add_action( 'wp_head', array( $this, 'dns_prefetch' ) );
175
 
176
  // Get all the script/css urls and rewrite them (if enabled).
177
  if ( ewww_image_optimizer_get_option( 'exactdn_all_the_things' ) ) {
@@ -179,6 +183,12 @@ class ExactDN extends EWWWIO_Page_Parser {
179
  add_filter( 'script_loader_src', array( $this, 'parse_enqueue' ), 20 );
180
  }
181
 
 
 
 
 
 
 
182
  // Configure Autoptimize with our CDN domain.
183
  add_filter( 'autoptimize_filter_cssjs_multidomain', array( $this, 'autoptimize_cdn_url' ) );
184
  if ( defined( 'AUTOPTIMIZE_PLUGIN_DIR' ) ) {
@@ -246,7 +256,7 @@ class ExactDN extends EWWWIO_Page_Parser {
246
  * If ExactDN is enabled, validates and configures the ExactDN domain name.
247
  */
248
  function setup() {
249
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
250
  // If we don't have a domain yet, go grab one.
251
  if ( ! $this->get_exactdn_domain() ) {
252
  ewwwio_debug_message( 'attempting to activate exactDN' );
@@ -298,7 +308,7 @@ class ExactDN extends EWWWIO_Page_Parser {
298
  * Use the Site URL to get the zone domain.
299
  */
300
  function activate_site() {
301
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
302
  $s3_active = false;
303
  if ( class_exists( 'Amazon_S3_And_CloudFront' ) ) {
304
  global $as3cf;
@@ -342,6 +352,10 @@ class ExactDN extends EWWWIO_Page_Parser {
342
  if ( strpos( $site_url, 'amazonaws.com' ) || strpos( $site_url, 'digitaloceanspaces.com' ) ) {
343
  $this->set_exactdn_option( 'verify_method', -1, false );
344
  }
 
 
 
 
345
  return $this->set_exactdn_domain( $response['domain'] );
346
  }
347
  } elseif ( ! empty( $result['body'] ) && strpos( $result['body'], 'error' ) !== false ) {
@@ -363,7 +377,7 @@ class ExactDN extends EWWWIO_Page_Parser {
363
  if ( empty( $domain ) ) {
364
  return false;
365
  }
366
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
367
  // Check the time, to see how long it has been since we verified the domain.
368
  $last_checkin = $this->get_exactdn_option( 'checkin' );
369
  if ( ! empty( $last_checkin ) && $last_checkin > time() ) {
@@ -451,7 +465,7 @@ class ExactDN extends EWWWIO_Page_Parser {
451
  */
452
  function check_verify_method() {
453
  if ( ! $this->get_exactdn_option( 'verify_method' ) ) {
454
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
455
  // Prelim test with a known valid image to ensure http(s) connectivity.
456
  $sim_url = 'https://optimize.exactdn.com/exactdn/testorig.jpg';
457
  add_filter( 'http_headers_useragent', 'ewww_image_optimizer_cloud_useragent', PHP_INT_MAX );
@@ -478,7 +492,7 @@ class ExactDN extends EWWWIO_Page_Parser {
478
  * @return string The validated ExactDN domain.
479
  */
480
  function sanitize_domain( $domain ) {
481
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
482
  if ( ! $domain ) {
483
  return;
484
  }
@@ -534,7 +548,7 @@ class ExactDN extends EWWWIO_Page_Parser {
534
  * @param string $domain The ExactDN domain name for this site or network.
535
  */
536
  function set_exactdn_domain( $domain ) {
537
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
538
  if ( defined( 'EXACTDN_DOMAIN' ) && $this->sanitize_domain( EXACTDN_DOMAIN ) ) {
539
  return true;
540
  }
@@ -560,7 +574,7 @@ class ExactDN extends EWWWIO_Page_Parser {
560
  * @param bool $autoload Optional. Whether to load the option when WordPress starts up.
561
  */
562
  function set_exactdn_option( $option_name, $option_value, $autoload = null ) {
563
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
564
  if ( defined( 'EXACTDN_DOMAIN' ) && EXACTDN_DOMAIN ) {
565
  return update_option( 'ewww_image_optimizer_exactdn_' . $option_name, $option_value, $autoload );
566
  }
@@ -600,13 +614,16 @@ class ExactDN extends EWWWIO_Page_Parser {
600
  * @return bool|string The content width, if set. Default false.
601
  */
602
  function get_content_width() {
603
- $content_width = isset( $GLOBALS['content_width'] ) ? $GLOBALS['content_width'] : 1920;
 
 
 
604
  /**
605
  * Filter the Content Width value.
606
  *
607
  * @param string $content_width Content Width value.
608
  */
609
- return apply_filters( 'exactdn_content_width', $content_width );
610
  }
611
 
612
  /**
@@ -657,7 +674,7 @@ class ExactDN extends EWWWIO_Page_Parser {
657
  * Starts an output buffer and registers the callback function to do ExactDN url replacement.
658
  */
659
  function buffer_start() {
660
- ob_start( array( $this, 'filter_the_page' ) );
661
  }
662
 
663
  /**
@@ -666,7 +683,8 @@ class ExactDN extends EWWWIO_Page_Parser {
666
  * @param string $content The page/post content.
667
  * @return string The content with ExactDN image urls.
668
  */
669
- function filter_the_page( $content ) {
 
670
  $this->filtering_the_page = true;
671
 
672
  $content = $this->filter_the_content( $content );
@@ -691,7 +709,7 @@ class ExactDN extends EWWWIO_Page_Parser {
691
  */
692
  function filter_the_content( $content ) {
693
  $started = microtime( true );
694
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
695
  $images = $this->get_images_from_html( $content, true );
696
 
697
  if ( ! empty( $images ) ) {
@@ -738,6 +756,11 @@ class ExactDN extends EWWWIO_Page_Parser {
738
 
739
  ewwwio_debug_message( 'made it passed the filters' );
740
 
 
 
 
 
 
741
  // Pre-empt srcset fill if the surrounding link has a background image or if there is a data-desktop attribute indicating a potential slider.
742
  if ( strpos( $tag, 'background-image:' ) || strpos( $tag, 'data-desktop=' ) ) {
743
  $srcset_fill = false;
@@ -798,7 +821,12 @@ class ExactDN extends EWWWIO_Page_Parser {
798
  }
799
 
800
  // Check for relative urls that start with a slash. Unlikely that we'll attempt relative urls beyond that.
801
- if ( '/' === substr( $src, 0, 1 ) && '/' !== substr( $src, 1, 1 ) && false === strpos( $this->upload_domain, 'amazonaws.com' ) && false === strpos( $this->upload_domain, 'digitaloceanspaces.com' ) ) {
 
 
 
 
 
802
  $src = '//' . $this->upload_domain . $src;
803
  }
804
 
@@ -906,23 +934,28 @@ class ExactDN extends EWWWIO_Page_Parser {
906
  }
907
  }
908
  }
909
-
 
 
 
 
 
910
  // If width is available, constrain to $content_width.
911
- if ( false !== $width && false === strpos( $width, '%' ) && is_numeric( $content_width ) ) {
912
- if ( $width > $content_width && false !== $height && false === strpos( $height, '%' ) ) {
913
  ewwwio_debug_message( 'constraining to content width' );
914
- $height = round( ( $content_width * $height ) / $width );
915
- $width = $content_width;
916
- } elseif ( $width > $content_width ) {
917
  ewwwio_debug_message( 'constraining to content width' );
918
- $width = $content_width;
919
  }
920
  }
921
 
922
  // Set a width if none is found and $content_width is available.
923
  // If width is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing.
924
- if ( false === $width && is_numeric( $content_width ) ) {
925
- $width = (int) $content_width;
926
 
927
  if ( false !== $height ) {
928
  $transform = 'fit';
@@ -1002,9 +1035,20 @@ class ExactDN extends EWWWIO_Page_Parser {
1002
  }
1003
  }
1004
 
1005
- // Supplant the original source value with our ExactDN URL.
 
 
 
 
 
 
 
 
 
1006
  $exactdn_url = str_replace( '&#038;', '&', esc_url( $exactdn_url ) );
1007
- $new_tag = str_replace( $src_orig, $exactdn_url, $new_tag );
 
 
1008
 
1009
  // If Lazy Load is in use, pass placeholder image through ExactDN.
1010
  if ( isset( $placeholder_src ) && $this->validate_image_url( $placeholder_src ) ) {
@@ -1019,6 +1063,11 @@ class ExactDN extends EWWWIO_Page_Parser {
1019
 
1020
  // Replace original tag with modified version.
1021
  $content = str_replace( $tag, $new_tag, $content );
 
 
 
 
 
1022
  }
1023
  } elseif ( ! $lazy && $this->validate_image_url( $src, true ) ) {
1024
  ewwwio_debug_message( "found a potential exactdn src url to insert into srcset: $src" );
@@ -1123,6 +1172,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1123
  $content = str_replace( '?wpcontent-bypass?', 'wp-content', $content );
1124
  }
1125
  }
 
1126
  ewwwio_debug_message( 'done parsing page' );
1127
  $this->filtering_the_content = false;
1128
 
@@ -1136,6 +1186,61 @@ class ExactDN extends EWWWIO_Page_Parser {
1136
  return $content;
1137
  }
1138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1139
  /**
1140
  * Allow resizing of images for some admin-ajax requests.
1141
  *
@@ -1156,6 +1261,9 @@ class ExactDN extends EWWWIO_Page_Parser {
1156
  if ( ! empty( $_POST['action'] ) && 'Essential_Grid_Front_request_ajax' == $_POST['action'] ) {
1157
  return true;
1158
  }
 
 
 
1159
  return $allow;
1160
  }
1161
 
@@ -1207,7 +1315,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1207
  */
1208
  function filter_image_downsize( $image, $attachment_id, $size ) {
1209
  $started = microtime( true );
1210
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1211
 
1212
  // Don't foul up the admin side of things, unless a plugin wants to.
1213
  if ( is_admin() &&
@@ -1287,6 +1395,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1287
  if ( is_string( $size ) && array_key_exists( $size, $this->image_sizes() ) ) {
1288
  $image_args = $this->image_sizes();
1289
  $image_args = $image_args[ $size ];
 
1290
 
1291
  $exactdn_args = array();
1292
 
@@ -1297,6 +1406,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1297
  $image_meta = wp_get_attachment_metadata( $attachment_id );
1298
  $intermediate = false;
1299
  } elseif ( ! $image_meta ) {
 
1300
  // If we still don't have any image meta at this point, it's probably from a custom thumbnail size
1301
  // for an image that was uploaded before the custom image was added to the theme. Try to determine the size manually.
1302
  $image_meta = wp_get_attachment_metadata( $attachment_id );
@@ -1309,14 +1419,15 @@ class ExactDN extends EWWWIO_Page_Parser {
1309
  }
1310
  }
1311
  }
1312
-
1313
  if ( isset( $image_meta['width'], $image_meta['height'] ) ) {
1314
  $image_args['width'] = $image_meta['width'];
1315
  $image_args['height'] = $image_meta['height'];
1316
 
 
1317
  list( $image_args['width'], $image_args['height'] ) = image_constrain_size_for_editor( $image_args['width'], $image_args['height'], $size, 'display' );
1318
 
1319
  $has_size_meta = true;
 
1320
  }
1321
 
1322
  $transform = $image_args['crop'] ? 'resize' : 'fit';
@@ -1332,6 +1443,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1332
  if ( ! isset( $image_meta['sizes'] ) ) {
1333
  $size_meta = $image_meta;
1334
  // Because we don't have the "real" meta, just the height/width for the specific size.
 
1335
  $image_meta = wp_get_attachment_metadata( $attachment_id );
1336
  }
1337
  if ( 'resize' === $transform && $image_meta && isset( $image_meta['width'], $image_meta['height'] ) ) {
@@ -1345,6 +1457,14 @@ class ExactDN extends EWWWIO_Page_Parser {
1345
  }
1346
  }
1347
 
 
 
 
 
 
 
 
 
1348
  if ( empty( $image_meta['sizes'] ) && ! empty( $size_meta ) ) {
1349
  $image_meta['sizes'][ $size ] = $size_meta;
1350
  }
@@ -1477,7 +1597,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1477
  */
1478
  public function filter_srcset_array( $sources = array(), $size_array = array(), $image_src = '', $image_meta = array(), $attachment_id = 0 ) {
1479
  $started = microtime( true );
1480
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1481
  // Don't foul up the admin side of things, unless a plugin wants to.
1482
  if ( is_admin() &&
1483
  /**
@@ -1567,7 +1687,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1567
  *
1568
  * @param array|bool $multipliers Array of multipliers to use or false to bypass.
1569
  */
1570
- $multipliers = apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1, 2, 3 ) );
1571
  $url = trailingslashit( $upload_dir['baseurl'] ) . $image_meta['file'];
1572
 
1573
  if (
@@ -1611,6 +1731,9 @@ class ExactDN extends EWWWIO_Page_Parser {
1611
  foreach ( $multipliers as $multiplier ) {
1612
 
1613
  $newwidth = intval( $base * $multiplier );
 
 
 
1614
  if ( $newwidth < 50 ) {
1615
  continue;
1616
  }
@@ -1666,7 +1789,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1666
  */
1667
  public function filter_sizes( $sizes, $size ) {
1668
  $started = microtime( true );
1669
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1670
  if ( ! doing_filter( 'the_content' ) ) {
1671
  return $sizes;
1672
  }
@@ -1693,7 +1816,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1693
  * @return string A srcset attribute with ExactDN image urls and widths.
1694
  */
1695
  public function generate_image_srcset( $url, $width, $zoom = false, $filename_width = false ) {
1696
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1697
  // Don't foul up the admin side of things.
1698
  if ( is_admin() ) {
1699
  return '';
@@ -1709,7 +1832,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1709
  *
1710
  * @param array|bool $multipliers Array of multipliers to use or false to bypass.
1711
  */
1712
- $multipliers = apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1, 2, 3 ) );
1713
  /**
1714
  * Filter the width ExactDN will use to create srcset attribute.
1715
  * Return a falsy value to short-circuit and bypass srcset fill.
@@ -1734,6 +1857,9 @@ class ExactDN extends EWWWIO_Page_Parser {
1734
 
1735
  foreach ( $multipliers as $multiplier ) {
1736
  $newwidth = intval( $width * $multiplier );
 
 
 
1737
  if ( $newwidth < 50 ) {
1738
  continue;
1739
  }
@@ -1787,7 +1913,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1787
  * @return array The arguments, possibly altered for smart cropping.
1788
  */
1789
  function maybe_smart_crop( $args, $attachment_id, $meta = false ) {
1790
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1791
  if ( ! empty( $args['crop'] ) ) {
1792
  ewwwio_debug_message( 'already cropped' );
1793
  return $args;
@@ -1865,7 +1991,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1865
  * @return WP_HTTP_Response The result, unaltered.
1866
  */
1867
  function parse_restapi_maybe( $response, $handler, $request ) {
1868
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1869
  if ( ! is_a( $request, 'WP_REST_Request' ) ) {
1870
  ewwwio_debug_message( 'oddball REST request or handler' );
1871
  return $response; // Something isn't right, bail.
@@ -1911,7 +2037,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1911
  * @return bool True if the url is considerd valid, false otherwise.
1912
  */
1913
  protected function validate_image_url( $url, $exactdn_is_valid = false ) {
1914
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1915
  $parsed_url = $this->parse_url( $url );
1916
  if ( ! $parsed_url ) {
1917
  ewwwio_debug_message( 'could not parse' );
@@ -1998,7 +2124,7 @@ class ExactDN extends EWWWIO_Page_Parser {
1998
  * @return string The possibly altered URL without dimensions.
1999
  **/
2000
  protected function strip_image_dimensions_maybe( $src ) {
2001
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
2002
  $stripped_src = $src;
2003
 
2004
  // Build URL, first removing WP's resized string so we pass the original image to ExactDN.
@@ -2026,7 +2152,7 @@ class ExactDN extends EWWWIO_Page_Parser {
2026
  * @return array
2027
  */
2028
  protected function image_sizes() {
2029
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
2030
  if ( null == self::$image_sizes ) {
2031
  global $_wp_additional_image_sizes;
2032
 
@@ -2075,7 +2201,7 @@ class ExactDN extends EWWWIO_Page_Parser {
2075
  * @return array The ExactDNified array of images.
2076
  */
2077
  function ngg_pro_lightbox_images_queue( $images ) {
2078
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
2079
  if ( ewww_image_optimizer_iterable( $images ) ) {
2080
  foreach ( $images as $index => $image ) {
2081
  if ( ! empty( $image['image'] ) && $this->validate_image_url( $image['image'] ) ) {
@@ -2130,13 +2256,28 @@ class ExactDN extends EWWWIO_Page_Parser {
2130
  ) {
2131
  return $image;
2132
  }
2133
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
2134
  if ( $this->validate_image_url( $image ) ) {
2135
  return $this->generate_url( $image );
2136
  }
2137
  return $image;
2138
  }
2139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2140
  /**
2141
  * Enqueue ExactDN helper script
2142
  */
@@ -2156,10 +2297,13 @@ class ExactDN extends EWWWIO_Page_Parser {
2156
  if ( strpos( $image_url, 'revslider/admin/assets/images/dummy.png' ) ) {
2157
  return array();
2158
  }
 
 
 
2159
  if ( strpos( $image_url, 'lazy_placeholder.gif' ) ) {
2160
  return array();
2161
  }
2162
- if ( strpos( $image_url, 'essential-grid/public/assets/images/' ) ) {
2163
  return array();
2164
  }
2165
  if ( strpos( $image_url, 'LayerSlider/static/img' ) ) {
@@ -2205,7 +2349,7 @@ class ExactDN extends EWWWIO_Page_Parser {
2205
  if ( is_admin() ) {
2206
  return $url;
2207
  }
2208
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
2209
  $parsed_url = $this->parse_url( $url );
2210
 
2211
  if ( false !== strpos( $url, 'wp-admin/' ) ) {
@@ -2235,6 +2379,11 @@ class ExactDN extends EWWWIO_Page_Parser {
2235
  return $url;
2236
  }
2237
 
 
 
 
 
 
2238
  // Make sure this is an allowed image domain/hostname for ExactDN on this site.
2239
  if ( ! $this->allow_image_domain( $parsed_url['host'] ) ) {
2240
  ewwwio_debug_message( "invalid host for ExactDN: {$parsed_url['host']}" );
@@ -2285,7 +2434,7 @@ class ExactDN extends EWWWIO_Page_Parser {
2285
  * @return string The raw final URL. You should run this through esc_url() before displaying it.
2286
  */
2287
  function generate_url( $image_url, $args = array(), $scheme = null ) {
2288
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
2289
  $image_url = trim( $image_url );
2290
 
2291
  if ( is_null( $scheme ) ) {
@@ -2448,7 +2597,7 @@ class ExactDN extends EWWWIO_Page_Parser {
2448
  * @return string Result of parse_url.
2449
  */
2450
  function url_scheme( $url, $scheme ) {
2451
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
2452
  if ( ! in_array( $scheme, array( 'http', 'https' ) ) ) {
2453
  ewwwio_debug_message( 'not a valid scheme' );
2454
  if ( preg_match( '#^(https?:)?//#', $url ) ) {
@@ -2502,12 +2651,16 @@ class ExactDN extends EWWWIO_Page_Parser {
2502
 
2503
  /**
2504
  * Adds link to header which enables DNS prefetching for faster speed.
 
 
 
 
2505
  */
2506
- function dns_prefetch() {
2507
- if ( $this->exactdn_domain ) {
2508
- echo "\r\n";
2509
- printf( "<link rel='dns-prefetch' href='%s'>\r\n", '//' . esc_attr( $this->exactdn_domain ) );
2510
  }
 
2511
  }
2512
 
2513
  /**
@@ -2517,7 +2670,7 @@ class ExactDN extends EWWWIO_Page_Parser {
2517
  * @return array The same list, with the ExactDN domain appended.
2518
  */
2519
  function autoptimize_cdn_url( $domains ) {
2520
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
2521
  if ( is_array( $domains ) && ! in_array( $this->exactdn_domain, $domains ) ) {
2522
  ewwwio_debug_message( 'adding to AO list: ' . $this->exactdn_domain );
2523
  $domains[] = $this->exactdn_domain;
114
  * Register (once) actions and filters for ExactDN. If you want to use this class, use the global.
115
  */
116
  function __construct() {
117
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
118
  global $exactdn;
119
  if ( is_object( $exactdn ) ) {
120
  return 'you are doing it wrong';
137
  // Images in post content and galleries.
138
  add_filter( 'the_content', array( $this, 'filter_the_content' ), 999999 );
139
  // Start an output buffer before any output starts.
140
+ /* add_action( 'template_redirect', array( $this, 'buffer_start' ), 2 ); */
141
+ add_filter( 'ewww_image_optimizer_filter_page_output', array( $this, 'filter_page_output' ), 5 );
142
 
143
  // Core image retrieval.
144
  if ( ! function_exists( 'aq_resize' ) ) {
148
  }
149
  // Disable image_downsize filter during themify_get_image().
150
  add_action( 'themify_before_post_image', array( $this, 'disable_image_downsize' ) );
151
+ if ( defined( 'EXACTDN_IMAGE_DOWNSIZE_SCALE' ) && EXACTDN_IMAGE_DOWNSIZE_SCALE ) {
152
  add_action( 'exactdn_image_downsize_array', array( $this, 'image_downsize_scale' ) );
153
  }
154
 
171
  add_filter( 'ngg_pro_lightbox_images_queue', array( $this, 'ngg_pro_lightbox_images_queue' ) );
172
  add_filter( 'ngg_get_image_url', array( $this, 'ngg_get_image_url' ) );
173
 
174
+ // Filter for legacy WooCommerce API endpoints.
175
+ add_filter( 'woocommerce_api_product_response', array( $this, 'woocommerce_api_product_response' ) );
176
+
177
  // DNS prefetching.
178
+ add_filter( 'wp_resource_hints', array( $this, 'dns_prefetch' ), 10, 2 );
179
 
180
  // Get all the script/css urls and rewrite them (if enabled).
181
  if ( ewww_image_optimizer_get_option( 'exactdn_all_the_things' ) ) {
183
  add_filter( 'script_loader_src', array( $this, 'parse_enqueue' ), 20 );
184
  }
185
 
186
+ // Improve the default content_width for Twenty Nineteen.
187
+ global $content_width;
188
+ if ( function_exists( 'twentynineteen_setup' ) && 640 == $content_width ) {
189
+ $content_width = 932;
190
+ }
191
+
192
  // Configure Autoptimize with our CDN domain.
193
  add_filter( 'autoptimize_filter_cssjs_multidomain', array( $this, 'autoptimize_cdn_url' ) );
194
  if ( defined( 'AUTOPTIMIZE_PLUGIN_DIR' ) ) {
256
  * If ExactDN is enabled, validates and configures the ExactDN domain name.
257
  */
258
  function setup() {
259
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
260
  // If we don't have a domain yet, go grab one.
261
  if ( ! $this->get_exactdn_domain() ) {
262
  ewwwio_debug_message( 'attempting to activate exactDN' );
308
  * Use the Site URL to get the zone domain.
309
  */
310
  function activate_site() {
311
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
312
  $s3_active = false;
313
  if ( class_exists( 'Amazon_S3_And_CloudFront' ) ) {
314
  global $as3cf;
352
  if ( strpos( $site_url, 'amazonaws.com' ) || strpos( $site_url, 'digitaloceanspaces.com' ) ) {
353
  $this->set_exactdn_option( 'verify_method', -1, false );
354
  }
355
+ if ( get_option( 'exactdn_never_been_active' ) ) {
356
+ ewww_image_optimizer_set_option( 'ewww_image_optimizer_lazy_load', true );
357
+ delete_option( 'exactdn_never_been_active' );
358
+ }
359
  return $this->set_exactdn_domain( $response['domain'] );
360
  }
361
  } elseif ( ! empty( $result['body'] ) && strpos( $result['body'], 'error' ) !== false ) {
377
  if ( empty( $domain ) ) {
378
  return false;
379
  }
380
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
381
  // Check the time, to see how long it has been since we verified the domain.
382
  $last_checkin = $this->get_exactdn_option( 'checkin' );
383
  if ( ! empty( $last_checkin ) && $last_checkin > time() ) {
465
  */
466
  function check_verify_method() {
467
  if ( ! $this->get_exactdn_option( 'verify_method' ) ) {
468
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
469
  // Prelim test with a known valid image to ensure http(s) connectivity.
470
  $sim_url = 'https://optimize.exactdn.com/exactdn/testorig.jpg';
471
  add_filter( 'http_headers_useragent', 'ewww_image_optimizer_cloud_useragent', PHP_INT_MAX );
492
  * @return string The validated ExactDN domain.
493
  */
494
  function sanitize_domain( $domain ) {
495
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
496
  if ( ! $domain ) {
497
  return;
498
  }
548
  * @param string $domain The ExactDN domain name for this site or network.
549
  */
550
  function set_exactdn_domain( $domain ) {
551
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
552
  if ( defined( 'EXACTDN_DOMAIN' ) && $this->sanitize_domain( EXACTDN_DOMAIN ) ) {
553
  return true;
554
  }
574
  * @param bool $autoload Optional. Whether to load the option when WordPress starts up.
575
  */
576
  function set_exactdn_option( $option_name, $option_value, $autoload = null ) {
577
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
578
  if ( defined( 'EXACTDN_DOMAIN' ) && EXACTDN_DOMAIN ) {
579
  return update_option( 'ewww_image_optimizer_exactdn_' . $option_name, $option_value, $autoload );
580
  }
614
  * @return bool|string The content width, if set. Default false.
615
  */
616
  function get_content_width() {
617
+ $content_width = isset( $GLOBALS['content_width'] ) && is_numeric( $GLOBALS['content_width'] ) ? $GLOBALS['content_width'] : 1920;
618
+ if ( function_exists( 'twentynineteen_setup' ) && 640 == $content_width ) {
619
+ $content_width = 932;
620
+ }
621
  /**
622
  * Filter the Content Width value.
623
  *
624
  * @param string $content_width Content Width value.
625
  */
626
+ return (int) apply_filters( 'exactdn_content_width', $content_width );
627
  }
628
 
629
  /**
674
  * Starts an output buffer and registers the callback function to do ExactDN url replacement.
675
  */
676
  function buffer_start() {
677
+ ob_start( array( $this, 'filter_page_output' ) );
678
  }
679
 
680
  /**
683
  * @param string $content The page/post content.
684
  * @return string The content with ExactDN image urls.
685
  */
686
+ function filter_page_output( $content ) {
687
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
688
  $this->filtering_the_page = true;
689
 
690
  $content = $this->filter_the_content( $content );
709
  */
710
  function filter_the_content( $content ) {
711
  $started = microtime( true );
712
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
713
  $images = $this->get_images_from_html( $content, true );
714
 
715
  if ( ! empty( $images ) ) {
756
 
757
  ewwwio_debug_message( 'made it passed the filters' );
758
 
759
+ // Log 0-size Pinterest schema images.
760
+ if ( strpos( $tag, 'data-pin-description=' ) && strpos( $tag, 'width="0" height="0"' ) ) {
761
+ ewwwio_debug_message( 'data-pin/Pinterest image' );
762
+ }
763
+
764
  // Pre-empt srcset fill if the surrounding link has a background image or if there is a data-desktop attribute indicating a potential slider.
765
  if ( strpos( $tag, 'background-image:' ) || strpos( $tag, 'data-desktop=' ) ) {
766
  $srcset_fill = false;
821
  }
822
 
823
  // Check for relative urls that start with a slash. Unlikely that we'll attempt relative urls beyond that.
824
+ if (
825
+ '/' === substr( $src, 0, 1 ) &&
826
+ '/' !== substr( $src, 1, 1 ) &&
827
+ false === strpos( $this->upload_domain, 'amazonaws.com' ) &&
828
+ false === strpos( $this->upload_domain, 'digitaloceanspaces.com' )
829
+ ) {
830
  $src = '//' . $this->upload_domain . $src;
831
  }
832
 
934
  }
935
  }
936
  }
937
+ $constrain_width = (int) $content_width;
938
+ if ( ! empty( $images['figure_class'][ $index ] ) && false !== strpos( $images['figure_class'][ $index ], 'alignfull' ) && current_theme_supports( 'align-wide' ) ) {
939
+ $constrain_width = (int) apply_filters( 'exactdn_full_align_image_width', max( 1920, $content_width ) );
940
+ } elseif ( ! empty( $images['figure_class'][ $index ] ) && false !== strpos( $images['figure_class'][ $index ], 'alignwide' ) && current_theme_supports( 'align-wide' ) ) {
941
+ $constrain_width = (int) apply_filters( 'exactdn_wide_align_image_width', max( 1500, $content_width ) );
942
+ }
943
  // If width is available, constrain to $content_width.
944
+ if ( false !== $width && false === strpos( $width, '%' ) && is_numeric( $constrain_width ) ) {
945
+ if ( $width > $constrain_width && false !== $height && false === strpos( $height, '%' ) ) {
946
  ewwwio_debug_message( 'constraining to content width' );
947
+ $height = round( ( $constrain_width * $height ) / $width );
948
+ $width = $constrain_width;
949
+ } elseif ( $width > $constrain_width ) {
950
  ewwwio_debug_message( 'constraining to content width' );
951
+ $width = $constrain_width;
952
  }
953
  }
954
 
955
  // Set a width if none is found and $content_width is available.
956
  // If width is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing.
957
+ if ( false === $width && is_numeric( $constrain_width ) ) {
958
+ $width = (int) $constrain_width;
959
 
960
  if ( false !== $height ) {
961
  $transform = 'fit';
1035
  }
1036
  }
1037
 
1038
+ // Check if content width pushed the respimg sizes attribute too far down.
1039
+ if ( ! empty( $constrain_width ) && $constrain_width != $content_width ) {
1040
+ $sizes_attr = $this->get_attribute( $new_tag, 'sizes' );
1041
+ $new_sizes_attr = str_replace( ' ' . $content_width . 'px', ' ' . $constrain_width . 'px', $sizes_attr );
1042
+ if ( $sizes_attr != $new_sizes_attr ) {
1043
+ $new_tag = str_replace( $sizes_attr, $new_sizes_attr, $new_tag );
1044
+ }
1045
+ }
1046
+
1047
+ // Cleanup ExactDN URL.
1048
  $exactdn_url = str_replace( '&#038;', '&', esc_url( $exactdn_url ) );
1049
+ // Supplant the original source value with our ExactDN URL.
1050
+ ewwwio_debug_message( "replacing $src_orig with $exactdn_url" );
1051
+ $new_tag = str_replace( $src_orig, $exactdn_url, $new_tag );
1052
 
1053
  // If Lazy Load is in use, pass placeholder image through ExactDN.
1054
  if ( isset( $placeholder_src ) && $this->validate_image_url( $placeholder_src ) ) {
1063
 
1064
  // Replace original tag with modified version.
1065
  $content = str_replace( $tag, $new_tag, $content );
1066
+ if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) && strpos( $content, $exactdn_url ) ) {
1067
+ ewwwio_debug_message( 'new image properly inserted' );
1068
+ } elseif ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
1069
+ ewwwio_debug_message( 'new url NOT found' );
1070
+ }
1071
  }
1072
  } elseif ( ! $lazy && $this->validate_image_url( $src, true ) ) {
1073
  ewwwio_debug_message( "found a potential exactdn src url to insert into srcset: $src" );
1172
  $content = str_replace( '?wpcontent-bypass?', 'wp-content', $content );
1173
  }
1174
  }
1175
+ $content = $this->filter_bg_images( $content );
1176
  ewwwio_debug_message( 'done parsing page' );
1177
  $this->filtering_the_content = false;
1178
 
1186
  return $content;
1187
  }
1188
 
1189
+ /**
1190
+ * Parse page content looking for elements with CSS background-image properties.
1191
+ *
1192
+ * @param string $content The HTML content of to parse.
1193
+ * @return string The filtered HTML content.
1194
+ */
1195
+ function filter_bg_images( $content ) {
1196
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
1197
+ $content_width = false;
1198
+ if ( ! $this->filtering_the_page ) {
1199
+ $content_width = $this->get_content_width();
1200
+ }
1201
+ ewwwio_debug_message( "content width is $content_width" );
1202
+ // Process background images on 'div' elements.
1203
+ $divs = $this->get_elements_from_html( $content, 'div' );
1204
+ if ( ewww_image_optimizer_iterable( $divs ) ) {
1205
+ foreach ( $divs as $index => $div ) {
1206
+ ewwwio_debug_message( 'parsing a div' );
1207
+ if ( false === strpos( $div, 'background:' ) && false === strpos( $div, 'background-image:' ) ) {
1208
+ continue;
1209
+ }
1210
+ $style = $this->get_attribute( $div, 'style' );
1211
+ if ( empty( $style ) ) {
1212
+ continue;
1213
+ }
1214
+ ewwwio_debug_message( "checking style attr for background-image: $style" );
1215
+ $bg_image_url = $this->get_background_image_url( $style );
1216
+ if ( $this->validate_image_url( $bg_image_url ) ) {
1217
+ /** This filter is already documented in class-exactdn.php */
1218
+ if ( apply_filters( 'exactdn_skip_image', false, $bg_image_url, $div ) ) {
1219
+ continue;
1220
+ }
1221
+ $args = array();
1222
+ $div_class = $this->get_attribute( $div, 'class' );
1223
+ if ( false !== strpos( $div_class, 'alignfull' ) && current_theme_supports( 'align-wide' ) ) {
1224
+ $args['w'] = apply_filters( 'exactdn_full_align_image_width', 1920 );
1225
+ } elseif ( false !== strpos( $div_class, 'alignwide' ) && current_theme_supports( 'align-wide' ) ) {
1226
+ $args['w'] = apply_filters( 'exactdn_wide_align_image_width', 1500 );
1227
+ } elseif ( $content_width ) {
1228
+ $args['w'] = $content_width;
1229
+ }
1230
+ $exactdn_bg_image_url = $this->generate_url( $bg_image_url, $args );
1231
+ if ( $bg_image_url !== $exactdn_bg_image_url ) {
1232
+ $new_style = str_replace( $bg_image_url, $exactdn_bg_image_url, $style );
1233
+ $div = str_replace( $style, $new_style, $div );
1234
+ }
1235
+ }
1236
+ if ( $div !== $divs[ $index ] ) {
1237
+ $content = str_replace( $divs[ $index ], $div, $content );
1238
+ }
1239
+ }
1240
+ }
1241
+ return $content;
1242
+ }
1243
+
1244
  /**
1245
  * Allow resizing of images for some admin-ajax requests.
1246
  *
1261
  if ( ! empty( $_POST['action'] ) && 'Essential_Grid_Front_request_ajax' == $_POST['action'] ) {
1262
  return true;
1263
  }
1264
+ if ( ! empty( $_POST['action'] ) && 'mabel-rpn-getnew-purchased-products' == $_POST['action'] ) {
1265
+ return true;
1266
+ }
1267
  return $allow;
1268
  }
1269
 
1315
  */
1316
  function filter_image_downsize( $image, $attachment_id, $size ) {
1317
  $started = microtime( true );
1318
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
1319
 
1320
  // Don't foul up the admin side of things, unless a plugin wants to.
1321
  if ( is_admin() &&
1395
  if ( is_string( $size ) && array_key_exists( $size, $this->image_sizes() ) ) {
1396
  $image_args = $this->image_sizes();
1397
  $image_args = $image_args[ $size ];
1398
+ ewwwio_debug_message( "image args for $size: " . implode( ',', $image_args ) );
1399
 
1400
  $exactdn_args = array();
1401
 
1406
  $image_meta = wp_get_attachment_metadata( $attachment_id );
1407
  $intermediate = false;
1408
  } elseif ( ! $image_meta ) {
1409
+ ewwwio_debug_message( 'still do not have meta, getting it now' );
1410
  // If we still don't have any image meta at this point, it's probably from a custom thumbnail size
1411
  // for an image that was uploaded before the custom image was added to the theme. Try to determine the size manually.
1412
  $image_meta = wp_get_attachment_metadata( $attachment_id );
1419
  }
1420
  }
1421
  }
 
1422
  if ( isset( $image_meta['width'], $image_meta['height'] ) ) {
1423
  $image_args['width'] = $image_meta['width'];
1424
  $image_args['height'] = $image_meta['height'];
1425
 
1426
+ // NOTE: it will constrain an image to $content_width which is expected behavior in core, so far as I can see.
1427
  list( $image_args['width'], $image_args['height'] ) = image_constrain_size_for_editor( $image_args['width'], $image_args['height'], $size, 'display' );
1428
 
1429
  $has_size_meta = true;
1430
+ ewwwio_debug_message( 'image args constrained: ' . implode( ',', $image_args ) );
1431
  }
1432
 
1433
  $transform = $image_args['crop'] ? 'resize' : 'fit';
1443
  if ( ! isset( $image_meta['sizes'] ) ) {
1444
  $size_meta = $image_meta;
1445
  // Because we don't have the "real" meta, just the height/width for the specific size.
1446
+ ewwwio_debug_message( 'getting attachment meta now' );
1447
  $image_meta = wp_get_attachment_metadata( $attachment_id );
1448
  }
1449
  if ( 'resize' === $transform && $image_meta && isset( $image_meta['width'], $image_meta['height'] ) ) {
1457
  }
1458
  }
1459
 
1460
+ if (
1461
+ ! empty( $image_meta['sizes'] ) && ! empty( $image_meta['width'] ) && ! empty( $image_meta['height'] ) &&
1462
+ $image_args['width'] == $image_meta['width'] &&
1463
+ $image_args['height'] == $image_meta['height']
1464
+ ) {
1465
+ ewwwio_debug_message( 'image args match size of original, just use that' );
1466
+ $size = 'full';
1467
+ }
1468
  if ( empty( $image_meta['sizes'] ) && ! empty( $size_meta ) ) {
1469
  $image_meta['sizes'][ $size ] = $size_meta;
1470
  }
1597
  */
1598
  public function filter_srcset_array( $sources = array(), $size_array = array(), $image_src = '', $image_meta = array(), $attachment_id = 0 ) {
1599
  $started = microtime( true );
1600
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
1601
  // Don't foul up the admin side of things, unless a plugin wants to.
1602
  if ( is_admin() &&
1603
  /**
1687
  *
1688
  * @param array|bool $multipliers Array of multipliers to use or false to bypass.
1689
  */
1690
+ $multipliers = apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1, 2, 3, 1920 ) );
1691
  $url = trailingslashit( $upload_dir['baseurl'] ) . $image_meta['file'];
1692
 
1693
  if (
1731
  foreach ( $multipliers as $multiplier ) {
1732
 
1733
  $newwidth = intval( $base * $multiplier );
1734
+ if ( 1920 == $multiplier ) {
1735
+ $newwidth = 1920;
1736
+ }
1737
  if ( $newwidth < 50 ) {
1738
  continue;
1739
  }
1789
  */
1790
  public function filter_sizes( $sizes, $size ) {
1791
  $started = microtime( true );
1792
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
1793
  if ( ! doing_filter( 'the_content' ) ) {
1794
  return $sizes;
1795
  }
1816
  * @return string A srcset attribute with ExactDN image urls and widths.
1817
  */
1818
  public function generate_image_srcset( $url, $width, $zoom = false, $filename_width = false ) {
1819
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
1820
  // Don't foul up the admin side of things.
1821
  if ( is_admin() ) {
1822
  return '';
1832
  *
1833
  * @param array|bool $multipliers Array of multipliers to use or false to bypass.
1834
  */
1835
+ $multipliers = apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1, 2, 3, 1920 ) );
1836
  /**
1837
  * Filter the width ExactDN will use to create srcset attribute.
1838
  * Return a falsy value to short-circuit and bypass srcset fill.
1857
 
1858
  foreach ( $multipliers as $multiplier ) {
1859
  $newwidth = intval( $width * $multiplier );
1860
+ if ( 1920 == $multiplier ) {
1861
+ $newwidth = 1920;
1862
+ }
1863
  if ( $newwidth < 50 ) {
1864
  continue;
1865
  }
1913
  * @return array The arguments, possibly altered for smart cropping.
1914
  */
1915
  function maybe_smart_crop( $args, $attachment_id, $meta = false ) {
1916
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
1917
  if ( ! empty( $args['crop'] ) ) {
1918
  ewwwio_debug_message( 'already cropped' );
1919
  return $args;
1991
  * @return WP_HTTP_Response The result, unaltered.
1992
  */
1993
  function parse_restapi_maybe( $response, $handler, $request ) {
1994
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
1995
  if ( ! is_a( $request, 'WP_REST_Request' ) ) {
1996
  ewwwio_debug_message( 'oddball REST request or handler' );
1997
  return $response; // Something isn't right, bail.
2037
  * @return bool True if the url is considerd valid, false otherwise.
2038
  */
2039
  protected function validate_image_url( $url, $exactdn_is_valid = false ) {
2040
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
2041
  $parsed_url = $this->parse_url( $url );
2042
  if ( ! $parsed_url ) {
2043
  ewwwio_debug_message( 'could not parse' );
2124
  * @return string The possibly altered URL without dimensions.
2125
  **/
2126
  protected function strip_image_dimensions_maybe( $src ) {
2127
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
2128
  $stripped_src = $src;
2129
 
2130
  // Build URL, first removing WP's resized string so we pass the original image to ExactDN.
2152
  * @return array
2153
  */
2154
  protected function image_sizes() {
2155
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
2156
  if ( null == self::$image_sizes ) {
2157
  global $_wp_additional_image_sizes;
2158
 
2201
  * @return array The ExactDNified array of images.
2202
  */
2203
  function ngg_pro_lightbox_images_queue( $images ) {
2204
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
2205
  if ( ewww_image_optimizer_iterable( $images ) ) {
2206
  foreach ( $images as $index => $image ) {
2207
  if ( ! empty( $image['image'] ) && $this->validate_image_url( $image['image'] ) ) {
2256
  ) {
2257
  return $image;
2258
  }
2259
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
2260
  if ( $this->validate_image_url( $image ) ) {
2261
  return $this->generate_url( $image );
2262
  }
2263
  return $image;
2264
  }
2265
 
2266
+ /**
2267
+ * Handle images in legacy WooCommerce API endpoints.
2268
+ *
2269
+ * @param array $product_data The product information that will be returned via the API.
2270
+ * @return array The product information with ExactDNified image urls.
2271
+ */
2272
+ function woocommerce_api_product_response( $product_data ) {
2273
+ if ( is_array( $product_data ) && ! empty( $product_data['featured_src'] ) ) {
2274
+ if ( $this->validate_image_url( $product_data['featured_src'] ) ) {
2275
+ $product_data['featured_src'] = $this->generate_url( $product_data['featured_src'] );
2276
+ }
2277
+ }
2278
+ return $product_data;
2279
+ }
2280
+
2281
  /**
2282
  * Enqueue ExactDN helper script
2283
  */
2297
  if ( strpos( $image_url, 'revslider/admin/assets/images/dummy.png' ) ) {
2298
  return array();
2299
  }
2300
+ if ( strpos( $image_url, '/lazy.png' ) ) {
2301
+ return array();
2302
+ }
2303
  if ( strpos( $image_url, 'lazy_placeholder.gif' ) ) {
2304
  return array();
2305
  }
2306
+ if ( strpos( $image_url, '/assets/images/' ) ) {
2307
  return array();
2308
  }
2309
  if ( strpos( $image_url, 'LayerSlider/static/img' ) ) {
2349
  if ( is_admin() ) {
2350
  return $url;
2351
  }
2352
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
2353
  $parsed_url = $this->parse_url( $url );
2354
 
2355
  if ( false !== strpos( $url, 'wp-admin/' ) ) {
2379
  return $url;
2380
  }
2381
 
2382
+ // No PHP files shall pass.
2383
+ if ( preg_match( '/\.php$/', $parsed_url['path'] ) ) {
2384
+ return $url;
2385
+ }
2386
+
2387
  // Make sure this is an allowed image domain/hostname for ExactDN on this site.
2388
  if ( ! $this->allow_image_domain( $parsed_url['host'] ) ) {
2389
  ewwwio_debug_message( "invalid host for ExactDN: {$parsed_url['host']}" );
2434
  * @return string The raw final URL. You should run this through esc_url() before displaying it.
2435
  */
2436
  function generate_url( $image_url, $args = array(), $scheme = null ) {
2437
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
2438
  $image_url = trim( $image_url );
2439
 
2440
  if ( is_null( $scheme ) ) {
2597
  * @return string Result of parse_url.
2598
  */
2599
  function url_scheme( $url, $scheme ) {
2600
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
2601
  if ( ! in_array( $scheme, array( 'http', 'https' ) ) ) {
2602
  ewwwio_debug_message( 'not a valid scheme' );
2603
  if ( preg_match( '#^(https?:)?//#', $url ) ) {
2651
 
2652
  /**
2653
  * Adds link to header which enables DNS prefetching for faster speed.
2654
+ *
2655
+ * @param array $hints A list of hints for a particular relationship type.
2656
+ * @param string $relationship_type The type of hint being filtered: dns-prefetch, preconnect, etc.
2657
+ * @return array The list of hints, potentially with the ExactDN domain added in.
2658
  */
2659
+ function dns_prefetch( $hints, $relationship_type ) {
2660
+ if ( 'dns-prefetch' === $relationship_type && $this->exactdn_domain ) {
2661
+ $hints[] = '//' . $this->exactdn_domain;
 
2662
  }
2663
+ return $hints;
2664
  }
2665
 
2666
  /**
2670
  * @return array The same list, with the ExactDN domain appended.
2671
  */
2672
  function autoptimize_cdn_url( $domains ) {
2673
+ ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
2674
  if ( is_array( $domains ) && ! in_array( $this->exactdn_domain, $domains ) ) {
2675
  ewwwio_debug_message( 'adding to AO list: ' . $this->exactdn_domain );
2676
  $domains[] = $this->exactdn_domain;
common.php CHANGED
@@ -23,7 +23,7 @@ if ( ! defined( 'ABSPATH' ) ) {
23
  exit;
24
  }
25
 
26
- define( 'EWWW_IMAGE_OPTIMIZER_VERSION', '463.0' );
27
 
28
  // Initialize a couple globals.
29
  $ewww_debug = '';
@@ -129,6 +129,8 @@ add_action( 'init', 'ewww_image_optimizer_parser_init', 99 );
129
  add_action( 'init', 'ewww_image_optimizer_gallery_support' );
130
  // Initializes the plugin for admin interactions, like saving network settings and scheduling cron jobs.
131
  add_action( 'admin_init', 'ewww_image_optimizer_admin_init' );
 
 
132
  // Get admin color scheme and save it for later.
133
  add_action( 'admin_head', 'ewww_image_optimizer_save_admin_colors' );
134
  // Legacy (non-AJAX) action hook for manually optimizing an image.
@@ -173,22 +175,24 @@ add_action( 'wp_ajax_ewww_manual_restore', 'ewww_image_optimizer_manual' );
173
  add_action( 'wp_ajax_ewww_manual_cloud_restore', 'ewww_image_optimizer_manual' );
174
  // AJAX action hook for manually restoring a single image backup from the API.
175
  add_action( 'wp_ajax_ewww_manual_cloud_restore_single', 'ewww_image_optimizer_cloud_restore_single_image_handler' );
 
 
176
  // AJAX action hook to disable the media library notice.
177
  add_action( 'wp_ajax_ewww_dismiss_media_notice', 'ewww_image_optimizer_dismiss_media_notice' );
178
  // Adds script to highlight mis-sized images on the front-end (for logged in admins only).
179
- add_action( 'wp_enqueue_scripts', 'ewww_image_optimizer_resize_detection_script' );
180
  // Adds a button on the admin bar to allow highlighting mis-sized images on-demand.
181
  add_action( 'admin_bar_init', 'ewww_image_optimizer_admin_bar_init' );
182
  // Non-AJAX handler to delete the API key, and reroute back to the settings page.
183
  add_action( 'admin_action_ewww_image_optimizer_remove_cloud_key', 'ewww_image_optimizer_remove_cloud_key' );
184
  // Non-AJAX handler to retest async/background mode.
185
  add_action( 'admin_action_ewww_image_optimizer_retest_background_optimization', 'ewww_image_optimizer_retest_background_optimization' );
 
 
186
  // Non-AJAX handler to delete the debug log, and reroute back to the settings page.
187
  add_action( 'admin_action_ewww_image_optimizer_delete_debug_log', 'ewww_image_optimizer_delete_debug_log' );
188
  // Makes sure to flush out any scheduled jobs on deactivation.
189
  register_deactivation_hook( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE, 'ewww_image_optimizer_network_deactivate' );
190
- // Removes the .htaccess rules for webp when uninstalled.
191
- register_uninstall_hook( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE, 'ewww_image_optimizer_uninstall' );
192
  // add_action( 'shutdown', 'ewwwio_memory_output' );.
193
  // Makes sure we flush the debug info to the log on shutdown.
194
  add_action( 'shutdown', 'ewww_image_optimizer_debug_log' );
@@ -204,8 +208,10 @@ if ( 'done' !== get_option( 'ewww_image_optimizer_relative_migration_status' ) )
204
  * Setup page parsing classes after theme functions.php is loaded and plugins have run init routines.
205
  */
206
  function ewww_image_optimizer_parser_init() {
 
207
  // If ExactDN is enabled.
208
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) && empty( $_GET['exactdn_disable'] ) ) {
 
209
  /**
210
  * Page Parsing class for working with HTML content.
211
  */
@@ -220,8 +226,21 @@ function ewww_image_optimizer_parser_init() {
220
  ewww_image_optimizer_set_option( 'autoptimize_cdn_url', '' );
221
  }
222
  }
 
 
 
 
 
 
 
 
 
 
 
 
223
  // If Alt WebP Rewriting is enabled.
224
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) ) {
 
225
  /**
226
  * Page Parsing class for working with HTML content.
227
  */
@@ -231,6 +250,28 @@ function ewww_image_optimizer_parser_init() {
231
  */
232
  require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-alt-webp.php' );
233
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  }
235
 
236
  /**
@@ -446,6 +487,17 @@ function ewww_image_optimizer_preinit() {
446
  */
447
  function ewww_image_optimizer_gallery_support() {
448
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
 
 
 
 
 
 
 
 
 
 
 
449
  $active_plugins = get_option( 'active_plugins' );
450
  if ( is_multisite() && is_array( $active_plugins ) ) {
451
  $sitewide_plugins = get_site_option( 'active_sitewide_plugins' );
@@ -513,16 +565,21 @@ function ewww_image_optimizer_upgrade() {
513
  $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE 'wp_ewwwio_test_optimize_batch_%'" );
514
 
515
  }
 
 
 
516
  if ( get_option( 'ewww_image_optimizer_version' ) < 280 ) {
517
  ewww_image_optimizer_migrate_settings_to_levels();
518
  }
519
  if ( get_option( 'ewww_image_optimizer_version' ) < 407 ) {
 
520
  add_site_option( 'exactdn_all_the_things', true );
521
  }
522
  if ( get_option( 'ewww_image_optimizer_version' ) > 0 && get_option( 'ewww_image_optimizer_version' ) < 434 && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpegtran_copy' ) ) {
523
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_metadata_remove', false );
524
  }
525
  if ( get_option( 'ewww_image_optimizer_version' ) > 0 && get_option( 'ewww_image_optimizer_version' ) < 440 && ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) || ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_level' ) < 30 ) ) {
 
526
  add_site_option( 'exactdn_lossy', true );
527
  }
528
  if ( get_option( 'ewww_image_optimizer_version' ) < 454 ) {
@@ -656,6 +713,8 @@ function ewww_image_optimizer_admin_init() {
656
  update_site_option( 'exactdn_all_the_things', $_POST['exactdn_all_the_things'] );
657
  $_POST['exactdn_lossy'] = ( empty( $_POST['exactdn_lossy'] ) ? false : true );
658
  update_site_option( 'exactdn_lossy', $_POST['exactdn_lossy'] );
 
 
659
  $_POST['ewww_image_optimizer_maxmediawidth'] = empty( $_POST['ewww_image_optimizer_maxmediawidth'] ) ? 0 : $_POST['ewww_image_optimizer_maxmediawidth'];
660
  update_site_option( 'ewww_image_optimizer_maxmediawidth', (int) $_POST['ewww_image_optimizer_maxmediawidth'] );
661
  $_POST['ewww_image_optimizer_maxmediaheight'] = empty( $_POST['ewww_image_optimizer_maxmediaheight'] ) ? 0 : $_POST['ewww_image_optimizer_maxmediaheight'];
@@ -729,6 +788,7 @@ function ewww_image_optimizer_admin_init() {
729
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_exactdn', 'boolval' );
730
  register_setting( 'ewww_image_optimizer_options', 'exactdn_all_the_things', 'boolval' );
731
  register_setting( 'ewww_image_optimizer_options', 'exactdn_lossy', 'boolval' );
 
732
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_resize_detection', 'boolval' );
733
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_maxmediawidth', 'intval' );
734
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_maxmediaheight', 'intval' );
@@ -753,6 +813,18 @@ function ewww_image_optimizer_admin_init() {
753
  add_action( 'network_admin_notices', 'ewww_image_optimizer_notice_invalid_key' );
754
  add_action( 'admin_notices', 'ewww_image_optimizer_notice_invalid_key' );
755
  }
 
 
 
 
 
 
 
 
 
 
 
 
756
  // Alert user if multiple re-optimizations detected.
757
  add_action( 'network_admin_notices', 'ewww_image_optimizer_notice_reoptimization' );
758
  add_action( 'admin_notices', 'ewww_image_optimizer_notice_reoptimization' );
@@ -767,6 +839,10 @@ function ewww_image_optimizer_admin_init() {
767
  add_action( 'admin_notices', 'ewww_image_optimizer_thumbnail_regen_notice' );
768
  }
769
  }
 
 
 
 
770
  if ( ! empty( $_GET['ewww_pngout'] ) ) {
771
  add_action( 'admin_notices', 'ewww_image_optimizer_pngout_installed' );
772
  add_action( 'network_admin_notices', 'ewww_image_optimizer_pngout_installed' );
@@ -831,8 +907,7 @@ function ewww_image_optimizer_ajax_compat_check() {
831
  if ( ! empty( $_REQUEST['action'] ) ) {
832
  if ( 'regeneratethumbnail' == $_REQUEST['action'] ||
833
  'meauh_save_image' == $_REQUEST['action'] ||
834
- 'hotspot_save' == $_REQUEST['action'] ||
835
- false !== strpos( $_REQUEST['action'], 'wc_regenerate_images' )
836
  ) {
837
  ewwwio_debug_message( 'doing regeneratethumbnail' );
838
  ewww_image_optimizer_image_sizes( false );
@@ -846,13 +921,19 @@ function ewww_image_optimizer_ajax_compat_check() {
846
  return;
847
  }
848
  }
 
 
 
 
 
 
 
849
  // Check for Image Watermark plugin.
850
  if ( ! empty( $_POST['iw-action'] ) ) {
851
  $action = $_POST['iw-action'];
852
  ewwwio_debug_message( "doing $action" );
853
  global $ewww_preempt_editor;
854
  $ewww_preempt_editor = true;
855
- /* remove_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 ); */
856
  if ( 'applywatermark' === $action ) {
857
  remove_filter( 'wp_generate_attachment_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15 );
858
  add_action( 'iw_after_apply_watermark', 'ewww_image_optimizer_single_size_optimize', 10, 2 );
@@ -892,6 +973,23 @@ function ewww_image_optimizer_privacy_policy_content() {
892
  wp_add_privacy_policy_content( 'EWWW Image Optimizer', $content );
893
  }
894
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
895
  /**
896
  * Optimize a single image from an attachment, based on the size and ID.
897
  *
@@ -1368,6 +1466,7 @@ function ewww_image_optimizer_pngout_installed() {
1368
  "</div>\n";
1369
  }
1370
  }
 
1371
  /**
1372
  * Display a notice that PHP version 5.5 support is going away.
1373
  */
@@ -1375,6 +1474,13 @@ function ewww_image_optimizer_php55_warning() {
1375
  echo '<div id="ewww-image-optimizer-notice-php55" class="notice notice-info"><p><a href="https://docs.ewww.io/article/55-upgrading-php" target="_blank" data-beacon-article="5ab2baa6042863478ea7c2ae">' . esc_html__( 'The next major release of EWWW Image Optimizer will require PHP 5.6 or greater. Newer versions of PHP, like 7.1 and 7.2, are significantly faster and much more secure. If you are unsure how to upgrade to a supported version, ask your webhost for instructions.', 'ewww-image-optimizer' ) . '</a></p></div>';
1376
  }
1377
 
 
 
 
 
 
 
 
1378
  /**
1379
  * Lets the user know their network settings have been saved.
1380
  */
@@ -1390,6 +1496,32 @@ function ewww_image_optimizer_thumbnail_regen_notice() {
1390
  echo '&nbsp;<a href="https://docs.ewww.io/article/49-regenerate-thumbnails" target="_blank" data-beacon-article="5a0f84ed2c7d3a272c0dc801">' . esc_html__( 'Learn more.', 'ewww-image-optimizer' ) . '</a></p></div>';
1391
  }
1392
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1393
  /**
1394
  * Let the user know they can view more options and stats in the Media Library's list mode.
1395
  */
@@ -1494,7 +1626,6 @@ function ewww_image_optimizer_add_attachment() {
1494
  */
1495
  function ewww_image_optimizer_image_sizes( $sizes ) {
1496
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1497
- /* remove_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 ); */
1498
  global $ewww_preempt_editor;
1499
  $ewww_preempt_editor = true;
1500
  // This happens right after thumbs and meta are generated.
@@ -1546,7 +1677,6 @@ function ewww_image_optimizer_editor_save_pre( $image ) {
1546
  if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_noauto' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_disable_editor' ) ) {
1547
  global $ewww_preempt_editor;
1548
  $ewww_preempt_editor = true;
1549
- /* remove_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 ); */
1550
  add_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_restore_editor_hooks', 1 );
1551
  add_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15, 2 );
1552
  }
@@ -1625,7 +1755,6 @@ function ewww_image_optimizer_retina_wrapper( $meta ) {
1625
  }
1626
  global $ewww_preempt_editor;
1627
  $ewww_preempt_editor = true;
1628
- /* remove_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 ); */
1629
  if ( class_exists( 'Meow_WR2X_Core' ) ) {
1630
  global $wr2x_core;
1631
  if ( is_object( $wr2x_core ) ) {
@@ -1635,7 +1764,6 @@ function ewww_image_optimizer_retina_wrapper( $meta ) {
1635
  $meta = wr2x_wp_generate_attachment_metadata( $meta );
1636
  }
1637
  $ewww_preempt_editor = false;
1638
- /* add_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 ); */
1639
  return $meta;
1640
  }
1641
 
@@ -1929,22 +2057,6 @@ function ewww_image_optimizer_network_deactivate( $network_wide ) {
1929
  }
1930
  }
1931
 
1932
- /**
1933
- * Cleans up when the plugin is removed.
1934
- *
1935
- * Removes rules from .htaccess file added for WebP rewriting. Also clears the ewwwio_queue table.
1936
- */
1937
- function ewww_image_optimizer_uninstall() {
1938
- if ( ewwwio_extract_from_markers( ewww_image_optimizer_htaccess_path(), 'EWWWIO' ) ) {
1939
- insert_with_markers( ewww_image_optimizer_htaccess_path(), 'EWWWIO', '' );
1940
- }
1941
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'aux-optimize.php' );
1942
- ewww_image_optimizer_delete_queue_images();
1943
- ewww_image_optimizer_delete_queue_images( 'flag' );
1944
- ewww_image_optimizer_delete_queue_images( 'nextgen' );
1945
- ewww_image_optimizer_delete_queue_images( 'nextcell' );
1946
- }
1947
-
1948
  /**
1949
  * Adds a global settings page to the network admin settings menu.
1950
  */
@@ -2018,13 +2130,14 @@ function ewww_image_optimizer_admin_menu() {
2018
  'ewww_image_optimizer_network_singlesite_options' // Function to call.
2019
  );
2020
  }
2021
- if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
 
2022
  // Add Dynamic Image Debugging page for image regeneration issues.
2023
  add_media_page( esc_html__( 'Dynamic Image Debugging', 'ewww-image-optimizer' ), esc_html__( 'Dynamic Image Debugging', 'ewww-image-optimizer' ), $permissions, 'ewww-image-optimizer-dynamic-debug', 'ewww_image_optimizer_dynamic_image_debug' );
2024
  // Add Image Queue Debugging to allow clearing and checking queues.
2025
  add_media_page( esc_html__( 'Image Queue Debugging', 'ewww-image-optimizer' ), esc_html__( 'Image Queue Debugging', 'ewww-image-optimizer' ), $permissions, 'ewww-image-optimizer-queue-debug', 'ewww_image_optimizer_image_queue_debug' );
2026
  // Add debug log page for viewing the log on hosts where you can't directly access it.
2027
- add_media_page( esc_html__( 'EWWW IO Debug Log', 'ewww-image-optimizer' ), esc_html__( 'EWWW IO Debug Log', 'ewww-image-optimizer' ), $permissions, 'ewww-image-optimizer-debug-log-display', 'ewww_image_optimizer_debug_log_display' );
2028
  }
2029
  if ( is_plugin_active( 'image-store/ImStore.php' ) || is_plugin_active_for_network( 'image-store/ImStore.php' ) ) {
2030
  // Adds an optimize page for Image Store galleries and images.
@@ -3578,14 +3691,19 @@ function ewww_image_optimizer_cloud_autorotate( $file, $type ) {
3578
  *
3579
  * @since 4.4.0
3580
  *
3581
- * @param string $file The file to resize.
3582
- * @param string $type File type of the file.
3583
- * @param int|null $max_w Desired image width.
3584
- * @param int|null $max_h Desired image height.
3585
- * @param bool $crop Optional. Scale by default, crop if true.
 
 
 
 
 
3586
  * @return string|WP_Error The image contents or the error message.
3587
  */
3588
- function ewww_image_optimizer_cloud_resize( $file, $type, $max_w, $max_h, $crop = false ) {
3589
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
3590
  if ( ! ewwwio_check_memory_available( filesize( $file ) * 2.2 ) ) { // 2.2 = upload buffer + download buffer (2) multiplied by a factor of 1.1 for extra wiggle room.
3591
  $memory_required = filesize( $file ) * 2.2;
@@ -3613,8 +3731,8 @@ function ewww_image_optimizer_cloud_resize( $file, $type, $max_w, $max_h, $crop
3613
  return new WP_Error( 'invalid_key', __( 'License Exceeded', 'ewww-image-optimizer' ) );
3614
  }
3615
  ewwwio_debug_message( "file: $file " );
3616
- ewwwio_debug_message( "width: $max_w" );
3617
- ewwwio_debug_message( "height: $max_h" );
3618
  $api_key = ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' );
3619
  if ( empty( $api_key ) ) {
3620
  return new WP_Error( 'invalid_key', __( 'Could not verify API key', 'ewww-image-optimizer' ) );
@@ -3636,9 +3754,14 @@ function ewww_image_optimizer_cloud_resize( $file, $type, $max_w, $max_h, $crop
3636
  $post_fields = array(
3637
  'filename' => $file,
3638
  'api_key' => $api_key,
3639
- 'width' => (int) $max_w,
3640
- 'height' => (int) $max_h,
3641
- 'crop' => (int) $crop,
 
 
 
 
 
3642
  );
3643
 
3644
  $payload = '';
@@ -4127,7 +4250,7 @@ function ewww_image_optimizer_aux_images_loop( $attachment = null, $auto = false
4127
  );
4128
  if ( get_site_option( 'ewww_image_optimizer_debug' ) ) {
4129
  global $ewww_debug;
4130
- $output['results'] .= '<div style="background-color:#ffff99;">' . $ewww_debug . '</div>';
4131
  }
4132
  $next_file = ewww_image_optimizer_absolutize_path( $wpdb->get_var( "SELECT path FROM $wpdb->ewwwio_images WHERE pending=1 LIMIT 1" ) );
4133
  if ( ! empty( $next_file ) ) {
@@ -4184,6 +4307,63 @@ function ewww_image_optimizer_hidpi_optimize( $orig_path, $return_path = false,
4184
  ewww_image_optimizer( $hidpi_path );
4185
  }
4186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4187
  /**
4188
  * Fetches images from S3 or Azure storage so that they can be optimized locally.
4189
  *
@@ -4201,7 +4381,7 @@ function ewww_image_optimizer_remote_fetch( $id, $meta ) {
4201
  if ( class_exists( 'Amazon_S3_And_CloudFront' ) ) {
4202
  global $as3cf;
4203
  $full_url = get_attached_file( $id );
4204
- if ( strpos( $full_url, 's3' ) === 0 ) {
4205
  $full_url = $as3cf->get_attachment_url( $id, null, null, $meta );
4206
  }
4207
  $filename = get_attached_file( $id, true );
@@ -4509,16 +4689,21 @@ function ewwwio_crop_dimensions( $current_width, $current_height, $max_width = 0
4509
  *
4510
  * @since 4.4.0
4511
  *
4512
- * @param string $file The file to resize.
4513
- * @param int|null $max_w Desired image width.
4514
- * @param int|null $max_h Desired image height.
4515
- * @param bool $crop Optional. Scale by default, crop if true.
 
 
 
 
 
4516
  * @return string|WP_Error The image contents or the error message.
4517
  */
4518
- function ewww_image_optimizer_better_resize( $file, $max_w, $max_h, $crop = false ) {
4519
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
4520
- ewwwio_debug_message( "resizing to $max_w and $max_h" );
4521
- if ( $crop ) {
4522
  ewwwio_debug_message( 'cropping too' );
4523
  $crop = true;
4524
  }
@@ -4528,9 +4713,9 @@ function ewww_image_optimizer_better_resize( $file, $max_w, $max_h, $crop = fals
4528
  return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $file );
4529
  }
4530
  if ( 'image/gif' == $type && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) && function_exists( 'ewww_image_optimizer_gifsicle_resize' ) ) {
4531
- return ewww_image_optimizer_gifsicle_resize( $file, $max_w, $max_h, $crop );
4532
  }
4533
- return ewww_image_optimizer_cloud_resize( $file, $type, $max_w, $max_h, $crop );
4534
  }
4535
 
4536
  /**
@@ -4746,7 +4931,7 @@ function ewww_image_optimizer_resize_upload( $file ) {
4746
  // From here...
4747
  global $ewww_preempt_editor;
4748
  $ewww_preempt_editor = true;
4749
- /* remove_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 ); */
4750
  $editor = wp_get_image_editor( $file );
4751
  if ( is_wp_error( $editor ) ) {
4752
  ewwwio_debug_message( 'could not get image editor' );
@@ -4795,7 +4980,7 @@ function ewww_image_optimizer_resize_upload( $file ) {
4795
  }
4796
  // to here is replaced by cloud/API function.
4797
  $new_size = ewww_image_optimizer_filesize( $new_file );
4798
- if ( $new_size && $new_size < $orig_size ) {
4799
  // Use this action to perform any operations on the original file before it is overwritten with the new, smaller file.
4800
  do_action( 'ewww_image_optimizer_image_resized', $file, $new_file );
4801
  ewwwio_debug_message( "after resizing: $new_size" );
@@ -5131,7 +5316,6 @@ function ewww_image_optimizer_rebuild_meta( $attachment_id ) {
5131
  if ( is_file( $file ) ) {
5132
  global $ewww_preempt_editor;
5133
  $ewww_preempt_editor = true;
5134
- /* remove_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 ); */
5135
  remove_all_filters( 'wp_generate_attachment_metadata' );
5136
  ewwwio_debug_message( "generating new meta for $attachment_id" );
5137
  $meta = wp_generate_attachment_metadata( $attachment_id, $file );
@@ -5230,11 +5414,11 @@ function ewww_image_optimizer_resize_from_meta_data( $meta, $id = null, $log = t
5230
  if ( 'ims_image' == get_post_type( $id ) ) {
5231
  $gallery_type = 6;
5232
  }
5233
- if ( ! $new_image && class_exists( 'Amazon_S3_And_CloudFront' ) && strpos( $file_path, 's3' ) === 0 ) {
5234
  ewww_image_optimizer_check_table_as3cf( $meta, $id, $file_path );
5235
  }
5236
  // If the local file is missing and we have valid metadata, see if we can fetch via CDN.
5237
- if ( ! is_file( $file_path ) || ( strpos( $file_path, 's3' ) === 0 && ! class_exists( 'S3_Uploads' ) ) ) {
5238
  $file_path = ewww_image_optimizer_remote_fetch( $id, $meta );
5239
  if ( ! $file_path ) {
5240
  ewwwio_debug_message( 'could not retrieve path' );
@@ -5887,11 +6071,23 @@ function ewww_image_optimizer_attachment_path( $meta, $id, $file = '', $refresh_
5887
  $file_path = ( 0 !== strpos( $file, '/' ) && ! preg_match( '|^.:\\\|', $file ) ? $upload_path . $file : $file );
5888
  $filtered_file_path = apply_filters( 'get_attached_file', $file_path, $id );
5889
  ewwwio_debug_message( "WP (filtered) thinks the file is at: $filtered_file_path" );
5890
- if ( ( strpos( $filtered_file_path, 's3' ) === false || in_array( 's3', stream_get_wrappers() ) ) && is_file( $filtered_file_path ) ) {
 
 
 
 
 
 
5891
  return array( str_replace( '//_imsgalleries/', '/_imsgalleries/', $filtered_file_path ), $upload_path );
5892
  }
5893
  ewwwio_debug_message( "WP (unfiltered) thinks the file is at: $file_path" );
5894
- if ( ( strpos( $file_path, 's3' ) === false || in_array( 's3', stream_get_wrappers() ) ) && is_file( $file_path ) ) {
 
 
 
 
 
 
5895
  return array( str_replace( '//_imsgalleries/', '/_imsgalleries/', $file_path ), $upload_path );
5896
  }
5897
  if ( 'ims_image' == get_post_type( $id ) && is_array( $meta ) && ! empty( $meta['file'] ) ) {
@@ -5917,7 +6113,7 @@ function ewww_image_optimizer_attachment_path( $meta, $id, $file = '', $refresh_
5917
  }
5918
  if ( is_array( $meta ) && ! empty( $meta['file'] ) ) {
5919
  $file_path = $meta['file'];
5920
- if ( strpos( $file_path, 's3' ) === 0 && ! in_array( 's3', stream_get_wrappers() ) ) {
5921
  return array( '', $upload_path );
5922
  }
5923
  ewwwio_debug_message( "looking for file at $file_path" );
@@ -5954,7 +6150,6 @@ function ewww_image_optimizer_relativize_path( $file ) {
5954
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE' ) || ! EWWW_IMAGE_OPTIMIZER_RELATIVE ) {
5955
  return $file;
5956
  }
5957
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
5958
  if ( defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER' ) && EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER && strpos( $file, EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER ) === 0 ) {
5959
  ewwwio_debug_message( "removing custom relative folder from $file" );
5960
  return str_replace( EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER, 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER', $file );
@@ -5984,7 +6179,6 @@ function ewww_image_optimizer_absolutize_path( $file ) {
5984
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE' ) ) {
5985
  return $file;
5986
  }
5987
- ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
5988
  if ( defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER' ) && EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER && strpos( $file, 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER' ) === 0 ) {
5989
  ewwwio_debug_message( "replacing custom relative folder in $file" );
5990
  return str_replace( 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER', EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER, $file );
@@ -6098,7 +6292,7 @@ function ewww_image_optimizer_quick_mimetype( $path ) {
6098
  case 'pdf':
6099
  return 'application/pdf';
6100
  default:
6101
- if ( empty( $pathextension ) && 0 !== strpos( $path, 's3' ) && is_file( $path ) ) {
6102
  return ewww_image_optimizer_mimetype( $path, 'i' );
6103
  }
6104
  return false;
@@ -6248,7 +6442,7 @@ function ewww_image_optimizer_custom_column( $column_name, $id, $meta = null, $r
6248
  $print_meta = print_r( $meta, true );
6249
  $print_meta = preg_replace( array( '/ /', '/\n+/' ), array( '&nbsp;', '<br />' ), $print_meta );
6250
  $debug_button = esc_html__( 'Show Metadata', 'ewww-image-optimizer' );
6251
- $output .= "<button type='button' class='ewww-show-debug-meta button button-secondary' data-id='$id'>$debug_button</button><div id='ewww-debug-meta-$id' style='background-color:#ffff99;font-size: 10px;padding: 10px;margin:3px -10px 10px;line-height: 1.1em;display: none;'>$print_meta</div>";
6252
  }
6253
  $output .= "<div id='ewww-media-status-$id'>";
6254
  $ewww_cdn = false;
@@ -6264,11 +6458,11 @@ function ewww_image_optimizer_custom_column( $column_name, $id, $meta = null, $r
6264
  $output .= '<div>' . esc_html__( 'Azure Storage image', 'ewww-image-optimizer' ) . '</div>';
6265
  $ewww_cdn = true;
6266
  }
6267
- if ( is_array( $meta ) && class_exists( 'Amazon_S3_And_CloudFront' ) && preg_match( '/^(http|s3)\w*:/', get_attached_file( $id ) ) ) {
6268
- $output .= '<div>' . esc_html__( 'Amazon S3 image', 'ewww-image-optimizer' ) . '</div>';
6269
  $ewww_cdn = true;
6270
  }
6271
- if ( is_array( $meta ) && class_exists( 'S3_Uploads' ) && preg_match( '/^(http|s3)\w*:/', get_attached_file( $id ) ) ) {
6272
  $output .= '<div>' . esc_html__( 'Amazon S3 image', 'ewww-image-optimizer' ) . '</div>';
6273
  $ewww_cdn = true;
6274
  }
@@ -6858,6 +7052,20 @@ function ewww_image_optimizer_migrate_meta_to_db( $id, $meta, $bail_early = fals
6858
  return $meta;
6859
  }
6860
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6861
  /**
6862
  * Disables the Media Library notice about List Mode.
6863
  */
@@ -7376,6 +7584,8 @@ function ewww_image_optimizer_network_singlesite_options() {
7376
  * @param string $network Indicates which options should be shown in multisite installations.
7377
  */
7378
  function ewww_image_optimizer_options( $network = 'singlesite' ) {
 
 
7379
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
7380
  ewwwio_debug_version_info();
7381
  ewwwio_debug_message( 'ABSPATH: ' . ABSPATH );
@@ -7383,6 +7593,8 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
7383
  ewwwio_debug_message( 'home url: ' . get_home_url() );
7384
  ewwwio_debug_message( 'site url: ' . get_site_url() );
7385
  ewwwio_debug_message( 'content_url: ' . content_url() );
 
 
7386
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_NOEXEC' ) ) {
7387
  if ( defined( 'EWWW_IMAGE_OPTIMIZER_CLOUD' ) && EWWW_IMAGE_OPTIMIZER_CLOUD ) {
7388
  ewww_image_optimizer_disable_tools();
@@ -7422,12 +7634,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
7422
  "</style>\n";
7423
  $output[] = "<div class='wrap'>\n";
7424
  $output[] = "<h1>EWWW Image Optimizer</h1>\n";
7425
- $output[] = "<div id='ewww-container-left' style='float: left; margin-right: 225px;'>\n";
7426
- $output[] = "<p><a href='https://ewww.io/'>" . esc_html__( 'Plugin Home Page', 'ewww-image-optimizer' ) . '</a> | ' .
7427
- "<a class='ewww-docs-root' href='https://docs.ewww.io/'>" . esc_html__( 'Documentation', 'ewww-image-optimizer' ) . '</a> | ' .
7428
- "<a class='ewww-docs-root' href='https://ewww.io/contact-us/'>" . esc_html__( 'Plugin Support', 'ewww-image-optimizer' ) . '</a> | ' .
7429
- "<a href='https://ewww.io/status/'>" . esc_html__( 'Server Status', 'ewww-image-optimizer' ) . '</a> | ' .
7430
- "<a href='https://ewww.io/downloads/s3-image-optimizer/'>" . esc_html__( 'S3 Image Optimizer', 'ewww-image-optimizer' ) . "</a></p>\n";
7431
  if ( 'network-multisite' == $network ) {
7432
  $bulk_link = esc_html__( 'Media Library', 'ewww-image-optimizer' ) . ' -> ' . esc_html__( 'Bulk Optimize', 'ewww-image-optimizer' );
7433
  } else {
@@ -7454,7 +7661,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
7454
  $compress_recommendations = array();
7455
  $resize_recommendations = array();
7456
 
7457
- $status_output = "<div id='ewww-widgets' class='metabox-holder'><div class='meta-box-sortables'><div id='ewww-status' class='postbox'>\n" .
7458
  "<h2 class='ewww-hndle'>" . esc_html__( 'Optimization Status', 'ewww-image-optimizer' ) . "</h2>\n<div class='inside'>";
7459
 
7460
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) ) {
@@ -7767,6 +7974,8 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
7767
  "<li class='ewww-tab ewww-conversion-nav'><span class='ewww-tab-hidden'>" . esc_html__( 'Convert', 'ewww-image-optimizer' ) . "</span></li>\n" .
7768
  "<li class='ewww-tab ewww-webp-nav'><span class='ewww-tab-hidden'>" . esc_html__( 'WebP', 'ewww-image-optimizer' ) . "</span></li>\n" .
7769
  "<li class='ewww-tab ewww-overrides-nav'><span class='ewww-tab-hidden'><a href='https://docs.ewww.io/article/40-override-options' target='_blank'><span class='ewww-tab-hidden'>" . esc_html__( 'Overrides', 'ewww-image-optimizer' ) . "</a></span></li>\n" .
 
 
7770
  "</ul>\n";
7771
  }
7772
  if ( 'network-multisite' == $network ) {
@@ -7786,6 +7995,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
7786
  ewwwio_debug_message( 'automatic compression enabled' );
7787
  }
7788
  $output[] = "<div id='ewww-general-settings'>\n";
 
7789
  $output[] = "<table class='form-table'>\n";
7790
  if ( is_multisite() ) {
7791
  if ( is_plugin_active_for_network( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE_REL ) ) {
@@ -7813,8 +8023,6 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
7813
  } else {
7814
  $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_cloud_key'>" . esc_html__( 'Optimization API Key', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/7-basic-configuration', '585373d5c697912ffd6c0bb2,5ad0c8e7042863075092650b,5a9efec62c7d3a7549516550' ) . "</th><td><input type='text' id='ewww_image_optimizer_cloud_key' name='ewww_image_optimizer_cloud_key' value='' size='32' /> " . esc_html__( 'API Key will be validated when you save your settings.', 'ewww-image-optimizer' ) . " <a href='https://ewww.io/plans/' target='_blank'>" . esc_html__( 'Purchase an API key.', 'ewww-image-optimizer' ) . "</a></td></tr>\n";
7815
  }
7816
- $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_debug'>" . esc_html__( 'Debugging', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/7-basic-configuration', '585373d5c697912ffd6c0bb2' ) . '</th>' .
7817
- "<td><input type='checkbox' id='ewww_image_optimizer_debug' name='ewww_image_optimizer_debug' value='true' " . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) == true ? "checked='true'" : '' ) . ' /> ' . esc_html__( 'Use this to provide information for support purposes, or if you feel comfortable digging around in the code to fix a problem you are experiencing.', 'ewww-image-optimizer' ) . "</td></tr>\n";
7818
  $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_metadata_remove'>" . esc_html__( 'Remove Metadata', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/7-basic-configuration', '585373d5c697912ffd6c0bb2' ) . "</th>\n" .
7819
  "<td><input type='checkbox' id='ewww_image_optimizer_metadata_remove' name='ewww_image_optimizer_metadata_remove' value='true' " . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_metadata_remove' ) == true ? "checked='true'" : '' ) . ' /> ' . esc_html__( 'This will remove ALL metadata: EXIF, comments, color profiles, and anything else that is not pixel data.', 'ewww-image-optimizer' ) .
7820
  "<p class ='description'>" . esc_html__( 'Color profiles are preserved when using the API or ExactDN.', 'ewww-image-optimizer' ) . "</p></td></tr>\n";
@@ -7875,6 +8083,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
7875
  $output[] = "</table>\n</div>\n";
7876
  $output[] = "<div id='ewww-exactdn-settings'>\n";
7877
  $output[] = "<table class='form-table'>\n";
 
7878
  $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_exactdn'>" . esc_html__( 'ExactDN', 'ewww-image-optimizer' ) .
7879
  '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/44-introduction-to-exactdn', '59bc5ad6042863033a1ce370,59de6631042863379ddc953c,59c44349042863033a1d06d3,5ada43a12c7d3a0e93678b8c,5a3d278a2c7d3a1943677b52,5a9868eb04286374f7087795,59de68482c7d3a40f0ed6035,592dd69b2c7d3a074e8aed5b' ) . "</th><td><input type='checkbox' id='ewww_image_optimizer_exactdn' name='ewww_image_optimizer_exactdn' value='true' " .
7880
  ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) == true ? "checked='true'" : '' ) . ' /> ' .
@@ -7896,9 +8105,13 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
7896
  $output[] = "<tr class='$network_class'><th scope='row'><label for='exactdn_lossy'>" . esc_html__( 'Premium Compression', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/47-getting-more-from-exactdn', '59de6631042863379ddc953c' ) . '</th>' .
7897
  "<td><input type='checkbox' id='exactdn_lossy' name='exactdn_lossy' value='true' " .
7898
  ( ewww_image_optimizer_get_option( 'exactdn_lossy' ) ? "checked='true'" : '' ) . '> ' . esc_html__( 'Enable high quality premium compression for all images. Disable to use Pixel Perfect mode instead.', 'ewww-image-optimizer' ) . "</td></tr>\n";
 
 
 
7899
  ewwwio_debug_message( 'ExactDN lossy: ' . intval( ewww_image_optimizer_get_option( 'exactdn_lossy' ) ) );
7900
  ewwwio_debug_message( 'ExactDN resize existing: ' . ( ewww_image_optimizer_get_option( 'exactdn_resize_existing' ) == true ? 'on' : 'off' ) );
7901
  ewwwio_debug_message( 'ExactDN attachment queries: ' . ( ewww_image_optimizer_get_option( 'exactdn_prevent_db_queries' ) == true ? 'off' : 'on' ) );
 
7902
  if ( defined( 'EXACTDN_EXCLUDE' ) && EXACTDN_EXCLUDE ) {
7903
  $exactdn_user_exclusions = EXACTDN_EXCLUDE;
7904
  if ( is_array( $exactdn_user_exclusions ) ) {
@@ -7911,6 +8124,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
7911
  }
7912
  $output[] = "</table>\n</div>\n";
7913
  $output[] = "<div id='ewww-optimization-settings'>\n";
 
7914
  $output[] = "<table class='form-table'>\n";
7915
  if ( ! ewww_image_optimizer_full_cloud() ) {
7916
  ewwwio_debug_message( 'optipng level: ' . ewww_image_optimizer_get_option( 'ewww_image_optimizer_optipng_level' ) );
@@ -7996,14 +8210,10 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
7996
  ewwwio_debug_message( 'exclude originals from lossy: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_lossy_skip_full' ) == true ? 'on' : 'off' ) );
7997
  ewwwio_debug_message( 'exclude originals from metadata removal: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_metadata_skip_full' ) == true ? 'on' : 'off' ) );
7998
  ewwwio_debug_message( 'use system binaries: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_bundle' ) == true ? 'yes' : 'no' ) );
7999
- $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_enable_help'>" . esc_html__( 'Enable Embedded Help', 'ewww-image-optimizer' ) . "</label></th><td><input type='checkbox' id='ewww_image_optimizer_enable_help' name='ewww_image_optimizer_enable_help' value='true' " . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help' ) == true ? "checked='true'" : '' ) . ' /> ' .
8000
- esc_html__( 'Enable the support beacon, which gives you access to documentation and our support team right from your WordPress dashboard. To assist you more efficiently, we may collect the current url, IP address, browser/device information, and debugging information.', 'ewww-image-optimizer' ) . "</td></tr>\n";
8001
- ewwwio_debug_message( 'enable help beacon: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help' ) == true ? 'yes' : 'no' ) );
8002
- $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_allow_tracking'>" . esc_html__( 'Allow Usage Tracking?', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/23-usage-tracking', '591f3a8e2c7d3a057f893d91' ) . "</th><td><input type='checkbox' id='ewww_image_optimizer_allow_tracking' name='ewww_image_optimizer_allow_tracking' value='true' " . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_allow_tracking' ) == true ? "checked='true'" : '' ) . ' /> ' .
8003
- esc_html__( 'Allow EWWW Image Optimizer to anonymously track how this plugin is used and help us make the plugin better. Opt-in to tracking and receive 500 API image credits free. No sensitive data is tracked.', 'ewww-image-optimizer' ) . "</td></tr>\n";
8004
  $output[] = "</table>\n</div>\n";
8005
 
8006
  $output[] = "<div id='ewww-resize-settings'>\n";
 
8007
  $output[] = "<table class='form-table'>\n";
8008
  $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_resize_detection'>" . esc_html__( 'Resize Detection', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/41-resize-settings', '59849911042863033a1ba5f9' ) . "</th><td><input type='checkbox' id='ewww_image_optimizer_resize_detection' name='ewww_image_optimizer_resize_detection' value='true' " . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_detection' ) == true ? "checked='true'" : '' ) . ' /> ' . esc_html__( 'Highlight images that need to be resized because the browser is scaling them down. Only visible for Admin users and adds a button to the admin bar to detect scaled images that have been lazy loaded.', 'ewww-image-optimizer' ) . "</td></tr>\n";
8009
  ewwwio_debug_message( 'resize detection: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_detection' ) == true ? 'on' : 'off' ) );
@@ -8046,7 +8256,9 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
8046
  $output[] = '<p><span style="color: #3eadc9">' . esc_html__( '*Settings to disable creation and optimization of individual sizes must be configured for each individual site.', 'ewww-image-optimizer' ) . "</span></p></td></tr>\n";
8047
  }
8048
  $output[] = "</table>\n</div>\n";
 
8049
  $output[] = "<div id='ewww-conversion-settings'>\n";
 
8050
  $output[] = '<p>' . esc_html__( 'Conversion is only available for images in the Media Library (except WebP). By default, all images have a link available in the Media Library for one-time conversion. Turning on individual conversion operations below will enable conversion filters any time an image is uploaded or modified.', 'ewww-image-optimizer' ) . "<br />\n" .
8051
  '<b>' . esc_html__( 'NOTE:', 'ewww-image-optimizer' ) . '</b> ' . esc_html__( 'The plugin will attempt to update image locations for any posts that contain the images. You may still need to manually update locations/urls for converted images.', 'ewww-image-optimizer' ) . "\n" .
8052
  "</p>\n";
@@ -8080,7 +8292,9 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
8080
  '<p><span style="color: #3eadc9">' . esc_html__( 'Image conversion requires one of the following PHP libraries: GD, Imagick, or GMagick.', 'ewww-image-optimizer' ) . "</span></p></td></tr>\n";
8081
  }
8082
  $output[] = "</table>\n</div>\n";
 
8083
  $output[] = "<div id='ewww-webp-settings'>\n";
 
8084
  $output[] = "<table class='form-table'>\n";
8085
  if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) || ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) ) {
8086
  $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_webp'>" . esc_html__( 'JPG/PNG to WebP', 'ewww-image-optimizer' ) . '</label>' .
@@ -8110,13 +8324,43 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
8110
  esc_html__( 'JS WebP Rewriting', 'ewww-image-optimizer' ) .
8111
  '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/16-ewww-io-and-webp-images', '5854745ac697912ffd6c1c89,59443d162c7d3a0747cdf9f0' ) . "</th><td><span><input type='checkbox' id='ewww_image_optimizer_webp_for_cdn' name='ewww_image_optimizer_webp_for_cdn' value='true' " .
8112
  ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) == true ? "checked='true'" : '' ) . ' /> ' .
8113
- esc_html__( 'Use this if the Apache rewrite rules do not work, or if your images are served from a CDN.', 'ewww-image-optimizer' ) . ' ' .
8114
- esc_html__( 'Requires jQuery, but may be loaded using async/defer methods or even combined with other scripts.', 'ewww-image-optimizer' ) . ' ' .
8115
  /* translators: %s: Cache Enabler (link) */
8116
  ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ? sprintf( esc_html__( 'Sites using a CDN may also use the WebP option in the %s plugin.', 'ewww-image-optimizer' ), '<a href="https://wordpress.org/plugins/cache-enabler/">Cache Enabler</a>' ) : '' ) . '</span></td></tr>';
8117
  }
8118
  ewwwio_debug_message( 'alt webp rewriting: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) == true ? 'on' : 'off' ) );
8119
  $output[] = "</table>\n</div>\n";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8120
  $output[] = "<p class='submit'><input type='submit' class='button-primary' value='" . esc_attr__( 'Save Changes', 'ewww-image-optimizer' ) . "' /></p>\n";
8121
  $output[] = "</form>\n";
8122
  // Make sure .htaccess rules are terminated when ExactDN is enabled.
@@ -8139,7 +8383,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
8139
  if ( ! ewww_image_optimizer_webp_rewrite_verify() ) {
8140
  $output[] = "<img id='webp-image' src='" . plugins_url( '/images/test.png', __FILE__ ) . "' style='float: right; padding: 0 0 10px 10px;'>\n" .
8141
  "<p id='ewww-webp-rewrite-status'><b>" . esc_html__( 'Rules verified successfully', 'ewww-image-optimizer' ) . "</b></p>\n" .
8142
- "<button type='submit' id='ewww-webp-remove' class='button-secondary action'>" . esc_html__( 'Remove Rewrite Rules', 'ewww-image-optimizer' ) . "</button>\n";
8143
  ewwwio_debug_message( 'webp .htaccess rewriting enabled' );
8144
  } else {
8145
  $output[] = "<pre id='webp-rewrite-rules' style='background: white; font-color: black; border: 1px solid black; clear: both; padding: 10px;'>\n" .
@@ -8157,7 +8401,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
8157
  "AddType image/webp .webp</pre>\n" .
8158
  "<img id='webp-image' src='" . plugins_url( '/images/test.png', __FILE__ ) . "' style='float: right; padding-left: 10px;'>\n" .
8159
  "<p id='ewww-webp-rewrite-status'>" . esc_html__( 'The image to the right will display a WebP image with WEBP in white text, if your site is serving WebP images and your browser supports WebP.', 'ewww-image-optimizer' ) . "</p>\n" .
8160
- "<button type='submit' id='ewww-webp-insert' class='button-secondary action'>" . esc_html__( 'Insert Rewrite Rules', 'ewww-image-optimizer' ) . "</button>\n";
8161
  ewwwio_debug_message( 'webp .htaccess rules not detected' );
8162
  }
8163
  $output[] = "</form>\n";
@@ -8166,17 +8410,16 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
8166
  $test_png_image = plugins_url( '/images/test.png', __FILE__ );
8167
  $output[] = "<noscript data-img='$test_png_image' data-webp='$test_webp_image' data-style='float: right; padding: 0 0 10px 10px;' class='ewww_webp'><img src='$test_png_image' style='float: right; padding: 0 0 10px 10px;'></noscript>\n";
8168
  }
8169
- $output[] = "</div><!-- end container left -->\n";
8170
- $output[] = "<div id='ewww-container-right' style='border: 1px solid #e5e5e5; float: right; margin-left: -215px; padding: 0em 1.5em 1em; background-color: #fff; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); display: inline-block; width: 174px;'>\n" .
8171
  '<h2>' . esc_html__( 'Support EWWW I.O.', 'ewww-image-optimizer' ) . "</h2>\n" .
8172
- '<p>' . esc_html__( 'Would you like to help support development of this plugin?', 'ewww-image-optimizer' ) . "</p>\n" .
8173
  "<p><a href='https://translate.wordpress.org/projects/wp-plugins/ewww-image-optimizer/'>" . esc_html__( 'Help translate EWWW I.O.', 'ewww-image-optimizer' ) . "</a></p>\n" .
8174
  "<p><a href='https://wordpress.org/support/view/plugin-reviews/ewww-image-optimizer#postform'>" . esc_html__( 'Write a review.', 'ewww-image-optimizer' ) . "</a></p>\n" .
8175
  '<p>' . esc_html__( 'Signup for premium image optimization:', 'ewww-image-optimizer' ) . "<br>\n" .
8176
  "<a target='_blank' href='https://ewww.io/plans/'>" . esc_html__( 'Compress', 'ewww-image-optimizer' ) . "</a><br>\n" .
8177
  "<a target='_blank' href='https://ewww.io/resize/'>" . esc_html__( 'Resize', 'ewww-image-optimizer' ) . "</a></p>\n" .
8178
  '<p><b>' . esc_html_x( 'CDN:', 'abbreviation for Content Delivery Network', 'ewww-image-optimizer' ) . "</b><br><a target='_blank' href='https://ewww.io/resize/'>" . esc_html__( 'Add ExactDN to increase website speeds dramatically!', 'ewww-image-optimizer' ) . "</a></p>\n" .
8179
- "</div>\n" .
8180
  "</div>\n";
8181
  ewwwio_debug_message( 'max_execution_time: ' . ini_get( 'max_execution_time' ) );
8182
  ewww_image_optimizer_stl_check();
@@ -8185,7 +8428,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
8185
  if ( 'debug-silent' === $network ) {
8186
  return;
8187
  }
8188
- echo apply_filters( 'ewww_image_optimizer_settings', $output );
8189
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) && ! ewww_image_optimizer_ce_webp_enabled() ) {
8190
  global $ewwwio_alt_webp;
8191
  $ewwwio_alt_webp->inline_script();
@@ -8195,16 +8438,20 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
8195
  esc_html__( 'This will allow us to assist you more quickly.', 'ewww-image-optimizer' );
8196
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
8197
  global $ewww_debug;
8198
- echo '<p style="clear:both"><b>' . esc_html__( 'Debugging Information', 'ewww-image-optimizer' ) . ':</b> <button id="ewww-copy-debug" class="button button-secondary">' . esc_html__( 'Copy', 'ewww-image-optimizer' ) . '</button>';
 
8199
  if ( is_file( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'debug.log' ) ) {
8200
- $debug_log_url = plugins_url( '/debug.log', __FILE__ );
8201
- echo "&emsp;<a href='$debug_log_url'>" . esc_html( 'View Debug Log', 'ewww-image-optimizer' ) . "</a> - <a href='admin.php?action=ewww_image_optimizer_delete_debug_log'>" . esc_html( 'Remove Debug Log', 'ewww-image-optimizer' ) . '</a>';
8202
  }
8203
- echo '</p>';
8204
- echo '<div id="ewww-debug-info" style="background:#ffff99;margin-left:-20px;padding:10px" contenteditable="true">' . $ewww_debug . '</div>';
 
8205
  $help_instructions = esc_html__( 'Debugging information will be included with your message automatically.', 'ewww-image-optimizer' ) . ' ' .
8206
  esc_html__( 'This will allow us to assist you more quickly.', 'ewww-image-optimizer' );
 
 
8207
  }
 
8208
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help' ) ) {
8209
  $current_user = wp_get_current_user();
8210
  $help_email = $current_user->user_email;
@@ -8242,6 +8489,10 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
8242
  <?php
8243
  }
8244
  ewwwio_memory( __FUNCTION__ );
 
 
 
 
8245
  $ewww_debug = '';
8246
  }
8247
 
@@ -8370,9 +8621,15 @@ function ewww_image_optimizer_resize_detection_script() {
8370
  return;
8371
  }
8372
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_detection' ) ) {
8373
- wp_enqueue_script( 'ewww-resize-detection', plugins_url( '/includes/resize_detection.js', __FILE__ ), array(), EWWW_IMAGE_OPTIMIZER_VERSION );
 
 
 
 
 
 
 
8374
  }
8375
- add_filter( 'autoptimize_filter_js_exclude', 'ewww_image_optimizer_autoptimize_js_exclude', -1, 2 );
8376
  }
8377
 
8378
  /**
@@ -8464,7 +8721,8 @@ function ewww_image_optimizer_debug_log_display() {
8464
  */
8465
  function ewww_image_optimizer_debug_log() {
8466
  global $ewww_debug;
8467
- if ( ! empty( $ewww_debug ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
 
8468
  $memory_limit = ewwwio_memory_limit();
8469
  clearstatcache();
8470
  $timestamp = date( 'Y-m-d H:i:s' ) . "\n";
@@ -8485,6 +8743,23 @@ function ewww_image_optimizer_debug_log() {
8485
  ewwwio_memory( __FUNCTION__ );
8486
  }
8487
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8488
  /**
8489
  * Removes the debug.log file from the plugin folder.
8490
  */
23
  exit;
24
  }
25
 
26
+ define( 'EWWW_IMAGE_OPTIMIZER_VERSION', '470.0' );
27
 
28
  // Initialize a couple globals.
29
  $ewww_debug = '';
129
  add_action( 'init', 'ewww_image_optimizer_gallery_support' );
130
  // Initializes the plugin for admin interactions, like saving network settings and scheduling cron jobs.
131
  add_action( 'admin_init', 'ewww_image_optimizer_admin_init' );
132
+ // Check the current screen ID to see if temp debugging should still be enabled.
133
+ add_action( 'current_screen', 'ewww_image_optimizer_current_screen', 10, 1 );
134
  // Get admin color scheme and save it for later.
135
  add_action( 'admin_head', 'ewww_image_optimizer_save_admin_colors' );
136
  // Legacy (non-AJAX) action hook for manually optimizing an image.
175
  add_action( 'wp_ajax_ewww_manual_cloud_restore', 'ewww_image_optimizer_manual' );
176
  // AJAX action hook for manually restoring a single image backup from the API.
177
  add_action( 'wp_ajax_ewww_manual_cloud_restore_single', 'ewww_image_optimizer_cloud_restore_single_image_handler' );
178
+ // AJAX action hook to dismiss the WooCommerce regen notice.
179
+ add_action( 'wp_ajax_ewww_dismiss_wc_regen', 'ewww_image_optimizer_dismiss_wc_regen' );
180
  // AJAX action hook to disable the media library notice.
181
  add_action( 'wp_ajax_ewww_dismiss_media_notice', 'ewww_image_optimizer_dismiss_media_notice' );
182
  // Adds script to highlight mis-sized images on the front-end (for logged in admins only).
183
+ add_action( 'wp_head', 'ewww_image_optimizer_resize_detection_script' );
184
  // Adds a button on the admin bar to allow highlighting mis-sized images on-demand.
185
  add_action( 'admin_bar_init', 'ewww_image_optimizer_admin_bar_init' );
186
  // Non-AJAX handler to delete the API key, and reroute back to the settings page.
187
  add_action( 'admin_action_ewww_image_optimizer_remove_cloud_key', 'ewww_image_optimizer_remove_cloud_key' );
188
  // Non-AJAX handler to retest async/background mode.
189
  add_action( 'admin_action_ewww_image_optimizer_retest_background_optimization', 'ewww_image_optimizer_retest_background_optimization' );
190
+ // Non-AJAX handler to view the debug log, and display it.
191
+ add_action( 'admin_action_ewww_image_optimizer_view_debug_log', 'ewww_image_optimizer_view_debug_log' );
192
  // Non-AJAX handler to delete the debug log, and reroute back to the settings page.
193
  add_action( 'admin_action_ewww_image_optimizer_delete_debug_log', 'ewww_image_optimizer_delete_debug_log' );
194
  // Makes sure to flush out any scheduled jobs on deactivation.
195
  register_deactivation_hook( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE, 'ewww_image_optimizer_network_deactivate' );
 
 
196
  // add_action( 'shutdown', 'ewwwio_memory_output' );.
197
  // Makes sure we flush the debug info to the log on shutdown.
198
  add_action( 'shutdown', 'ewww_image_optimizer_debug_log' );
208
  * Setup page parsing classes after theme functions.php is loaded and plugins have run init routines.
209
  */
210
  function ewww_image_optimizer_parser_init() {
211
+ $buffer_start = false;
212
  // If ExactDN is enabled.
213
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) && empty( $_GET['exactdn_disable'] ) ) {
214
+ $buffer_start = true;
215
  /**
216
  * Page Parsing class for working with HTML content.
217
  */
226
  ewww_image_optimizer_set_option( 'autoptimize_cdn_url', '' );
227
  }
228
  }
229
+ // If Lazy Load is enabled.
230
+ if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) ) {
231
+ $buffer_start = true;
232
+ /**
233
+ * Page Parsing class for working with HTML content.
234
+ */
235
+ require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-page-parser.php' );
236
+ /**
237
+ * Alt WebP class for parsing image urls and rewriting them for WebP support.
238
+ */
239
+ require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-lazy-load.php' );
240
+ }
241
  // If Alt WebP Rewriting is enabled.
242
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) ) {
243
+ $buffer_start = true;
244
  /**
245
  * Page Parsing class for working with HTML content.
246
  */
250
  */
251
  require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-alt-webp.php' );
252
  }
253
+ if ( $buffer_start ) {
254
+ // Start an output buffer before any output starts.
255
+ add_action( 'template_redirect', 'ewww_image_optimizer_buffer_start', 0 );
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Starts an output buffer and registers the callback function to do WebP replacement.
261
+ */
262
+ function ewww_image_optimizer_buffer_start() {
263
+ ob_start( 'ewww_image_optimizer_filter_page_output' );
264
+ }
265
+
266
+ /**
267
+ * Run the page through any registered EWWW IO filters.
268
+ *
269
+ * @param string $buffer The full HTML page generated since the output buffer was started.
270
+ * @return string The altered buffer containing the full page with WebP images inserted.
271
+ */
272
+ function ewww_image_optimizer_filter_page_output( $buffer ) {
273
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
274
+ return apply_filters( 'ewww_image_optimizer_filter_page_output', $buffer );
275
  }
276
 
277
  /**
487
  */
488
  function ewww_image_optimizer_gallery_support() {
489
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
490
+
491
+ // Check to see if this is the settings page and enable debugging temporarily if it is.
492
+ global $ewwwio_temp_debug;
493
+ $ewwwio_temp_debug = false;
494
+ if ( is_admin() && ! wp_doing_ajax() ) {
495
+ if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
496
+ $ewwwio_temp_debug = true;
497
+ ewww_image_optimizer_set_option( 'ewww_image_optimizer_debug', true );
498
+ }
499
+ }
500
+
501
  $active_plugins = get_option( 'active_plugins' );
502
  if ( is_multisite() && is_array( $active_plugins ) ) {
503
  $sitewide_plugins = get_site_option( 'active_sitewide_plugins' );
565
  $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE 'wp_ewwwio_test_optimize_batch_%'" );
566
 
567
  }
568
+ if ( ! get_option( 'ewww_image_optimizer_version' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) {
569
+ add_option( 'exactdn_never_been_active', true, '', false );
570
+ }
571
  if ( get_option( 'ewww_image_optimizer_version' ) < 280 ) {
572
  ewww_image_optimizer_migrate_settings_to_levels();
573
  }
574
  if ( get_option( 'ewww_image_optimizer_version' ) < 407 ) {
575
+ add_option( 'exactdn_all_the_things', true );
576
  add_site_option( 'exactdn_all_the_things', true );
577
  }
578
  if ( get_option( 'ewww_image_optimizer_version' ) > 0 && get_option( 'ewww_image_optimizer_version' ) < 434 && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpegtran_copy' ) ) {
579
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_metadata_remove', false );
580
  }
581
  if ( get_option( 'ewww_image_optimizer_version' ) > 0 && get_option( 'ewww_image_optimizer_version' ) < 440 && ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) || ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_level' ) < 30 ) ) {
582
+ add_option( 'exactdn_lossy', true );
583
  add_site_option( 'exactdn_lossy', true );
584
  }
585
  if ( get_option( 'ewww_image_optimizer_version' ) < 454 ) {
713
  update_site_option( 'exactdn_all_the_things', $_POST['exactdn_all_the_things'] );
714
  $_POST['exactdn_lossy'] = ( empty( $_POST['exactdn_lossy'] ) ? false : true );
715
  update_site_option( 'exactdn_lossy', $_POST['exactdn_lossy'] );
716
+ $_POST['ewww_image_optimizer_lazy_load'] = ( empty( $_POST['ewww_image_optimizer_lazy_load'] ) ? false : true );
717
+ update_site_option( 'ewww_image_optimizer_lazy_load', $_POST['ewww_image_optimizer_lazy_load'] );
718
  $_POST['ewww_image_optimizer_maxmediawidth'] = empty( $_POST['ewww_image_optimizer_maxmediawidth'] ) ? 0 : $_POST['ewww_image_optimizer_maxmediawidth'];
719
  update_site_option( 'ewww_image_optimizer_maxmediawidth', (int) $_POST['ewww_image_optimizer_maxmediawidth'] );
720
  $_POST['ewww_image_optimizer_maxmediaheight'] = empty( $_POST['ewww_image_optimizer_maxmediaheight'] ) ? 0 : $_POST['ewww_image_optimizer_maxmediaheight'];
788
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_exactdn', 'boolval' );
789
  register_setting( 'ewww_image_optimizer_options', 'exactdn_all_the_things', 'boolval' );
790
  register_setting( 'ewww_image_optimizer_options', 'exactdn_lossy', 'boolval' );
791
+ register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_lazy_load', 'boolval' );
792
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_resize_detection', 'boolval' );
793
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_maxmediawidth', 'intval' );
794
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_maxmediaheight', 'intval' );
813
  add_action( 'network_admin_notices', 'ewww_image_optimizer_notice_invalid_key' );
814
  add_action( 'admin_notices', 'ewww_image_optimizer_notice_invalid_key' );
815
  }
816
+ // Prevent ShortPixel AIO messiness.
817
+ remove_action( 'admin_notices', 'autoptimizeMain::notice_plug_imgopt' );
818
+ if ( class_exists( 'autoptimizeExtra' ) ) {
819
+ $ao_extra = get_option( 'autoptimize_extra_settings' );
820
+ if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) && ! empty( $ao_extra['autoptimize_extra_checkbox_field_5'] ) ) {
821
+ ewwwio_debug_message( 'detected ExactDN + SP conflict' );
822
+ $ao_extra['autoptimize_extra_checkbox_field_5'] = 0;
823
+ update_option( 'autoptimize_extra_settings', $ao_extra );
824
+ add_action( 'admin_notices', 'ewww_image_optimizer_notice_exactdn_sp_conflict' );
825
+ }
826
+ }
827
+
828
  // Alert user if multiple re-optimizations detected.
829
  add_action( 'network_admin_notices', 'ewww_image_optimizer_notice_reoptimization' );
830
  add_action( 'admin_notices', 'ewww_image_optimizer_notice_reoptimization' );
839
  add_action( 'admin_notices', 'ewww_image_optimizer_thumbnail_regen_notice' );
840
  }
841
  }
842
+ if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_wc_regen' ) ) {
843
+ add_action( 'admin_notices', 'ewww_image_optimizer_notice_wc_regen' );
844
+ add_action( 'admin_footer', 'ewww_image_optimizer_wc_regen_script' );
845
+ }
846
  if ( ! empty( $_GET['ewww_pngout'] ) ) {
847
  add_action( 'admin_notices', 'ewww_image_optimizer_pngout_installed' );
848
  add_action( 'network_admin_notices', 'ewww_image_optimizer_pngout_installed' );
907
  if ( ! empty( $_REQUEST['action'] ) ) {
908
  if ( 'regeneratethumbnail' == $_REQUEST['action'] ||
909
  'meauh_save_image' == $_REQUEST['action'] ||
910
+ 'hotspot_save' == $_REQUEST['action']
 
911
  ) {
912
  ewwwio_debug_message( 'doing regeneratethumbnail' );
913
  ewww_image_optimizer_image_sizes( false );
921
  return;
922
  }
923
  }
924
+ if ( ! empty( $_REQUEST['action'] ) && false !== strpos( $_REQUEST['action'], 'wc_regenerate_images' ) ) {
925
+ // Unhook all automatic processing, and save an option that (does not autoload) tells the user WC regenerated their images and they should run the bulk optimizer.
926
+ remove_filter( 'wp_image_editors', 'ewww_image_optimizer_load_editor', 60 );
927
+ remove_filter( 'wp_generate_attachment_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15 );
928
+ update_option( 'ewww_image_optimizer_wc_regen', true, false );
929
+ return;
930
+ }
931
  // Check for Image Watermark plugin.
932
  if ( ! empty( $_POST['iw-action'] ) ) {
933
  $action = $_POST['iw-action'];
934
  ewwwio_debug_message( "doing $action" );
935
  global $ewww_preempt_editor;
936
  $ewww_preempt_editor = true;
 
937
  if ( 'applywatermark' === $action ) {
938
  remove_filter( 'wp_generate_attachment_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15 );
939
  add_action( 'iw_after_apply_watermark', 'ewww_image_optimizer_single_size_optimize', 10, 2 );
973
  wp_add_privacy_policy_content( 'EWWW Image Optimizer', $content );
974
  }
975
 
976
+ /**
977
+ * Check the current screen, currently used to temporarily enable debugging on settings page.
978
+ *
979
+ * @param object $screen Information about the page/screen currently being loaded.
980
+ */
981
+ function ewww_image_optimizer_current_screen( $screen ) {
982
+ global $ewwwio_temp_debug;
983
+ global $ewww_debug;
984
+ if ( false === strpos( $screen->id, 'settings_page_ewww-image-optimizer' ) ) {
985
+ if ( $ewwwio_temp_debug ) {
986
+ ewww_image_optimizer_set_option( 'ewww_image_optimizer_debug', false );
987
+ }
988
+ $ewwwio_temp_debug = false;
989
+ $ewww_debug = '';
990
+ }
991
+ }
992
+
993
  /**
994
  * Optimize a single image from an attachment, based on the size and ID.
995
  *
1466
  "</div>\n";
1467
  }
1468
  }
1469
+
1470
  /**
1471
  * Display a notice that PHP version 5.5 support is going away.
1472
  */
1474
  echo '<div id="ewww-image-optimizer-notice-php55" class="notice notice-info"><p><a href="https://docs.ewww.io/article/55-upgrading-php" target="_blank" data-beacon-article="5ab2baa6042863478ea7c2ae">' . esc_html__( 'The next major release of EWWW Image Optimizer will require PHP 5.6 or greater. Newer versions of PHP, like 7.1 and 7.2, are significantly faster and much more secure. If you are unsure how to upgrade to a supported version, ask your webhost for instructions.', 'ewww-image-optimizer' ) . '</a></p></div>';
1475
  }
1476
 
1477
+ /**
1478
+ * Inform the user that we disabled SP AIO to prevent conflicts with ExactDN.
1479
+ */
1480
+ function ewww_image_optimizer_notice_exactdn_sp_conflict() {
1481
+ echo "<div id='ewww-image-optimizer-exactdn-sp' class='notice notice-warning'><p>" . esc_html__( 'ShortPixel image optimization has been disabled to prevent conflicts with ExactDN (EWWW Image Optimizer).', 'ewww-image-optimizer' ) . '</p></div>';
1482
+ }
1483
+
1484
  /**
1485
  * Lets the user know their network settings have been saved.
1486
  */
1496
  echo '&nbsp;<a href="https://docs.ewww.io/article/49-regenerate-thumbnails" target="_blank" data-beacon-article="5a0f84ed2c7d3a272c0dc801">' . esc_html__( 'Learn more.', 'ewww-image-optimizer' ) . '</a></p></div>';
1497
  }
1498
 
1499
+ /**
1500
+ * Lets the user know WooCommerce has regenerated thumbnails and that they need to take action.
1501
+ */
1502
+ function ewww_image_optimizer_notice_wc_regen() {
1503
+ echo "<div id='ewww-image-optimizer-wc-regen' class='notice notice-info is-dismissible'><p>" . esc_html__( 'EWWW Image Optimizer has detected a WooCommerce thumbnail regeneration. To optimize new thumbnails, you may run the Bulk Optimizer from the Media menu. This notice may be dismissed after the regeneration is complete.', 'ewww-image-optimizer' ) . '</p></div>';
1504
+ }
1505
+
1506
+ /**
1507
+ * Loads the inline script to dismiss the WC regen notice.
1508
+ */
1509
+ function ewww_image_optimizer_wc_regen_script() {
1510
+ echo
1511
+ "<script>\n" .
1512
+ "jQuery(document).on('click', '#ewww-image-optimizer-wc-regen .notice-dismiss', function() {\n" .
1513
+ "\tvar ewww_dismiss_wc_regen_data = {\n" .
1514
+ "\t\taction: 'ewww_dismiss_wc_regen',\n" .
1515
+ "\t};\n" .
1516
+ "\tjQuery.post(ajaxurl, ewww_dismiss_wc_regen_data, function(response) {\n" .
1517
+ "\t\tif (response) {\n" .
1518
+ "\t\t\tconsole.log(response);\n" .
1519
+ "\t\t}\n" .
1520
+ "\t});\n" .
1521
+ "});\n" .
1522
+ "</script>\n";
1523
+ }
1524
+
1525
  /**
1526
  * Let the user know they can view more options and stats in the Media Library's list mode.
1527
  */
1626
  */
1627
  function ewww_image_optimizer_image_sizes( $sizes ) {
1628
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
 
1629
  global $ewww_preempt_editor;
1630
  $ewww_preempt_editor = true;
1631
  // This happens right after thumbs and meta are generated.
1677
  if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_noauto' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_disable_editor' ) ) {
1678
  global $ewww_preempt_editor;
1679
  $ewww_preempt_editor = true;
 
1680
  add_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_restore_editor_hooks', 1 );
1681
  add_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15, 2 );
1682
  }
1755
  }
1756
  global $ewww_preempt_editor;
1757
  $ewww_preempt_editor = true;
 
1758
  if ( class_exists( 'Meow_WR2X_Core' ) ) {
1759
  global $wr2x_core;
1760
  if ( is_object( $wr2x_core ) ) {
1764
  $meta = wr2x_wp_generate_attachment_metadata( $meta );
1765
  }
1766
  $ewww_preempt_editor = false;
 
1767
  return $meta;
1768
  }
1769
 
2057
  }
2058
  }
2059
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2060
  /**
2061
  * Adds a global settings page to the network admin settings menu.
2062
  */
2130
  'ewww_image_optimizer_network_singlesite_options' // Function to call.
2131
  );
2132
  }
2133
+ global $ewwwio_temp_debug;
2134
+ if ( ! $ewwwio_temp_debug && ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
2135
  // Add Dynamic Image Debugging page for image regeneration issues.
2136
  add_media_page( esc_html__( 'Dynamic Image Debugging', 'ewww-image-optimizer' ), esc_html__( 'Dynamic Image Debugging', 'ewww-image-optimizer' ), $permissions, 'ewww-image-optimizer-dynamic-debug', 'ewww_image_optimizer_dynamic_image_debug' );
2137
  // Add Image Queue Debugging to allow clearing and checking queues.
2138
  add_media_page( esc_html__( 'Image Queue Debugging', 'ewww-image-optimizer' ), esc_html__( 'Image Queue Debugging', 'ewww-image-optimizer' ), $permissions, 'ewww-image-optimizer-queue-debug', 'ewww_image_optimizer_image_queue_debug' );
2139
  // Add debug log page for viewing the log on hosts where you can't directly access it.
2140
+ /* add_media_page( esc_html__( 'EWWW IO Debug Log', 'ewww-image-optimizer' ), esc_html__( 'EWWW IO Debug Log', 'ewww-image-optimizer' ), $permissions, 'ewww-image-optimizer-debug-log-display', 'ewww_image_optimizer_debug_log_display' ); */
2141
  }
2142
  if ( is_plugin_active( 'image-store/ImStore.php' ) || is_plugin_active_for_network( 'image-store/ImStore.php' ) ) {
2143
  // Adds an optimize page for Image Store galleries and images.
3691
  *
3692
  * @since 4.4.0
3693
  *
3694
+ * @param string $file The file to resize.
3695
+ * @param string $type File type of the file.
3696
+ * @param int $dst_x X-coordinate of destination image (usually 0).
3697
+ * @param int $dst_y Y-coordinate of destination image (usually 0).
3698
+ * @param int $src_x X-coordinate of source image (usually 0 unless cropping).
3699
+ * @param int $src_y Y-coordinate of source image (usually 0 unless cropping).
3700
+ * @param int $dst_w Desired image width.
3701
+ * @param int $dst_h Desired image height.
3702
+ * @param int $src_w Source width.
3703
+ * @param int $src_h Source height.
3704
  * @return string|WP_Error The image contents or the error message.
3705
  */
3706
+ function ewww_image_optimizer_cloud_resize( $file, $type, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) {
3707
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
3708
  if ( ! ewwwio_check_memory_available( filesize( $file ) * 2.2 ) ) { // 2.2 = upload buffer + download buffer (2) multiplied by a factor of 1.1 for extra wiggle room.
3709
  $memory_required = filesize( $file ) * 2.2;
3731
  return new WP_Error( 'invalid_key', __( 'License Exceeded', 'ewww-image-optimizer' ) );
3732
  }
3733
  ewwwio_debug_message( "file: $file " );
3734
+ ewwwio_debug_message( "width: $dst_w" );
3735
+ ewwwio_debug_message( "height: $dst_h" );
3736
  $api_key = ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' );
3737
  if ( empty( $api_key ) ) {
3738
  return new WP_Error( 'invalid_key', __( 'Could not verify API key', 'ewww-image-optimizer' ) );
3754
  $post_fields = array(
3755
  'filename' => $file,
3756
  'api_key' => $api_key,
3757
+ 'dst_x' => (int) $dst_x,
3758
+ 'dst_y' => (int) $dst_y,
3759
+ 'src_x' => (int) $src_x,
3760
+ 'src_y' => (int) $src_y,
3761
+ 'dst_w' => (int) $dst_w,
3762
+ 'dst_h' => (int) $dst_h,
3763
+ 'src_w' => (int) $src_w,
3764
+ 'src_h' => (int) $src_h,
3765
  );
3766
 
3767
  $payload = '';
4250
  );
4251
  if ( get_site_option( 'ewww_image_optimizer_debug' ) ) {
4252
  global $ewww_debug;
4253
+ $output['results'] .= '<div style="background-color:#f1f1f1;">' . $ewww_debug . '</div>';
4254
  }
4255
  $next_file = ewww_image_optimizer_absolutize_path( $wpdb->get_var( "SELECT path FROM $wpdb->ewwwio_images WHERE pending=1 LIMIT 1" ) );
4256
  if ( ! empty( $next_file ) ) {
4307
  ewww_image_optimizer( $hidpi_path );
4308
  }
4309
 
4310
+ /**
4311
+ * Cleanup temp file for optimizing S3 Uploads image.
4312
+ *
4313
+ * @param string $file The filename of the temp file.
4314
+ * @return string The name of the file unaltered, or the s3 filename stored in $s3_uploads_image.
4315
+ */
4316
+ function ewww_image_optimizer_s3_uploads_image_cleanup( $file ) {
4317
+ global $s3_uploads_image;
4318
+ if ( ! ewww_image_optimizer_stream_wrapped( $file ) && strpos( $file, 's3-uploads' ) === false && ! empty( $s3_uploads_image ) ) {
4319
+ if ( is_file( $file ) ) {
4320
+ unlink( $file );
4321
+ }
4322
+ $file = $s3_uploads_image;
4323
+ unset( $s3_uploads_image );
4324
+ }
4325
+ return $file;
4326
+ }
4327
+
4328
+ /**
4329
+ * Checks the existence of a cloud storage stream wrapper.
4330
+ *
4331
+ * @return bool True if a supported stream wrapper is found, false otherwise.
4332
+ */
4333
+ function ewww_image_optimizer_stream_wrapper_exists() {
4334
+ $wrappers = stream_get_wrappers();
4335
+ if ( ! ewww_image_optimizer_iterable( $wrappers ) ) {
4336
+ return false;
4337
+ }
4338
+ foreach ( $wrappers as $wrapper ) {
4339
+ if ( strpos( $wrapper, 's3' ) === 0 ) {
4340
+ return true;
4341
+ }
4342
+ if ( strpos( $wrapper, 'gs' ) === 0 ) {
4343
+ return true;
4344
+ }
4345
+ }
4346
+ return false;
4347
+ }
4348
+
4349
+ /**
4350
+ * Checks the filename for an S3 or GCS stream wrapper.
4351
+ *
4352
+ * @param string $filename The filename to be searched.
4353
+ * @return bool True if a stream wrapper is found, false otherwise.
4354
+ */
4355
+ function ewww_image_optimizer_stream_wrapped( $filename ) {
4356
+ if ( false !== strpos( $filename, '://' ) ) {
4357
+ if ( strpos( $filename, 's3' ) === 0 ) {
4358
+ return true;
4359
+ }
4360
+ if ( strpos( $filename, 'gs' ) === 0 ) {
4361
+ return true;
4362
+ }
4363
+ }
4364
+ return false;
4365
+ }
4366
+
4367
  /**
4368
  * Fetches images from S3 or Azure storage so that they can be optimized locally.
4369
  *
4381
  if ( class_exists( 'Amazon_S3_And_CloudFront' ) ) {
4382
  global $as3cf;
4383
  $full_url = get_attached_file( $id );
4384
+ if ( ewww_image_optimizer_stream_wrapped( $full_url ) ) {
4385
  $full_url = $as3cf->get_attachment_url( $id, null, null, $meta );
4386
  }
4387
  $filename = get_attached_file( $id, true );
4689
  *
4690
  * @since 4.4.0
4691
  *
4692
+ * @param string $file The file to resize.
4693
+ * @param int $dst_x X-coordinate of destination image (usually 0).
4694
+ * @param int $dst_y Y-coordinate of destination image (usually 0).
4695
+ * @param int $src_x X-coordinate of source image (usually 0 unless cropping).
4696
+ * @param int $src_y Y-coordinate of source image (usually 0 unless cropping).
4697
+ * @param int $dst_w Desired image width.
4698
+ * @param int $dst_h Desired image height.
4699
+ * @param int $src_w Source width.
4700
+ * @param int $src_h Source height.
4701
  * @return string|WP_Error The image contents or the error message.
4702
  */
4703
+ function ewww_image_optimizer_better_resize( $file, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) {
4704
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
4705
+ ewwwio_debug_message( "resizing to $dst_w and $dst_h" );
4706
+ if ( $dst_x || $dst_y ) {
4707
  ewwwio_debug_message( 'cropping too' );
4708
  $crop = true;
4709
  }
4713
  return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $file );
4714
  }
4715
  if ( 'image/gif' == $type && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) && function_exists( 'ewww_image_optimizer_gifsicle_resize' ) ) {
4716
+ return ewww_image_optimizer_gifsicle_resize( $file, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h );
4717
  }
4718
+ return ewww_image_optimizer_cloud_resize( $file, $type, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h );
4719
  }
4720
 
4721
  /**
4931
  // From here...
4932
  global $ewww_preempt_editor;
4933
  $ewww_preempt_editor = true;
4934
+
4935
  $editor = wp_get_image_editor( $file );
4936
  if ( is_wp_error( $editor ) ) {
4937
  ewwwio_debug_message( 'could not get image editor' );
4980
  }
4981
  // to here is replaced by cloud/API function.
4982
  $new_size = ewww_image_optimizer_filesize( $new_file );
4983
+ if ( apply_filters( 'ewww_image_optimizer_resize_filesize_ignore', false ) || ( $new_size && $new_size < $orig_size ) ) {
4984
  // Use this action to perform any operations on the original file before it is overwritten with the new, smaller file.
4985
  do_action( 'ewww_image_optimizer_image_resized', $file, $new_file );
4986
  ewwwio_debug_message( "after resizing: $new_size" );
5316
  if ( is_file( $file ) ) {
5317
  global $ewww_preempt_editor;
5318
  $ewww_preempt_editor = true;
 
5319
  remove_all_filters( 'wp_generate_attachment_metadata' );
5320
  ewwwio_debug_message( "generating new meta for $attachment_id" );
5321
  $meta = wp_generate_attachment_metadata( $attachment_id, $file );
5414
  if ( 'ims_image' == get_post_type( $id ) ) {
5415
  $gallery_type = 6;
5416
  }
5417
+ if ( ! $new_image && class_exists( 'Amazon_S3_And_CloudFront' ) && ewww_image_optimizer_stream_wrapped( $file_path ) ) {
5418
  ewww_image_optimizer_check_table_as3cf( $meta, $id, $file_path );
5419
  }
5420
  // If the local file is missing and we have valid metadata, see if we can fetch via CDN.
5421
+ if ( ! is_file( $file_path ) || ( ewww_image_optimizer_stream_wrapped( $file_path ) && ! class_exists( 'S3_Uploads' ) ) ) {
5422
  $file_path = ewww_image_optimizer_remote_fetch( $id, $meta );
5423
  if ( ! $file_path ) {
5424
  ewwwio_debug_message( 'could not retrieve path' );
6071
  $file_path = ( 0 !== strpos( $file, '/' ) && ! preg_match( '|^.:\\\|', $file ) ? $upload_path . $file : $file );
6072
  $filtered_file_path = apply_filters( 'get_attached_file', $file_path, $id );
6073
  ewwwio_debug_message( "WP (filtered) thinks the file is at: $filtered_file_path" );
6074
+ if (
6075
+ (
6076
+ ! ewww_image_optimizer_stream_wrapped( $filtered_file_path ) ||
6077
+ ewww_image_optimizer_stream_wrapper_exists()
6078
+ )
6079
+ && is_file( $filtered_file_path )
6080
+ ) {
6081
  return array( str_replace( '//_imsgalleries/', '/_imsgalleries/', $filtered_file_path ), $upload_path );
6082
  }
6083
  ewwwio_debug_message( "WP (unfiltered) thinks the file is at: $file_path" );
6084
+ if (
6085
+ (
6086
+ ! ewww_image_optimizer_stream_wrapped( $file_path ) ||
6087
+ ewww_image_optimizer_stream_wrapper_exists()
6088
+ )
6089
+ && is_file( $file_path )
6090
+ ) {
6091
  return array( str_replace( '//_imsgalleries/', '/_imsgalleries/', $file_path ), $upload_path );
6092
  }
6093
  if ( 'ims_image' == get_post_type( $id ) && is_array( $meta ) && ! empty( $meta['file'] ) ) {
6113
  }
6114
  if ( is_array( $meta ) && ! empty( $meta['file'] ) ) {
6115
  $file_path = $meta['file'];
6116
+ if ( ewww_image_optimizer_stream_wrapped( $file_path ) && ! ewww_image_optimizer_stream_wrapper_exists() ) {
6117
  return array( '', $upload_path );
6118
  }
6119
  ewwwio_debug_message( "looking for file at $file_path" );
6150
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE' ) || ! EWWW_IMAGE_OPTIMIZER_RELATIVE ) {
6151
  return $file;
6152
  }
 
6153
  if ( defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER' ) && EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER && strpos( $file, EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER ) === 0 ) {
6154
  ewwwio_debug_message( "removing custom relative folder from $file" );
6155
  return str_replace( EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER, 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER', $file );
6179
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE' ) ) {
6180
  return $file;
6181
  }
 
6182
  if ( defined( 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER' ) && EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER && strpos( $file, 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER' ) === 0 ) {
6183
  ewwwio_debug_message( "replacing custom relative folder in $file" );
6184
  return str_replace( 'EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER', EWWW_IMAGE_OPTIMIZER_RELATIVE_FOLDER, $file );
6292
  case 'pdf':
6293
  return 'application/pdf';
6294
  default:
6295
+ if ( empty( $pathextension ) && ! ewww_image_optimizer_stream_wrapped( $path ) && is_file( $path ) ) {
6296
  return ewww_image_optimizer_mimetype( $path, 'i' );
6297
  }
6298
  return false;
6442
  $print_meta = print_r( $meta, true );
6443
  $print_meta = preg_replace( array( '/ /', '/\n+/' ), array( '&nbsp;', '<br />' ), $print_meta );
6444
  $debug_button = esc_html__( 'Show Metadata', 'ewww-image-optimizer' );
6445
+ $output .= "<button type='button' class='ewww-show-debug-meta button button-secondary' data-id='$id'>$debug_button</button><div id='ewww-debug-meta-$id' style='font-size: 10px;padding: 10px;margin:3px -10px 10px;line-height: 1.1em;display: none;'>$print_meta</div>";
6446
  }
6447
  $output .= "<div id='ewww-media-status-$id'>";
6448
  $ewww_cdn = false;
6458
  $output .= '<div>' . esc_html__( 'Azure Storage image', 'ewww-image-optimizer' ) . '</div>';
6459
  $ewww_cdn = true;
6460
  }
6461
+ if ( is_array( $meta ) && class_exists( 'Amazon_S3_And_CloudFront' ) && preg_match( '/^(http|s3|gs)\w*:/', get_attached_file( $id ) ) ) {
6462
+ $output .= '<div>' . esc_html__( 'Offloaded Media', 'ewww-image-optimizer' ) . '</div>';
6463
  $ewww_cdn = true;
6464
  }
6465
+ if ( is_array( $meta ) && class_exists( 'S3_Uploads' ) && preg_match( '/^(http|s3|gs)\w*:/', get_attached_file( $id ) ) ) {
6466
  $output .= '<div>' . esc_html__( 'Amazon S3 image', 'ewww-image-optimizer' ) . '</div>';
6467
  $ewww_cdn = true;
6468
  }
7052
  return $meta;
7053
  }
7054
 
7055
+ /**
7056
+ * Dismisses the WC regen notice.
7057
+ */
7058
+ function ewww_image_optimizer_dismiss_wc_regen() {
7059
+ ewwwio_ob_clean();
7060
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
7061
+ // Verify that the user is properly authorized.
7062
+ if ( ! current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', 'manage_options' ) ) ) {
7063
+ wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) );
7064
+ }
7065
+ delete_option( 'ewww_image_optimizer_wc_regen' );
7066
+ wp_die();
7067
+ }
7068
+
7069
  /**
7070
  * Disables the Media Library notice about List Mode.
7071
  */
7584
  * @param string $network Indicates which options should be shown in multisite installations.
7585
  */
7586
  function ewww_image_optimizer_options( $network = 'singlesite' ) {
7587
+ global $ewwwio_temp_debug;
7588
+ global $content_width;
7589
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
7590
  ewwwio_debug_version_info();
7591
  ewwwio_debug_message( 'ABSPATH: ' . ABSPATH );
7593
  ewwwio_debug_message( 'home url: ' . get_home_url() );
7594
  ewwwio_debug_message( 'site url: ' . get_site_url() );
7595
  ewwwio_debug_message( 'content_url: ' . content_url() );
7596
+ ewwwio_debug_message( "content_width: $content_width" );
7597
+ ewwwio_debug_message( 'registered stream wrappers: ' . implode( ',', stream_get_wrappers() ) );
7598
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_NOEXEC' ) ) {
7599
  if ( defined( 'EWWW_IMAGE_OPTIMIZER_CLOUD' ) && EWWW_IMAGE_OPTIMIZER_CLOUD ) {
7600
  ewww_image_optimizer_disable_tools();
7634
  "</style>\n";
7635
  $output[] = "<div class='wrap'>\n";
7636
  $output[] = "<h1>EWWW Image Optimizer</h1>\n";
7637
+ $output[] = "<!--<div id='ewww-container-left' style='float: left; margin-right: 225px;'>-->\n";
 
 
 
 
 
7638
  if ( 'network-multisite' == $network ) {
7639
  $bulk_link = esc_html__( 'Media Library', 'ewww-image-optimizer' ) . ' -> ' . esc_html__( 'Bulk Optimize', 'ewww-image-optimizer' );
7640
  } else {
7661
  $compress_recommendations = array();
7662
  $resize_recommendations = array();
7663
 
7664
+ $status_output = "<div id='ewww-widgets' class='metabox-holder' style='max-width:1170px;'><div class='meta-box-sortables'><div id='ewww-status' class='postbox'>\n" .
7665
  "<h2 class='ewww-hndle'>" . esc_html__( 'Optimization Status', 'ewww-image-optimizer' ) . "</h2>\n<div class='inside'>";
7666
 
7667
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) ) {
7974
  "<li class='ewww-tab ewww-conversion-nav'><span class='ewww-tab-hidden'>" . esc_html__( 'Convert', 'ewww-image-optimizer' ) . "</span></li>\n" .
7975
  "<li class='ewww-tab ewww-webp-nav'><span class='ewww-tab-hidden'>" . esc_html__( 'WebP', 'ewww-image-optimizer' ) . "</span></li>\n" .
7976
  "<li class='ewww-tab ewww-overrides-nav'><span class='ewww-tab-hidden'><a href='https://docs.ewww.io/article/40-override-options' target='_blank'><span class='ewww-tab-hidden'>" . esc_html__( 'Overrides', 'ewww-image-optimizer' ) . "</a></span></li>\n" .
7977
+ "<li class='ewww-tab ewww-support-nav'><span class='ewww-tab-hidden'>" . esc_html__( 'Support', 'ewww-image-optimizer' ) . "</span></li>\n" .
7978
+ "<li class='ewww-tab ewww-contribute-nav'><span class='ewww-tab-hidden'>" . esc_html__( 'Contribute', 'ewww-image-optimizer' ) . "</span></li>\n" .
7979
  "</ul>\n";
7980
  }
7981
  if ( 'network-multisite' == $network ) {
7995
  ewwwio_debug_message( 'automatic compression enabled' );
7996
  }
7997
  $output[] = "<div id='ewww-general-settings'>\n";
7998
+ $output[] = '<noscript><h2>' . esc_html__( 'Basic', 'ewww-image-optimizer' ) . '</h2></noscript>';
7999
  $output[] = "<table class='form-table'>\n";
8000
  if ( is_multisite() ) {
8001
  if ( is_plugin_active_for_network( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE_REL ) ) {
8023
  } else {
8024
  $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_cloud_key'>" . esc_html__( 'Optimization API Key', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/7-basic-configuration', '585373d5c697912ffd6c0bb2,5ad0c8e7042863075092650b,5a9efec62c7d3a7549516550' ) . "</th><td><input type='text' id='ewww_image_optimizer_cloud_key' name='ewww_image_optimizer_cloud_key' value='' size='32' /> " . esc_html__( 'API Key will be validated when you save your settings.', 'ewww-image-optimizer' ) . " <a href='https://ewww.io/plans/' target='_blank'>" . esc_html__( 'Purchase an API key.', 'ewww-image-optimizer' ) . "</a></td></tr>\n";
8025
  }
 
 
8026
  $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_metadata_remove'>" . esc_html__( 'Remove Metadata', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/7-basic-configuration', '585373d5c697912ffd6c0bb2' ) . "</th>\n" .
8027
  "<td><input type='checkbox' id='ewww_image_optimizer_metadata_remove' name='ewww_image_optimizer_metadata_remove' value='true' " . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_metadata_remove' ) == true ? "checked='true'" : '' ) . ' /> ' . esc_html__( 'This will remove ALL metadata: EXIF, comments, color profiles, and anything else that is not pixel data.', 'ewww-image-optimizer' ) .
8028
  "<p class ='description'>" . esc_html__( 'Color profiles are preserved when using the API or ExactDN.', 'ewww-image-optimizer' ) . "</p></td></tr>\n";
8083
  $output[] = "</table>\n</div>\n";
8084
  $output[] = "<div id='ewww-exactdn-settings'>\n";
8085
  $output[] = "<table class='form-table'>\n";
8086
+ $output[] = '<noscript><h2>' . esc_html__( 'ExactDN', 'ewww-image-optimizer' ) . '</h2></noscript>';
8087
  $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_exactdn'>" . esc_html__( 'ExactDN', 'ewww-image-optimizer' ) .
8088
  '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/44-introduction-to-exactdn', '59bc5ad6042863033a1ce370,59de6631042863379ddc953c,59c44349042863033a1d06d3,5ada43a12c7d3a0e93678b8c,5a3d278a2c7d3a1943677b52,5a9868eb04286374f7087795,59de68482c7d3a40f0ed6035,592dd69b2c7d3a074e8aed5b' ) . "</th><td><input type='checkbox' id='ewww_image_optimizer_exactdn' name='ewww_image_optimizer_exactdn' value='true' " .
8089
  ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) == true ? "checked='true'" : '' ) . ' /> ' .
8105
  $output[] = "<tr class='$network_class'><th scope='row'><label for='exactdn_lossy'>" . esc_html__( 'Premium Compression', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/47-getting-more-from-exactdn', '59de6631042863379ddc953c' ) . '</th>' .
8106
  "<td><input type='checkbox' id='exactdn_lossy' name='exactdn_lossy' value='true' " .
8107
  ( ewww_image_optimizer_get_option( 'exactdn_lossy' ) ? "checked='true'" : '' ) . '> ' . esc_html__( 'Enable high quality premium compression for all images. Disable to use Pixel Perfect mode instead.', 'ewww-image-optimizer' ) . "</td></tr>\n";
8108
+ $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_lazy_load'>" . esc_html__( 'Lazy Load', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/74-lazy-load', '5c6c36ed042863543ccd2d9b' ) .
8109
+ "</th><td><input type='checkbox' id='ewww_image_optimizer_lazy_load' name='ewww_image_optimizer_lazy_load' value='true' " . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) == true ? "checked='true'" : '' ) . ' /> ' .
8110
+ esc_html__( 'Improves actual and perceived loading time as images will be loaded only as they enter (or are about to enter) the viewport. When used with the ExactDN and WebP features, the plugin will load the best available image size and format for each device.', 'ewww-image-optimizer' ) . "</td></tr>\n";
8111
  ewwwio_debug_message( 'ExactDN lossy: ' . intval( ewww_image_optimizer_get_option( 'exactdn_lossy' ) ) );
8112
  ewwwio_debug_message( 'ExactDN resize existing: ' . ( ewww_image_optimizer_get_option( 'exactdn_resize_existing' ) == true ? 'on' : 'off' ) );
8113
  ewwwio_debug_message( 'ExactDN attachment queries: ' . ( ewww_image_optimizer_get_option( 'exactdn_prevent_db_queries' ) == true ? 'off' : 'on' ) );
8114
+ ewwwio_debug_message( 'lazy load: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) == true ? 'on' : 'off' ) );
8115
  if ( defined( 'EXACTDN_EXCLUDE' ) && EXACTDN_EXCLUDE ) {
8116
  $exactdn_user_exclusions = EXACTDN_EXCLUDE;
8117
  if ( is_array( $exactdn_user_exclusions ) ) {
8124
  }
8125
  $output[] = "</table>\n</div>\n";
8126
  $output[] = "<div id='ewww-optimization-settings'>\n";
8127
+ $output[] = '<noscript><h2>' . esc_html__( 'Advanced', 'ewww-image-optimizer' ) . '</h2></noscript>';
8128
  $output[] = "<table class='form-table'>\n";
8129
  if ( ! ewww_image_optimizer_full_cloud() ) {
8130
  ewwwio_debug_message( 'optipng level: ' . ewww_image_optimizer_get_option( 'ewww_image_optimizer_optipng_level' ) );
8210
  ewwwio_debug_message( 'exclude originals from lossy: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_lossy_skip_full' ) == true ? 'on' : 'off' ) );
8211
  ewwwio_debug_message( 'exclude originals from metadata removal: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_metadata_skip_full' ) == true ? 'on' : 'off' ) );
8212
  ewwwio_debug_message( 'use system binaries: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_bundle' ) == true ? 'yes' : 'no' ) );
 
 
 
 
 
8213
  $output[] = "</table>\n</div>\n";
8214
 
8215
  $output[] = "<div id='ewww-resize-settings'>\n";
8216
+ $output[] = '<noscript><h2>' . esc_html__( 'Resize', 'ewww-image-optimizer' ) . '</h2></noscript>';
8217
  $output[] = "<table class='form-table'>\n";
8218
  $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_resize_detection'>" . esc_html__( 'Resize Detection', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/41-resize-settings', '59849911042863033a1ba5f9' ) . "</th><td><input type='checkbox' id='ewww_image_optimizer_resize_detection' name='ewww_image_optimizer_resize_detection' value='true' " . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_detection' ) == true ? "checked='true'" : '' ) . ' /> ' . esc_html__( 'Highlight images that need to be resized because the browser is scaling them down. Only visible for Admin users and adds a button to the admin bar to detect scaled images that have been lazy loaded.', 'ewww-image-optimizer' ) . "</td></tr>\n";
8219
  ewwwio_debug_message( 'resize detection: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_detection' ) == true ? 'on' : 'off' ) );
8256
  $output[] = '<p><span style="color: #3eadc9">' . esc_html__( '*Settings to disable creation and optimization of individual sizes must be configured for each individual site.', 'ewww-image-optimizer' ) . "</span></p></td></tr>\n";
8257
  }
8258
  $output[] = "</table>\n</div>\n";
8259
+
8260
  $output[] = "<div id='ewww-conversion-settings'>\n";
8261
+ $output[] = '<noscript><h2>' . esc_html__( 'Convert', 'ewww-image-optimizer' ) . '</h2></noscript>';
8262
  $output[] = '<p>' . esc_html__( 'Conversion is only available for images in the Media Library (except WebP). By default, all images have a link available in the Media Library for one-time conversion. Turning on individual conversion operations below will enable conversion filters any time an image is uploaded or modified.', 'ewww-image-optimizer' ) . "<br />\n" .
8263
  '<b>' . esc_html__( 'NOTE:', 'ewww-image-optimizer' ) . '</b> ' . esc_html__( 'The plugin will attempt to update image locations for any posts that contain the images. You may still need to manually update locations/urls for converted images.', 'ewww-image-optimizer' ) . "\n" .
8264
  "</p>\n";
8292
  '<p><span style="color: #3eadc9">' . esc_html__( 'Image conversion requires one of the following PHP libraries: GD, Imagick, or GMagick.', 'ewww-image-optimizer' ) . "</span></p></td></tr>\n";
8293
  }
8294
  $output[] = "</table>\n</div>\n";
8295
+
8296
  $output[] = "<div id='ewww-webp-settings'>\n";
8297
+ $output[] = '<noscript><h2>' . esc_html__( 'WebP', 'ewww-image-optimizer' ) . '</h2></noscript>';
8298
  $output[] = "<table class='form-table'>\n";
8299
  if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) || ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' ) ) {
8300
  $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_webp'>" . esc_html__( 'JPG/PNG to WebP', 'ewww-image-optimizer' ) . '</label>' .
8324
  esc_html__( 'JS WebP Rewriting', 'ewww-image-optimizer' ) .
8325
  '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/16-ewww-io-and-webp-images', '5854745ac697912ffd6c1c89,59443d162c7d3a0747cdf9f0' ) . "</th><td><span><input type='checkbox' id='ewww_image_optimizer_webp_for_cdn' name='ewww_image_optimizer_webp_for_cdn' value='true' " .
8326
  ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) == true ? "checked='true'" : '' ) . ' /> ' .
8327
+ ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ? esc_html( 'Enables automatic WebP conversion with ExactDN.', 'ewww-image-optimizer' ) : esc_html__( 'Use this if the Apache rewrite rules do not work, or if your images are served from a CDN.', 'ewww-image-optimizer' ) ) . ' ' .
 
8328
  /* translators: %s: Cache Enabler (link) */
8329
  ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ? sprintf( esc_html__( 'Sites using a CDN may also use the WebP option in the %s plugin.', 'ewww-image-optimizer' ), '<a href="https://wordpress.org/plugins/cache-enabler/">Cache Enabler</a>' ) : '' ) . '</span></td></tr>';
8330
  }
8331
  ewwwio_debug_message( 'alt webp rewriting: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) == true ? 'on' : 'off' ) );
8332
  $output[] = "</table>\n</div>\n";
8333
+
8334
+ $output[] = "<div id='ewww-support-settings'>\n";
8335
+ $output[] = '<noscript><h2>' . esc_html__( 'Support', 'ewww-image-optimizer' ) . '</h2></noscript>';
8336
+ $output[] = "<p><a class='ewww-docs-root' href='https://docs.ewww.io/'>" . esc_html__( 'Documentation', 'ewww-image-optimizer' ) . '</a> | ' .
8337
+ "<a class='ewww-docs-root' href='https://ewww.io/contact-us/'>" . esc_html__( 'Plugin Support', 'ewww-image-optimizer' ) . '</a> | ' .
8338
+ "<a href='https://ewww.io/status/'>" . esc_html__( 'Server Status', 'ewww-image-optimizer' ) . '</a>' .
8339
+ "</p>\n";
8340
+ $output[] = "<table class='form-table'>\n";
8341
+ $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_enable_help'>" . esc_html__( 'Enable Embedded Help', 'ewww-image-optimizer' ) . "</label></th><td><input type='checkbox' id='ewww_image_optimizer_enable_help' name='ewww_image_optimizer_enable_help' value='true' " . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help' ) == true ? "checked='true'" : '' ) . ' /> ' .
8342
+ esc_html__( 'Enable the support beacon, which gives you access to documentation and our support team right from your WordPress dashboard. To assist you more efficiently, we may collect the current url, IP address, browser/device information, and debugging information.', 'ewww-image-optimizer' ) . "</td></tr>\n";
8343
+ ewwwio_debug_message( 'enable help beacon: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help' ) == true ? 'yes' : 'no' ) );
8344
+ $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_debug'>" . esc_html__( 'Debugging', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/7-basic-configuration', '585373d5c697912ffd6c0bb2' ) . '</th>' .
8345
+ "<td><input type='checkbox' id='ewww_image_optimizer_debug' name='ewww_image_optimizer_debug' value='true' " . ( ! $ewwwio_temp_debug && ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) == true ? "checked='true'" : '' ) . ' /> ' . esc_html__( 'Use this to provide information for support purposes, or if you feel comfortable digging around in the code to fix a problem you are experiencing.', 'ewww-image-optimizer' ) . "</td></tr>\n";
8346
+ $output[] = "</table>\n";
8347
+ if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
8348
+ $output[] = 'DEBUG_PLACEHOLDER';
8349
+ }
8350
+ $output[] = "</div>\n";
8351
+
8352
+ $output[] = "<div id='ewww-contribute-settings'>\n";
8353
+ $output[] = '<noscript><h2>' . esc_html__( 'Contribute', 'ewww-image-optimizer' ) . '</h2></noscript>';
8354
+ $output[] = '<p><strong>' . esc_html__( 'Here are some ways you can contribute to the development of this plugin:', 'ewww-image-optimizer' ) . "</strong></p>\n";
8355
+ $output[] = "<p><a href='https://translate.wordpress.org/projects/wp-plugins/ewww-image-optimizer/'>" . esc_html__( 'Translate EWWW I.O.', 'ewww-image-optimizer' ) . '</a> | ' .
8356
+ "<a href='https://wordpress.org/support/view/plugin-reviews/ewww-image-optimizer#postform'>" . esc_html__( 'Write a review', 'ewww-image-optimizer' ) . '</a> | ' .
8357
+ "<a href='https://ewww.io/plans/'>" . esc_html__( 'Upgrade to premium image optimization', 'ewww-image-optimizer' ) . "</a></p>\n";
8358
+ $output[] = "<table class='form-table'>\n";
8359
+ $output[] = "<tr class='$network_class'><th scope='row'><label for='ewww_image_optimizer_allow_tracking'>" . esc_html__( 'Allow Usage Tracking?', 'ewww-image-optimizer' ) . '</label>' . ewwwio_help_link( 'https://docs.ewww.io/article/23-usage-tracking', '591f3a8e2c7d3a057f893d91' ) . "</th><td><input type='checkbox' id='ewww_image_optimizer_allow_tracking' name='ewww_image_optimizer_allow_tracking' value='true' " . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_allow_tracking' ) == true ? "checked='true'" : '' ) . ' /> ' .
8360
+ esc_html__( 'Allow EWWW Image Optimizer to anonymously track how this plugin is used and help us make the plugin better. Opt-in to tracking and receive 500 API image credits free. No sensitive data is tracked.', 'ewww-image-optimizer' ) . "</td></tr>\n";
8361
+ $output[] = "</table>\n";
8362
+ $output[] = "</div>\n";
8363
+
8364
  $output[] = "<p class='submit'><input type='submit' class='button-primary' value='" . esc_attr__( 'Save Changes', 'ewww-image-optimizer' ) . "' /></p>\n";
8365
  $output[] = "</form>\n";
8366
  // Make sure .htaccess rules are terminated when ExactDN is enabled.
8383
  if ( ! ewww_image_optimizer_webp_rewrite_verify() ) {
8384
  $output[] = "<img id='webp-image' src='" . plugins_url( '/images/test.png', __FILE__ ) . "' style='float: right; padding: 0 0 10px 10px;'>\n" .
8385
  "<p id='ewww-webp-rewrite-status'><b>" . esc_html__( 'Rules verified successfully', 'ewww-image-optimizer' ) . "</b></p>\n" .
8386
+ "<button type='button' id='ewww-webp-remove' class='button-secondary action'>" . esc_html__( 'Remove Rewrite Rules', 'ewww-image-optimizer' ) . "</button>\n";
8387
  ewwwio_debug_message( 'webp .htaccess rewriting enabled' );
8388
  } else {
8389
  $output[] = "<pre id='webp-rewrite-rules' style='background: white; font-color: black; border: 1px solid black; clear: both; padding: 10px;'>\n" .
8401
  "AddType image/webp .webp</pre>\n" .
8402
  "<img id='webp-image' src='" . plugins_url( '/images/test.png', __FILE__ ) . "' style='float: right; padding-left: 10px;'>\n" .
8403
  "<p id='ewww-webp-rewrite-status'>" . esc_html__( 'The image to the right will display a WebP image with WEBP in white text, if your site is serving WebP images and your browser supports WebP.', 'ewww-image-optimizer' ) . "</p>\n" .
8404
+ "<button type='button' id='ewww-webp-insert' class='button-secondary action'>" . esc_html__( 'Insert Rewrite Rules', 'ewww-image-optimizer' ) . "</button>\n";
8405
  ewwwio_debug_message( 'webp .htaccess rules not detected' );
8406
  }
8407
  $output[] = "</form>\n";
8410
  $test_png_image = plugins_url( '/images/test.png', __FILE__ );
8411
  $output[] = "<noscript data-img='$test_png_image' data-webp='$test_webp_image' data-style='float: right; padding: 0 0 10px 10px;' class='ewww_webp'><img src='$test_png_image' style='float: right; padding: 0 0 10px 10px;'></noscript>\n";
8412
  }
8413
+ $output[] = "<!--</div>--><!-- end container left -->\n";
8414
+ $output[] = "<!--<div id='ewww-container-right' style='border: 1px solid #e5e5e5; float: right; margin-left: -215px; padding: 0em 1.5em 1em; background-color: #fff; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); display: inline-block; width: 174px;'>\n" .
8415
  '<h2>' . esc_html__( 'Support EWWW I.O.', 'ewww-image-optimizer' ) . "</h2>\n" .
 
8416
  "<p><a href='https://translate.wordpress.org/projects/wp-plugins/ewww-image-optimizer/'>" . esc_html__( 'Help translate EWWW I.O.', 'ewww-image-optimizer' ) . "</a></p>\n" .
8417
  "<p><a href='https://wordpress.org/support/view/plugin-reviews/ewww-image-optimizer#postform'>" . esc_html__( 'Write a review.', 'ewww-image-optimizer' ) . "</a></p>\n" .
8418
  '<p>' . esc_html__( 'Signup for premium image optimization:', 'ewww-image-optimizer' ) . "<br>\n" .
8419
  "<a target='_blank' href='https://ewww.io/plans/'>" . esc_html__( 'Compress', 'ewww-image-optimizer' ) . "</a><br>\n" .
8420
  "<a target='_blank' href='https://ewww.io/resize/'>" . esc_html__( 'Resize', 'ewww-image-optimizer' ) . "</a></p>\n" .
8421
  '<p><b>' . esc_html_x( 'CDN:', 'abbreviation for Content Delivery Network', 'ewww-image-optimizer' ) . "</b><br><a target='_blank' href='https://ewww.io/resize/'>" . esc_html__( 'Add ExactDN to increase website speeds dramatically!', 'ewww-image-optimizer' ) . "</a></p>\n" .
8422
+ "</div>-->\n" .
8423
  "</div>\n";
8424
  ewwwio_debug_message( 'max_execution_time: ' . ini_get( 'max_execution_time' ) );
8425
  ewww_image_optimizer_stl_check();
8428
  if ( 'debug-silent' === $network ) {
8429
  return;
8430
  }
8431
+ $output = apply_filters( 'ewww_image_optimizer_settings', $output );
8432
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) && ! ewww_image_optimizer_ce_webp_enabled() ) {
8433
  global $ewwwio_alt_webp;
8434
  $ewwwio_alt_webp->inline_script();
8438
  esc_html__( 'This will allow us to assist you more quickly.', 'ewww-image-optimizer' );
8439
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
8440
  global $ewww_debug;
8441
+
8442
+ $debug_output = '<p style="clear:both"><b>' . esc_html__( 'Debugging Information', 'ewww-image-optimizer' ) . ':</b> <button id="ewww-copy-debug" class="button button-secondary" type="button">' . esc_html__( 'Copy', 'ewww-image-optimizer' ) . '</button>';
8443
  if ( is_file( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'debug.log' ) ) {
8444
+ $debug_output .= "&emsp;<a href='admin.php?action=ewww_image_optimizer_view_debug_log'>" . esc_html( 'View Debug Log', 'ewww-image-optimizer' ) . "</a> - <a href='admin.php?action=ewww_image_optimizer_delete_debug_log'>" . esc_html( 'Remove Debug Log', 'ewww-image-optimizer' ) . '</a>';
 
8445
  }
8446
+ $debug_output .= '</p>';
8447
+ $debug_output .= '<div id="ewww-debug-info" style="border:1px solid #e5e5e5;background:#fff;overflow:auto;height:300px;width:800px;" contenteditable="true">' . $ewww_debug . '</div>';
8448
+
8449
  $help_instructions = esc_html__( 'Debugging information will be included with your message automatically.', 'ewww-image-optimizer' ) . ' ' .
8450
  esc_html__( 'This will allow us to assist you more quickly.', 'ewww-image-optimizer' );
8451
+
8452
+ $output = str_replace( 'DEBUG_PLACEHOLDER', $debug_output, $output );
8453
  }
8454
+ echo $output;
8455
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_help' ) ) {
8456
  $current_user = wp_get_current_user();
8457
  $help_email = $current_user->user_email;
8489
  <?php
8490
  }
8491
  ewwwio_memory( __FUNCTION__ );
8492
+ if ( $ewwwio_temp_debug ) {
8493
+ ewww_image_optimizer_set_option( 'ewww_image_optimizer_debug', false );
8494
+ $ewwwio_temp_debug = false;
8495
+ }
8496
  $ewww_debug = '';
8497
  }
8498
 
8621
  return;
8622
  }
8623
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_detection' ) ) {
8624
+ $resize_detection_script = file_get_contents( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'includes/resize_detection.js' );
8625
+ echo "<style>\n" .
8626
+ "img.scaled-image {\n" .
8627
+ "\tborder: 3px #3eadc9 dotted;\n" .
8628
+ "\tmargin: -3px;\n" .
8629
+ "}\n" .
8630
+ "</style>\n";
8631
+ echo "<script>$resize_detection_script</script>";
8632
  }
 
8633
  }
8634
 
8635
  /**
8721
  */
8722
  function ewww_image_optimizer_debug_log() {
8723
  global $ewww_debug;
8724
+ global $ewwwio_temp_debug;
8725
+ if ( ! empty( $ewww_debug ) && empty( $ewwwio_temp_debug ) && ewww_image_optimizer_get_option( 'ewww_image_optimizer_debug' ) ) {
8726
  $memory_limit = ewwwio_memory_limit();
8727
  clearstatcache();
8728
  $timestamp = date( 'Y-m-d H:i:s' ) . "\n";
8743
  ewwwio_memory( __FUNCTION__ );
8744
  }
8745
 
8746
+ /**
8747
+ * View the debug.log file from the wp-admin.
8748
+ */
8749
+ function ewww_image_optimizer_view_debug_log() {
8750
+ $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', 'manage_options' );
8751
+ if ( false === current_user_can( $permissions ) ) {
8752
+ wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) );
8753
+ }
8754
+ if ( is_file( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'debug.log' ) ) {
8755
+ ewwwio_ob_clean();
8756
+ header( 'Content-Type: text/plain;charset=UTF-8' );
8757
+ readfile( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'debug.log' );
8758
+ exit;
8759
+ }
8760
+ wp_die( esc_html__( 'The Debug Log is empty.', 'ewww-image-optimizer' ) );
8761
+ }
8762
+
8763
  /**
8764
  * Removes the debug.log file from the plugin folder.
8765
  */
ewww-image-optimizer.php CHANGED
@@ -13,8 +13,7 @@ Plugin Name: EWWW Image Optimizer
13
  Plugin URI: https://wordpress.org/plugins/ewww-image-optimizer/
14
  Description: Reduce file sizes for images within WordPress including NextGEN Gallery and GRAND FlAGallery. Uses jpegtran, optipng/pngout, and gifsicle.
15
  Author: Exactly WWW
16
- Text Domain: ewww-image-optimizer
17
- Version: 4.6.3
18
  Author URI: https://ewww.io/
19
  License: GPLv3
20
  */
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: 4.7.0
 
17
  Author URI: https://ewww.io/
18
  License: GPLv3
19
  */
includes/eio.js CHANGED
@@ -107,6 +107,8 @@ jQuery(document).ready(function($) {
107
  }
108
  $('#ewww-optimization-settings').hide();
109
  $('#ewww-conversion-settings').hide();
 
 
110
  $('.ewww-webp-nav').click(function() {
111
  $('.ewww-tab-nav li').removeClass('ewww-selected');
112
  $('li.ewww-webp-nav').addClass('ewww-selected');
@@ -117,6 +119,8 @@ jQuery(document).ready(function($) {
117
  $('#ewww-optimization-settings').hide();
118
  $('#ewww-resize-settings').hide();
119
  $('#ewww-conversion-settings').hide();
 
 
120
  });
121
  $('.ewww-general-nav').click(function() {
122
  $('.ewww-tab-nav li').removeClass('ewww-selected');
@@ -128,6 +132,8 @@ jQuery(document).ready(function($) {
128
  $('#ewww-optimization-settings').hide();
129
  $('#ewww-resize-settings').hide();
130
  $('#ewww-conversion-settings').hide();
 
 
131
  });
132
  $('.ewww-exactdn-nav').click(function() {
133
  $('.ewww-tab-nav li').removeClass('ewww-selected');
@@ -139,6 +145,8 @@ jQuery(document).ready(function($) {
139
  $('#ewww-optimization-settings').hide();
140
  $('#ewww-resize-settings').hide();
141
  $('#ewww-conversion-settings').hide();
 
 
142
  });
143
  $('.ewww-optimization-nav').click(function() {
144
  $('.ewww-tab-nav li').removeClass('ewww-selected');
@@ -150,6 +158,8 @@ jQuery(document).ready(function($) {
150
  $('#ewww-optimization-settings').show();
151
  $('#ewww-resize-settings').hide();
152
  $('#ewww-conversion-settings').hide();
 
 
153
  });
154
  $('.ewww-resize-nav').click(function() {
155
  $('.ewww-tab-nav li').removeClass('ewww-selected');
@@ -161,6 +171,8 @@ jQuery(document).ready(function($) {
161
  $('#ewww-optimization-settings').hide();
162
  $('#ewww-resize-settings').show();
163
  $('#ewww-conversion-settings').hide();
 
 
164
  });
165
  $('.ewww-conversion-nav').click(function() {
166
  $('.ewww-tab-nav li').removeClass('ewww-selected');
@@ -172,6 +184,34 @@ jQuery(document).ready(function($) {
172
  $('#ewww-optimization-settings').hide();
173
  $('#ewww-resize-settings').hide();
174
  $('#ewww-conversion-settings').show();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  });
176
  $('.ewww-guage').tooltip({
177
  items: '.ewww-guage',
107
  }
108
  $('#ewww-optimization-settings').hide();
109
  $('#ewww-conversion-settings').hide();
110
+ $('#ewww-support-settings').hide();
111
+ $('#ewww-contribute-settings').hide();
112
  $('.ewww-webp-nav').click(function() {
113
  $('.ewww-tab-nav li').removeClass('ewww-selected');
114
  $('li.ewww-webp-nav').addClass('ewww-selected');
119
  $('#ewww-optimization-settings').hide();
120
  $('#ewww-resize-settings').hide();
121
  $('#ewww-conversion-settings').hide();
122
+ $('#ewww-support-settings').hide();
123
+ $('#ewww-contribute-settings').hide();
124
  });
125
  $('.ewww-general-nav').click(function() {
126
  $('.ewww-tab-nav li').removeClass('ewww-selected');
132
  $('#ewww-optimization-settings').hide();
133
  $('#ewww-resize-settings').hide();
134
  $('#ewww-conversion-settings').hide();
135
+ $('#ewww-support-settings').hide();
136
+ $('#ewww-contribute-settings').hide();
137
  });
138
  $('.ewww-exactdn-nav').click(function() {
139
  $('.ewww-tab-nav li').removeClass('ewww-selected');
145
  $('#ewww-optimization-settings').hide();
146
  $('#ewww-resize-settings').hide();
147
  $('#ewww-conversion-settings').hide();
148
+ $('#ewww-support-settings').hide();
149
+ $('#ewww-contribute-settings').hide();
150
  });
151
  $('.ewww-optimization-nav').click(function() {
152
  $('.ewww-tab-nav li').removeClass('ewww-selected');
158
  $('#ewww-optimization-settings').show();
159
  $('#ewww-resize-settings').hide();
160
  $('#ewww-conversion-settings').hide();
161
+ $('#ewww-support-settings').hide();
162
+ $('#ewww-contribute-settings').hide();
163
  });
164
  $('.ewww-resize-nav').click(function() {
165
  $('.ewww-tab-nav li').removeClass('ewww-selected');
171
  $('#ewww-optimization-settings').hide();
172
  $('#ewww-resize-settings').show();
173
  $('#ewww-conversion-settings').hide();
174
+ $('#ewww-support-settings').hide();
175
+ $('#ewww-contribute-settings').hide();
176
  });
177
  $('.ewww-conversion-nav').click(function() {
178
  $('.ewww-tab-nav li').removeClass('ewww-selected');
184
  $('#ewww-optimization-settings').hide();
185
  $('#ewww-resize-settings').hide();
186
  $('#ewww-conversion-settings').show();
187
+ $('#ewww-support-settings').hide();
188
+ $('#ewww-contribute-settings').hide();
189
+ });
190
+ $('.ewww-support-nav').click(function() {
191
+ $('.ewww-tab-nav li').removeClass('ewww-selected');
192
+ $('li.ewww-support-nav').addClass('ewww-selected');
193
+ $('.ewww-tab a').blur();
194
+ $('#ewww-webp-settings').hide();
195
+ $('#ewww-general-settings').hide();
196
+ $('#ewww-exactdn-settings').hide();
197
+ $('#ewww-optimization-settings').hide();
198
+ $('#ewww-resize-settings').hide();
199
+ $('#ewww-conversion-settings').hide();
200
+ $('#ewww-support-settings').show();
201
+ $('#ewww-contribute-settings').hide();
202
+ });
203
+ $('.ewww-contribute-nav').click(function() {
204
+ $('.ewww-tab-nav li').removeClass('ewww-selected');
205
+ $('li.ewww-contribute-nav').addClass('ewww-selected');
206
+ $('.ewww-tab a').blur();
207
+ $('#ewww-webp-settings').hide();
208
+ $('#ewww-general-settings').hide();
209
+ $('#ewww-exactdn-settings').hide();
210
+ $('#ewww-optimization-settings').hide();
211
+ $('#ewww-resize-settings').hide();
212
+ $('#ewww-conversion-settings').hide();
213
+ $('#ewww-support-settings').hide();
214
+ $('#ewww-contribute-settings').show();
215
  });
216
  $('.ewww-guage').tooltip({
217
  items: '.ewww-guage',
includes/lazysizes-post.js ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ lazysizesWebP('alpha', lazySizes.init);
2
+ function constrainSrc(bg,objectWidth,objectHeight){
3
+ var regW = /w=(\d+)/;
4
+ var regFit = /fit=(\d+),(\d+)/;
5
+ var regResize = /resize=(\d+),(\d+)/;
6
+ if (bg.search('\\?') > 0 && bg.search(ewww_lazy_vars.exactdn_domain) > 0){
7
+ var resultW = regW.exec(bg);
8
+ if(resultW && objectWidth < resultW[1]){
9
+ return bg.replace(regW, 'w=' + objectWidth);
10
+ }
11
+ var resultFit = regFit.exec(bg);
12
+ if(resultFit && objectWidth < resultFit[1]){
13
+ return bg.replace(regFit, 'fit=' + objectWidth + ',' + objectHeight);
14
+ }
15
+ var resultResize = regResize.exec(bg);
16
+ if(resultResize && objectWidth < resultResize[1]){
17
+ return bg.replace(regResize, 'resize=' + objectWidth + ',' + objectHeight);
18
+ }
19
+ if(!resultW && !resultFit && !resultResize){
20
+ return bg + '&w=' + objectWidth;
21
+ }
22
+ }
23
+ if (bg.search('\\?') == -1 && bg.search(ewww_lazy_vars.exactdn_domain) > 0){
24
+ return bg + '?w=' + objectWidth;
25
+ }
26
+ return bg;
27
+ }
28
+ document.addEventListener('lazybeforeunveil', function(e){
29
+ var target = e.target;
30
+ //console.log('the target');
31
+ //console.log(target);
32
+ //console.log('loading an image');
33
+ if(ewww_webp_supported) {
34
+ //console.log('we could load webp');
35
+ var srcset = target.getAttribute('data-srcset');
36
+ //console.log(srcset);
37
+ if (srcset && -1 < srcset.search('webp=1')){
38
+ //console.log('srcset already contains webp ' + srcset);
39
+ return;
40
+ }
41
+ if (srcset) {
42
+ var webpsrcset = target.getAttribute('data-srcset-webp');
43
+ if(webpsrcset){
44
+ //console.log('replacing webp srcset attr');
45
+ target.setAttribute('data-srcset', webpsrcset);
46
+ }
47
+ }
48
+ var src = target.getAttribute('data-src');
49
+ if (src && -1 < src.search('webp=1')){
50
+ //console.log('src already webp');
51
+ return;
52
+ } else {
53
+ //console.log('src missing webp ' + src);
54
+ }
55
+ var webpsrc = target.getAttribute('data-src-webp');
56
+ if(!webpsrc){
57
+ //console.log('no webp attr');
58
+ return;
59
+ }
60
+ //console.log('replacing webp src attr');
61
+ target.setAttribute('data-src', webpsrc);
62
+ }
63
+ });
includes/lazysizes-pre.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var ewww_webp_supported = false;
2
+ function lazysizesWebP(feature, callback) {
3
+ var kTestImages = {
4
+ alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
5
+ animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"
6
+ };
7
+ var img = new Image();
8
+ img.onload = function () {
9
+ ewww_webp_supported = (img.width > 0) && (img.height > 0);
10
+ callback();
11
+ };
12
+ img.onerror = function () {
13
+ callback();
14
+ };
15
+ img.src = "data:image/webp;base64," + kTestImages[feature];
16
+ }
17
+ window.lazySizesConfig = window.lazySizesConfig || {};
18
+ window.lazySizesConfig.init = false;
includes/lazysizes.js ADDED
@@ -0,0 +1,707 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function(window, factory) {
2
+ var lazySizes = factory(window, window.document);
3
+ window.lazySizes = lazySizes;
4
+ if(typeof module == 'object' && module.exports){
5
+ module.exports = lazySizes;
6
+ }
7
+ }(window, function l(window, document) {
8
+ 'use strict';
9
+ /*jshint eqnull:true */
10
+ if(!document.getElementsByClassName){return;}
11
+
12
+ var lazysizes, lazySizesConfig;
13
+
14
+ var docElem = document.documentElement;
15
+
16
+ var Date = window.Date;
17
+
18
+ var supportPicture = window.HTMLPictureElement;
19
+
20
+ var _addEventListener = 'addEventListener';
21
+
22
+ var _getAttribute = 'getAttribute';
23
+
24
+ var addEventListener = window[_addEventListener];
25
+
26
+ var setTimeout = window.setTimeout;
27
+
28
+ var requestAnimationFrame = window.requestAnimationFrame || setTimeout;
29
+
30
+ var requestIdleCallback = window.requestIdleCallback;
31
+
32
+ var regPicture = /^picture$/i;
33
+
34
+ var loadEvents = ['load', 'error', 'lazyincluded', '_lazyloaded'];
35
+
36
+ var regClassCache = {};
37
+
38
+ var forEach = Array.prototype.forEach;
39
+
40
+ var hasClass = function(ele, cls) {
41
+ if(!regClassCache[cls]){
42
+ regClassCache[cls] = new RegExp('(\\s|^)'+cls+'(\\s|$)');
43
+ }
44
+ return regClassCache[cls].test(ele[_getAttribute]('class') || '') && regClassCache[cls];
45
+ };
46
+
47
+ var addClass = function(ele, cls) {
48
+ if (!hasClass(ele, cls)){
49
+ ele.setAttribute('class', (ele[_getAttribute]('class') || '').trim() + ' ' + cls);
50
+ }
51
+ };
52
+
53
+ var removeClass = function(ele, cls) {
54
+ var reg;
55
+ if ((reg = hasClass(ele,cls))) {
56
+ ele.setAttribute('class', (ele[_getAttribute]('class') || '').replace(reg, ' '));
57
+ }
58
+ };
59
+
60
+ var addRemoveLoadEvents = function(dom, fn, add){
61
+ var action = add ? _addEventListener : 'removeEventListener';
62
+ if(add){
63
+ addRemoveLoadEvents(dom, fn);
64
+ }
65
+ loadEvents.forEach(function(evt){
66
+ dom[action](evt, fn);
67
+ });
68
+ };
69
+
70
+ var triggerEvent = function(elem, name, detail, noBubbles, noCancelable){
71
+ var event = document.createEvent('Event');
72
+
73
+ if(!detail){
74
+ detail = {};
75
+ }
76
+
77
+ detail.instance = lazysizes;
78
+
79
+ event.initEvent(name, !noBubbles, !noCancelable);
80
+
81
+ event.detail = detail;
82
+
83
+ elem.dispatchEvent(event);
84
+ return event;
85
+ };
86
+
87
+ var updatePolyfill = function (el, full){
88
+ var polyfill;
89
+ if( !supportPicture && ( polyfill = (window.picturefill || lazySizesConfig.pf) ) ){
90
+ if(full && full.src && !el[_getAttribute]('srcset')){
91
+ el.setAttribute('srcset', full.src);
92
+ }
93
+ polyfill({reevaluate: true, elements: [el]});
94
+ } else if(full && full.src){
95
+ el.src = full.src;
96
+ }
97
+ };
98
+
99
+ var getCSS = function (elem, style){
100
+ return (getComputedStyle(elem, null) || {})[style];
101
+ };
102
+
103
+ var getWidth = function(elem, parent, width){
104
+ width = width || elem.offsetWidth;
105
+
106
+ while(width < lazySizesConfig.minSize && parent && !elem._lazysizesWidth){
107
+ width = parent.offsetWidth;
108
+ parent = parent.parentNode;
109
+ }
110
+
111
+ return width;
112
+ };
113
+
114
+ var rAF = (function(){
115
+ var running, waiting;
116
+ var firstFns = [];
117
+ var secondFns = [];
118
+ var fns = firstFns;
119
+
120
+ var run = function(){
121
+ var runFns = fns;
122
+
123
+ fns = firstFns.length ? secondFns : firstFns;
124
+
125
+ running = true;
126
+ waiting = false;
127
+
128
+ while(runFns.length){
129
+ runFns.shift()();
130
+ }
131
+
132
+ running = false;
133
+ };
134
+
135
+ var rafBatch = function(fn, queue){
136
+ if(running && !queue){
137
+ fn.apply(this, arguments);
138
+ } else {
139
+ fns.push(fn);
140
+
141
+ if(!waiting){
142
+ waiting = true;
143
+ (document.hidden ? setTimeout : requestAnimationFrame)(run);
144
+ }
145
+ }
146
+ };
147
+
148
+ rafBatch._lsFlush = run;
149
+
150
+ return rafBatch;
151
+ })();
152
+
153
+ var rAFIt = function(fn, simple){
154
+ return simple ?
155
+ function() {
156
+ rAF(fn);
157
+ } :
158
+ function(){
159
+ var that = this;
160
+ var args = arguments;
161
+ rAF(function(){
162
+ fn.apply(that, args);
163
+ });
164
+ }
165
+ ;
166
+ };
167
+
168
+ var throttle = function(fn){
169
+ var running;
170
+ var lastTime = 0;
171
+ var gDelay = lazySizesConfig.throttleDelay;
172
+ var rICTimeout = lazySizesConfig.ricTimeout;
173
+ var run = function(){
174
+ running = false;
175
+ lastTime = Date.now();
176
+ fn();
177
+ };
178
+ var idleCallback = requestIdleCallback && rICTimeout > 49 ?
179
+ function(){
180
+ requestIdleCallback(run, {timeout: rICTimeout});
181
+
182
+ if(rICTimeout !== lazySizesConfig.ricTimeout){
183
+ rICTimeout = lazySizesConfig.ricTimeout;
184
+ }
185
+ } :
186
+ rAFIt(function(){
187
+ setTimeout(run);
188
+ }, true)
189
+ ;
190
+
191
+ return function(isPriority){
192
+ var delay;
193
+
194
+ if((isPriority = isPriority === true)){
195
+ rICTimeout = 33;
196
+ }
197
+
198
+ if(running){
199
+ return;
200
+ }
201
+
202
+ running = true;
203
+
204
+ delay = gDelay - (Date.now() - lastTime);
205
+
206
+ if(delay < 0){
207
+ delay = 0;
208
+ }
209
+
210
+ if(isPriority || delay < 9){
211
+ idleCallback();
212
+ } else {
213
+ setTimeout(idleCallback, delay);
214
+ }
215
+ };
216
+ };
217
+
218
+ //based on http://modernjavascript.blogspot.de/2013/08/building-better-debounce.html
219
+ var debounce = function(func) {
220
+ var timeout, timestamp;
221
+ var wait = 99;
222
+ var run = function(){
223
+ timeout = null;
224
+ func();
225
+ };
226
+ var later = function() {
227
+ var last = Date.now() - timestamp;
228
+
229
+ if (last < wait) {
230
+ setTimeout(later, wait - last);
231
+ } else {
232
+ (requestIdleCallback || run)(run);
233
+ }
234
+ };
235
+
236
+ return function() {
237
+ timestamp = Date.now();
238
+
239
+ if (!timeout) {
240
+ timeout = setTimeout(later, wait);
241
+ }
242
+ };
243
+ };
244
+
245
+ (function(){
246
+ var prop;
247
+
248
+ var lazySizesDefaults = {
249
+ lazyClass: 'lazyload',
250
+ loadedClass: 'lazyloaded',
251
+ loadingClass: 'lazyloading',
252
+ preloadClass: 'lazypreload',
253
+ errorClass: 'lazyerror',
254
+ //strictClass: 'lazystrict',
255
+ autosizesClass: 'lazyautosizes',
256
+ srcAttr: 'data-src',
257
+ srcsetAttr: 'data-srcset',
258
+ sizesAttr: 'data-sizes',
259
+ //preloadAfterLoad: false,
260
+ minSize: 40,
261
+ customMedia: {},
262
+ init: true,
263
+ expFactor: 1.5,
264
+ hFac: 0.8,
265
+ loadMode: 2,
266
+ loadHidden: true,
267
+ ricTimeout: 0,
268
+ throttleDelay: 125,
269
+ };
270
+
271
+ lazySizesConfig = window.lazySizesConfig || window.lazysizesConfig || {};
272
+
273
+ for(prop in lazySizesDefaults){
274
+ if(!(prop in lazySizesConfig)){
275
+ lazySizesConfig[prop] = lazySizesDefaults[prop];
276
+ }
277
+ }
278
+
279
+ window.lazySizesConfig = lazySizesConfig;
280
+
281
+ setTimeout(function(){
282
+ if(lazySizesConfig.init){
283
+ init();
284
+ }
285
+ });
286
+ })();
287
+
288
+ var loader = (function(){
289
+ var preloadElems, isCompleted, resetPreloadingTimer, loadMode, started;
290
+
291
+ var eLvW, elvH, eLtop, eLleft, eLright, eLbottom, isBodyHidden;
292
+
293
+ var regImg = /^img$/i;
294
+ var regIframe = /^iframe$/i;
295
+
296
+ var supportScroll = ('onscroll' in window) && !(/(gle|ing)bot/.test(navigator.userAgent));
297
+
298
+ var shrinkExpand = 0;
299
+ var currentExpand = 0;
300
+
301
+ var isLoading = 0;
302
+ var lowRuns = -1;
303
+
304
+ var resetPreloading = function(e){
305
+ isLoading--;
306
+ if(e && e.target){
307
+ addRemoveLoadEvents(e.target, resetPreloading);
308
+ }
309
+
310
+ if(!e || isLoading < 0 || !e.target){
311
+ isLoading = 0;
312
+ }
313
+ };
314
+
315
+ var isVisible = function (elem) {
316
+ if (isBodyHidden == null) {
317
+ isBodyHidden = getCSS(document.body, 'visibility') == 'hidden';
318
+ }
319
+
320
+ return isBodyHidden || (getCSS(elem.parentNode, 'visibility') != 'hidden' && getCSS(elem, 'visibility') != 'hidden');
321
+ };
322
+
323
+ var isNestedVisible = function(elem, elemExpand){
324
+ var outerRect;
325
+ var parent = elem;
326
+ var visible = isVisible(elem);
327
+
328
+ eLtop -= elemExpand;
329
+ eLbottom += elemExpand;
330
+ eLleft -= elemExpand;
331
+ eLright += elemExpand;
332
+
333
+ while(visible && (parent = parent.offsetParent) && parent != document.body && parent != docElem){
334
+ visible = ((getCSS(parent, 'opacity') || 1) > 0);
335
+
336
+ if(visible && getCSS(parent, 'overflow') != 'visible'){
337
+ outerRect = parent.getBoundingClientRect();
338
+ visible = eLright > outerRect.left &&
339
+ eLleft < outerRect.right &&
340
+ eLbottom > outerRect.top - 1 &&
341
+ eLtop < outerRect.bottom + 1
342
+ ;
343
+ }
344
+ }
345
+
346
+ return visible;
347
+ };
348
+
349
+ var checkElements = function() {
350
+ var eLlen, i, rect, autoLoadElem, loadedSomething, elemExpand, elemNegativeExpand, elemExpandVal,
351
+ beforeExpandVal, defaultExpand, preloadExpand, hFac;
352
+ var lazyloadElems = lazysizes.elements;
353
+
354
+ if((loadMode = lazySizesConfig.loadMode) && isLoading < 8 && (eLlen = lazyloadElems.length)){
355
+
356
+ i = 0;
357
+
358
+ lowRuns++;
359
+
360
+ defaultExpand = (!lazySizesConfig.expand || lazySizesConfig.expand < 1) ?
361
+ docElem.clientHeight > 500 && docElem.clientWidth > 500 ? 500 : 370 :
362
+ lazySizesConfig.expand;
363
+
364
+ preloadExpand = defaultExpand * lazySizesConfig.expFactor;
365
+ hFac = lazySizesConfig.hFac;
366
+ isBodyHidden = null;
367
+
368
+ if(currentExpand < preloadExpand && isLoading < 1 && lowRuns > 2 && loadMode > 2 && !document.hidden){
369
+ currentExpand = preloadExpand;
370
+ lowRuns = 0;
371
+ } else if(loadMode > 1 && lowRuns > 1 && isLoading < 6){
372
+ currentExpand = defaultExpand;
373
+ } else {
374
+ currentExpand = shrinkExpand;
375
+ }
376
+
377
+ for(; i < eLlen; i++){
378
+
379
+ if(!lazyloadElems[i] || lazyloadElems[i]._lazyRace){continue;}
380
+
381
+ if(!supportScroll){unveilElement(lazyloadElems[i]);continue;}
382
+
383
+ if(!(elemExpandVal = lazyloadElems[i][_getAttribute]('data-expand')) || !(elemExpand = elemExpandVal * 1)){
384
+ elemExpand = currentExpand;
385
+ }
386
+
387
+ if(beforeExpandVal !== elemExpand){
388
+ eLvW = innerWidth + (elemExpand * hFac);
389
+ elvH = innerHeight + elemExpand;
390
+ elemNegativeExpand = elemExpand * -1;
391
+ beforeExpandVal = elemExpand;
392
+ }
393
+
394
+ rect = lazyloadElems[i].getBoundingClientRect();
395
+
396
+ if ((eLbottom = rect.bottom) >= elemNegativeExpand &&
397
+ (eLtop = rect.top) <= elvH &&
398
+ (eLright = rect.right) >= elemNegativeExpand * hFac &&
399
+ (eLleft = rect.left) <= eLvW &&
400
+ (eLbottom || eLright || eLleft || eLtop) &&
401
+ (lazySizesConfig.loadHidden || isVisible(lazyloadElems[i])) &&
402
+ ((isCompleted && isLoading < 3 && !elemExpandVal && (loadMode < 3 || lowRuns < 4)) || isNestedVisible(lazyloadElems[i], elemExpand))){
403
+ unveilElement(lazyloadElems[i]);
404
+ loadedSomething = true;
405
+ if(isLoading > 9){break;}
406
+ } else if(!loadedSomething && isCompleted && !autoLoadElem &&
407
+ isLoading < 4 && lowRuns < 4 && loadMode > 2 &&
408
+ (preloadElems[0] || lazySizesConfig.preloadAfterLoad) &&
409
+ (preloadElems[0] || (!elemExpandVal && ((eLbottom || eLright || eLleft || eLtop) || lazyloadElems[i][_getAttribute](lazySizesConfig.sizesAttr) != 'auto')))){
410
+ autoLoadElem = preloadElems[0] || lazyloadElems[i];
411
+ }
412
+ }
413
+
414
+ if(autoLoadElem && !loadedSomething){
415
+ unveilElement(autoLoadElem);
416
+ }
417
+ }
418
+ };
419
+
420
+ var throttledCheckElements = throttle(checkElements);
421
+
422
+ var switchLoadingClass = function(e){
423
+ addClass(e.target, lazySizesConfig.loadedClass);
424
+ removeClass(e.target, lazySizesConfig.loadingClass);
425
+ addRemoveLoadEvents(e.target, rafSwitchLoadingClass);
426
+ triggerEvent(e.target, 'lazyloaded');
427
+ };
428
+ var rafedSwitchLoadingClass = rAFIt(switchLoadingClass);
429
+ var rafSwitchLoadingClass = function(e){
430
+ rafedSwitchLoadingClass({target: e.target});
431
+ };
432
+
433
+ var changeIframeSrc = function(elem, src){
434
+ try {
435
+ elem.contentWindow.location.replace(src);
436
+ } catch(e){
437
+ elem.src = src;
438
+ }
439
+ };
440
+
441
+ var handleSources = function(source){
442
+ var customMedia;
443
+
444
+ var sourceSrcset = source[_getAttribute](lazySizesConfig.srcsetAttr);
445
+
446
+ if( (customMedia = lazySizesConfig.customMedia[source[_getAttribute]('data-media') || source[_getAttribute]('media')]) ){
447
+ source.setAttribute('media', customMedia);
448
+ }
449
+
450
+ if(sourceSrcset){
451
+ source.setAttribute('srcset', sourceSrcset);
452
+ }
453
+ };
454
+
455
+ var lazyUnveil = rAFIt(function (elem, detail, isAuto, sizes, isImg){
456
+ var src, srcset, parent, isPicture, event, firesLoad;
457
+
458
+ if(!(event = triggerEvent(elem, 'lazybeforeunveil', detail)).defaultPrevented){
459
+
460
+ if(sizes){
461
+ if(isAuto){
462
+ addClass(elem, lazySizesConfig.autosizesClass);
463
+ } else {
464
+ elem.setAttribute('sizes', sizes);
465
+ }
466
+ }
467
+
468
+ srcset = elem[_getAttribute](lazySizesConfig.srcsetAttr);
469
+ src = elem[_getAttribute](lazySizesConfig.srcAttr);
470
+
471
+ if(isImg) {
472
+ parent = elem.parentNode;
473
+ isPicture = parent && regPicture.test(parent.nodeName || '');
474
+ }
475
+
476
+ firesLoad = detail.firesLoad || (('src' in elem) && (srcset || src || isPicture));
477
+
478
+ event = {target: elem};
479
+
480
+ if(firesLoad){
481
+ addRemoveLoadEvents(elem, resetPreloading, true);
482
+ clearTimeout(resetPreloadingTimer);
483
+ resetPreloadingTimer = setTimeout(resetPreloading, 2500);
484
+
485
+ addClass(elem, lazySizesConfig.loadingClass);
486
+ addRemoveLoadEvents(elem, rafSwitchLoadingClass, true);
487
+ }
488
+
489
+ if(isPicture){
490
+ forEach.call(parent.getElementsByTagName('source'), handleSources);
491
+ }
492
+
493
+ if(srcset){
494
+ elem.setAttribute('srcset', srcset);
495
+ } else if(src && !isPicture){
496
+ if(regIframe.test(elem.nodeName)){
497
+ changeIframeSrc(elem, src);
498
+ } else {
499
+ elem.src = src;
500
+ }
501
+ }
502
+
503
+ if(isImg && (srcset || isPicture)){
504
+ updatePolyfill(elem, {src: src});
505
+ }
506
+ }
507
+
508
+ if(elem._lazyRace){
509
+ delete elem._lazyRace;
510
+ }
511
+ removeClass(elem, lazySizesConfig.lazyClass);
512
+
513
+ rAF(function(){
514
+ if( !firesLoad || (elem.complete && elem.naturalWidth > 1)){
515
+ if(firesLoad){
516
+ resetPreloading(event);
517
+ } else {
518
+ isLoading--;
519
+ }
520
+ switchLoadingClass(event);
521
+ }
522
+ }, true);
523
+ });
524
+
525
+ var unveilElement = function (elem){
526
+ var detail;
527
+
528
+ var isImg = regImg.test(elem.nodeName);
529
+
530
+ //allow using sizes="auto", but don't use. it's invalid. Use data-sizes="auto" or a valid value for sizes instead (i.e.: sizes="80vw")
531
+ var sizes = isImg && (elem[_getAttribute](lazySizesConfig.sizesAttr) || elem[_getAttribute]('sizes'));
532
+ var isAuto = sizes == 'auto';
533
+
534
+ if( (isAuto || !isCompleted) && isImg && (elem[_getAttribute]('src') || elem.srcset) && !elem.complete && !hasClass(elem, lazySizesConfig.errorClass) && hasClass(elem, lazySizesConfig.lazyClass)){return;}
535
+
536
+ detail = triggerEvent(elem, 'lazyunveilread').detail;
537
+
538
+ if(isAuto){
539
+ autoSizer.updateElem(elem, true, elem.offsetWidth);
540
+ }
541
+
542
+ elem._lazyRace = true;
543
+ isLoading++;
544
+
545
+ lazyUnveil(elem, detail, isAuto, sizes, isImg);
546
+ };
547
+
548
+ var onload = function(){
549
+ if(isCompleted){return;}
550
+ if(Date.now() - started < 999){
551
+ setTimeout(onload, 999);
552
+ return;
553
+ }
554
+ var afterScroll = debounce(function(){
555
+ lazySizesConfig.loadMode = 3;
556
+ throttledCheckElements();
557
+ });
558
+
559
+ isCompleted = true;
560
+
561
+ lazySizesConfig.loadMode = 3;
562
+
563
+ throttledCheckElements();
564
+
565
+ addEventListener('scroll', function(){
566
+ if(lazySizesConfig.loadMode == 3){
567
+ lazySizesConfig.loadMode = 2;
568
+ }
569
+ afterScroll();
570
+ }, true);
571
+ };
572
+
573
+ return {
574
+ _: function(){
575
+ started = Date.now();
576
+
577
+ lazysizes.elements = document.getElementsByClassName(lazySizesConfig.lazyClass);
578
+ preloadElems = document.getElementsByClassName(lazySizesConfig.lazyClass + ' ' + lazySizesConfig.preloadClass);
579
+
580
+ addEventListener('scroll', throttledCheckElements, true);
581
+
582
+ addEventListener('resize', throttledCheckElements, true);
583
+
584
+ if(window.MutationObserver){
585
+ new MutationObserver( throttledCheckElements ).observe( docElem, {childList: true, subtree: true, attributes: true} );
586
+ } else {
587
+ docElem[_addEventListener]('DOMNodeInserted', throttledCheckElements, true);
588
+ docElem[_addEventListener]('DOMAttrModified', throttledCheckElements, true);
589
+ setInterval(throttledCheckElements, 999);
590
+ }
591
+
592
+ addEventListener('hashchange', throttledCheckElements, true);
593
+
594
+ //, 'fullscreenchange'
595
+ ['focus', 'mouseover', 'click', 'load', 'transitionend', 'animationend', 'webkitAnimationEnd'].forEach(function(name){
596
+ document[_addEventListener](name, throttledCheckElements, true);
597
+ });
598
+
599
+ if((/d$|^c/.test(document.readyState))){
600
+ onload();
601
+ } else {
602
+ addEventListener('load', onload);
603
+ document[_addEventListener]('DOMContentLoaded', throttledCheckElements);
604
+ setTimeout(onload, 20000);
605
+ }
606
+
607
+ if(lazysizes.elements.length){
608
+ checkElements();
609
+ rAF._lsFlush();
610
+ } else {
611
+ throttledCheckElements();
612
+ }
613
+ },
614
+ checkElems: throttledCheckElements,
615
+ unveil: unveilElement
616
+ };
617
+ })();
618
+
619
+
620
+ var autoSizer = (function(){
621
+ var autosizesElems;
622
+
623
+ var sizeElement = rAFIt(function(elem, parent, event, width){
624
+ var sources, i, len;
625
+ elem._lazysizesWidth = width;
626
+ width += 'px';
627
+
628
+ elem.setAttribute('sizes', width);
629
+
630
+ if(regPicture.test(parent.nodeName || '')){
631
+ sources = parent.getElementsByTagName('source');
632
+ for(i = 0, len = sources.length; i < len; i++){
633
+ sources[i].setAttribute('sizes', width);
634
+ }
635
+ }
636
+
637
+ if(!event.detail.dataAttr){
638
+ updatePolyfill(elem, event.detail);
639
+ }
640
+ });
641
+ var getSizeElement = function (elem, dataAttr, width){
642
+ var event;
643
+ var parent = elem.parentNode;
644
+
645
+ if(parent){
646
+ width = getWidth(elem, parent, width);
647
+ event = triggerEvent(elem, 'lazybeforesizes', {width: width, dataAttr: !!dataAttr});
648
+
649
+ if(!event.defaultPrevented){
650
+ width = event.detail.width;
651
+
652
+ if(width && width !== elem._lazysizesWidth){
653
+ sizeElement(elem, parent, event, width);
654
+ }
655
+ }
656
+ }
657
+ };
658
+
659
+ var updateElementsSizes = function(){
660
+ var i;
661
+ var len = autosizesElems.length;
662
+ if(len){
663
+ i = 0;
664
+
665
+ for(; i < len; i++){
666
+ getSizeElement(autosizesElems[i]);
667
+ }
668
+ }
669
+ };
670
+
671
+ var debouncedUpdateElementsSizes = debounce(updateElementsSizes);
672
+
673
+ return {
674
+ _: function(){
675
+ autosizesElems = document.getElementsByClassName(lazySizesConfig.autosizesClass);
676
+ addEventListener('resize', debouncedUpdateElementsSizes);
677
+ },
678
+ checkElems: debouncedUpdateElementsSizes,
679
+ updateElem: getSizeElement
680
+ };
681
+ })();
682
+
683
+ var init = function(){
684
+ if(!init.i){
685
+ init.i = true;
686
+ autoSizer._();
687
+ loader._();
688
+ }
689
+ };
690
+
691
+ lazysizes = {
692
+ cfg: lazySizesConfig,
693
+ autoSizer: autoSizer,
694
+ loader: loader,
695
+ init: init,
696
+ uP: updatePolyfill,
697
+ aC: addClass,
698
+ rC: removeClass,
699
+ hC: hasClass,
700
+ fire: triggerEvent,
701
+ gW: getWidth,
702
+ rAF: rAF,
703
+ };
704
+
705
+ return lazysizes;
706
+ }
707
+ ));
includes/lazysizes.min.js ADDED
@@ -0,0 +1 @@
 
1
+ var ewww_webp_supported=!1;function lazysizesWebP(e,t){var a=new Image;a.onload=function(){ewww_webp_supported=0<a.width&&0<a.height,t()},a.onerror=function(){t()},a.src="data:image/webp;base64,"+{alpha:"UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",animation:"UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"}[e]}function constrainSrc(e,t,a){var i=/w=(\d+)/,n=/fit=(\d+),(\d+)/,r=/resize=(\d+),(\d+)/;if(0<e.search("\\?")&&0<e.search(ewww_lazy_vars.exactdn_domain)){var o=i.exec(e);if(o&&t<o[1])return e.replace(i,"w="+t);var s=n.exec(e);if(s&&t<s[1])return e.replace(n,"fit="+t+","+a);var l=r.exec(e);if(l&&t<l[1])return e.replace(r,"resize="+t+","+a);if(!o&&!s&&!l)return e+"&w="+t}return-1==e.search("\\?")&&0<e.search(ewww_lazy_vars.exactdn_domain)?e+"?w="+t:e}window.lazySizesConfig=window.lazySizesConfig||{},window.lazySizesConfig.init=!1,function(e,t){var a=function(i,f){"use strict";if(!f.getElementsByClassName)return;var g,z,v=f.documentElement,r=i.Date,n=i.HTMLPictureElement,o="addEventListener",m="getAttribute",t=i[o],u=i.setTimeout,a=i.requestAnimationFrame||u,s=i.requestIdleCallback,A=/^picture$/i,l=["load","error","lazyincluded","_lazyloaded"],d={},p=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]},y=function(e,t){c(e,t)||e.setAttribute("class",(e[m]("class")||"").trim()+" "+t)},h=function(e,t){var a;(a=c(e,t))&&e.setAttribute("class",(e[m]("class")||"").replace(a," "))},b=function(t,a,e){var i=e?o:"removeEventListener";e&&b(t,a),l.forEach(function(e){t[i](e,a)})},w=function(e,t,a,i,n){var r=f.createEvent("Event");return a||(a={}),a.instance=g,r.initEvent(t,!i,!n),r.detail=a,e.dispatchEvent(r),r},C=function(e,t){var a;!n&&(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)},E=function(e,t){return(getComputedStyle(e,null)||{})[t]},_=function(e,t,a){for(a=a||e.offsetWidth;a<z.minSize&&t&&!e._lazysizesWidth;)a=t.offsetWidth,t=t.parentNode;return a},x=(L=[],M=[],N=L,R=function(){var e=N;for(N=L.length?M:L,W=!(S=!0);e.length;)e.shift()();S=!1},Q=function(e,t){S&&!t?e.apply(this,arguments):(N.push(e),W||(W=!0,(f.hidden?u:a)(R)))},Q._lsFlush=R,Q),e=function(a,e){return e?function(){x(a)}:function(){var e=this,t=arguments;x(function(){a.apply(e,t)})}},B=function(e){var t,a,i=function(){t=null,e()},n=function(){var e=r.now()-a;e<99?u(n,99-e):(s||i)(i)};return function(){a=r.now(),t||(t=u(n,99))}};var S,W,L,M,N,R,Q;!function(){var e,t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",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]);i.lazySizesConfig=z,u(function(){z.init&&P()})}();var k=(se=/^img$/i,le=/^iframe$/i,de="onscroll"in i&&!/(gle|ing)bot/.test(navigator.userAgent),ce=0,ue=0,Ae=-1,fe=function(e){ue--,e&&e.target&&b(e.target,fe),(!e||ue<0||!e.target)&&(ue=0)},ge=function(e){return null==Z&&(Z="hidden"==E(f.body,"visibility")),Z||"hidden"!=E(e.parentNode,"visibility")&&"hidden"!=E(e,"visibility")},ze=function(e,t){var a,i=e,n=ge(e);for(V-=t,K+=t,X-=t,Y+=t;n&&(i=i.offsetParent)&&i!=f.body&&i!=v;)(n=0<(E(i,"opacity")||1))&&"visible"!=E(i,"overflow")&&(a=i.getBoundingClientRect(),n=Y>a.left&&X<a.right&&K>a.top-1&&V<a.bottom+1);return n},ve=function(){var e,t,a,i,n,r,o,s,l,d,c,u,A=g.elements;if((G=z.loadMode)&&ue<8&&(e=A.length)){for(t=0,Ae++,d=!z.expand||z.expand<1?500<v.clientHeight&&500<v.clientWidth?500:370:z.expand,c=d*z.expFactor,u=z.hFac,Z=null,ce<c&&ue<1&&2<Ae&&2<G&&!f.hidden?(ce=c,Ae=0):ce=1<G&&1<Ae&&ue<6?d:0;t<e;t++)if(A[t]&&!A[t]._lazyRace)if(de)if((s=A[t][m]("data-expand"))&&(r=1*s)||(r=ce),l!==r&&(q=innerWidth+r*u,j=innerHeight+r,o=-1*r,l=r),a=A[t].getBoundingClientRect(),(K=a.bottom)>=o&&(V=a.top)<=j&&(Y=a.right)>=o*u&&(X=a.left)<=q&&(K||Y||X||V)&&(z.loadHidden||ge(A[t]))&&(J&&ue<3&&!s&&(G<3||Ae<4)||ze(A[t],r))){if(Ce(A[t]),n=!0,9<ue)break}else!n&&J&&!i&&ue<4&&Ae<4&&2<G&&(H[0]||z.preloadAfterLoad)&&(H[0]||!s&&(K||Y||X||V||"auto"!=A[t][m](z.sizesAttr)))&&(i=H[0]||A[t]);else Ce(A[t]);i&&!n&&Ce(i)}},ee=ve,ae=0,ie=z.throttleDelay,ne=z.ricTimeout,re=function(){te=!1,ae=r.now(),ee()},oe=s&&49<ne?function(){s(re,{timeout:ne}),ne!==z.ricTimeout&&(ne=z.ricTimeout)}:e(function(){u(re)},!0),me=function(e){var t;(e=!0===e)&&(ne=33),te||(te=!0,(t=ie-(r.now()-ae))<0&&(t=0),e||t<9?oe():u(oe,t))},pe=function(e){y(e.target,z.loadedClass),h(e.target,z.loadingClass),b(e.target,he),w(e.target,"lazyloaded")},ye=e(pe),he=function(e){ye({target:e.target})},be=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)},we=e(function(e,t,a,i,n){var r,o,s,l,d,c;(d=w(e,"lazybeforeunveil",t)).defaultPrevented||(i&&(a?y(e,z.autosizesClass):e.setAttribute("sizes",i)),o=e[m](z.srcsetAttr),r=e[m](z.srcAttr),n&&(s=e.parentNode,l=s&&A.test(s.nodeName||"")),c=t.firesLoad||"src"in e&&(o||r||l),d={target:e},c&&(b(e,fe,!0),clearTimeout(O),O=u(fe,2500),y(e,z.loadingClass),b(e,he,!0)),l&&p.call(s.getElementsByTagName("source"),be),o?e.setAttribute("srcset",o):r&&!l&&(le.test(e.nodeName)?function(t,a){try{t.contentWindow.location.replace(a)}catch(e){t.src=a}}(e,r):e.src=r),n&&(o||l)&&C(e,{src:r})),e._lazyRace&&delete e._lazyRace,h(e,z.lazyClass),x(function(){(!c||e.complete&&1<e.naturalWidth)&&(c?fe(d):ue--,pe(d))},!0)}),Ce=function(e){var t,a=se.test(e.nodeName),i=a&&(e[m](z.sizesAttr)||e[m]("sizes")),n="auto"==i;(!n&&J||!a||!e[m]("src")&&!e.srcset||e.complete||c(e,z.errorClass)||!c(e,z.lazyClass))&&(t=w(e,"lazyunveilread").detail,n&&D.updateElem(e,!0,e.offsetWidth),e._lazyRace=!0,ue++,we(e,t,n,i,a))},Ee=function(){if(!J)if(r.now()-$<999)u(Ee,999);else{var e=B(function(){z.loadMode=3,me()});J=!0,z.loadMode=3,me(),t("scroll",function(){3==z.loadMode&&(z.loadMode=2),e()},!0)}},{_:function(){$=r.now(),g.elements=f.getElementsByClassName(z.lazyClass),H=f.getElementsByClassName(z.lazyClass+" "+z.preloadClass),t("scroll",me,!0),t("resize",me,!0),i.MutationObserver?new MutationObserver(me).observe(v,{childList:!0,subtree:!0,attributes:!0}):(v[o]("DOMNodeInserted",me,!0),v[o]("DOMAttrModified",me,!0),setInterval(me,999)),t("hashchange",me,!0),["focus","mouseover","click","load","transitionend","animationend","webkitAnimationEnd"].forEach(function(e){f[o](e,me,!0)}),/d$|^c/.test(f.readyState)?Ee():(t("load",Ee),f[o]("DOMContentLoaded",me),u(Ee,2e4)),g.elements.length?(ve(),x._lsFlush()):me()},checkElems:me,unveil:Ce}),D=(F=e(function(e,t,a,i){var n,r,o;if(e._lazysizesWidth=i,i+="px",e.setAttribute("sizes",i),A.test(t.nodeName||""))for(n=t.getElementsByTagName("source"),r=0,o=n.length;r<o;r++)n[r].setAttribute("sizes",i);a.detail.dataAttr||C(e,a.detail)}),U=function(e,t,a){var i,n=e.parentNode;n&&(a=_(e,n,a),(i=w(e,"lazybeforesizes",{width:a,dataAttr:!!t})).defaultPrevented||(a=i.detail.width)&&a!==e._lazysizesWidth&&F(e,n,i,a))},I=B(function(){var e,t=T.length;if(t)for(e=0;e<t;e++)U(T[e])}),{_:function(){T=f.getElementsByClassName(z.autosizesClass),t("resize",I)},checkElems:I,updateElem:U}),P=function(){P.i||(P.i=!0,D._(),k._())};var T,F,U,I;var H,J,O,G,$,q,j,V,X,Y,K,Z,ee,te,ae,ie,ne,re,oe,se,le,de,ce,ue,Ae,fe,ge,ze,ve,me,pe,ye,he,be,we,Ce,Ee;return g={cfg:z,autoSizer:D,loader:k,init:P,uP:C,aC:y,rC:h,hC:c,fire:w,gW:_,rAF:x}}(e,e.document);e.lazySizes=a,"object"==typeof module&&module.exports&&(module.exports=a)}(window),lazysizesWebP("alpha",lazySizes.init),document.addEventListener("lazybeforeunveil",function(e){var t=e.target;if(ewww_webp_supported){var a=t.getAttribute("data-srcset");if(a&&-1<a.search("webp=1"))return;if(a){var i=t.getAttribute("data-srcset-webp");i&&t.setAttribute("data-srcset",i)}var n=t.getAttribute("data-src");if(n&&-1<n.search("webp=1"))return;var r=t.getAttribute("data-src-webp");if(!r)return;t.setAttribute("data-src",r)}}),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(e,i,n){"use strict";var r,o;i.addEventListener&&(r=function(e,t){var a=i.createElement("img");a.onload=function(){a.onload=null,a.onerror=null,a=null,t()},a.onerror=a.onload,a.src=e,a&&a.complete&&a.onload&&a.onload()},addEventListener("lazybeforeunveil",function(e){var t,a,i;e.detail.instance==n&&(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),t=constrainSrc(t,e.target.offsetWidth,e.target.offsetHeight),e.detail.firesLoad=!0,r(t,function(){e.target.style.backgroundImage="url("+(o.test(t)?JSON.stringify(t):t)+")",e.detail.firesLoad=!1,n.fire(e.target,"_lazyloaded",{},!0,!0)})),(i=e.target.getAttribute("data-poster"))&&(e.detail.firesLoad=!0,r(i,function(){e.target.poster=i,e.detail.firesLoad=!1,n.fire(e.target,"_lazyloaded",{},!0,!0)}))))},!(o=/\(|\)|\s|'/)))});
includes/load_webp.js CHANGED
@@ -477,101 +477,101 @@ function check_webp_feature(feature, callback) {
477
  };
478
  img.src = "data:image/webp;base64," + kTestImages[feature];
479
  }
480
- function ewww_load_images(ewww_webp_supported) {
481
- (function($) {
482
- $.fn.extend({
483
- ewwwattr: function(attr, value) {
484
- if (typeof value !== typeof undefined && value !== false) {
485
- this.attr(attr, value);
486
- }
487
- return this;
488
- }
489
- });
490
  var attr_prefix = 'data-';
491
- function ewww_copy_attrs(ewww_nscript, ewww_img) {
492
  var attrs = ['align','alt','border','crossorigin','height','hspace','ismap','longdesc','usemap','vspace','width','accesskey','class','contenteditable','contextmenu','dir','draggable','dropzone','hidden','id','lang','spellcheck','style','tabindex','title','translate','sizes','data-caption','data-attachment-id','data-permalink','data-orig-size','data-comments-opened','data-image-meta','data-image-title','data-image-description','data-event-trigger','data-highlight-color','data-highlight-opacity','data-highlight-border-color','data-highlight-border-width','data-highlight-border-opacity','data-no-lazy','data-lazy','data-large_image_width','data-large_image_height'];
493
  for (var i = 0, len = attrs.length; i < len; i++) {
494
- $(ewww_img).ewwwattr(attrs[i], $(ewww_nscript).attr(attr_prefix + attrs[i]));
495
  }
496
  return ewww_img;
497
  }
498
  if (ewww_webp_supported) {
499
- $('.batch-image img, .image-wrapper a, .ngg-pro-masonry-item a, .ngg-galleria-offscreen-seo-wrapper a').each(function() {
500
- $(this).ewwwattr('data-src', $(this).attr('data-webp'));
501
- $(this).ewwwattr('data-thumbnail', $(this).attr('data-webp-thumbnail'));
502
- });
503
- $('.image-wrapper a, .ngg-pro-masonry-item a').each(function() {
504
- $(this).ewwwattr('href', $(this).attr('data-webp'));
505
- });
506
- $('.rev_slider ul li').each(function() {
507
- $(this).ewwwattr('data-thumb', $(this).attr('data-webp-thumb'));
 
 
 
 
 
 
508
  var param_num = 1;
509
  while ( param_num < 11 ) {
510
- $(this).ewwwattr('data-param' + param_num, $(this).attr('data-webp-param' + param_num));
511
  param_num++;
512
  }
513
- });
514
- $('.rev_slider img').each(function() {
515
- $(this).ewwwattr('data-lazyload', $(this).attr('data-webp-lazyload'));
516
- });
517
- $('div.woocommerce-product-gallery__image').each(function() {
518
- $(this).ewwwattr('data-thumb', $(this).attr('data-webp-thumb'));
519
- });
 
 
520
  }
521
- $('video').each(function() {
 
522
  if (ewww_webp_supported) {
523
- $(this).ewwwattr('poster', $(this).attr('data-poster-webp'));
524
  } else {
525
- $(this).ewwwattr('poster', $(this).attr('data-poster-image'));
526
  }
527
- });
528
- $('img.ewww_webp_lazy_load').each(function() {
 
529
  if (ewww_webp_supported) {
530
- $(this).ewwwattr('data-lazy-srcset', $(this).attr('data-lazy-srcset-webp'));
531
- $(this).ewwwattr('data-srcset', $(this).attr('data-srcset-webp'));
532
- $(this).ewwwattr('data-lazy-src', $(this).attr('data-lazy-src-webp'));
533
- $(this).ewwwattr('data-src', $(this).attr('data-src-webp'));
534
- $(this).ewwwattr('data-orig-file', $(this).attr('data-webp-orig-file'));
535
- $(this).ewwwattr('data-medium-file', $(this).attr('data-webp-medium-file'));
536
- $(this).ewwwattr('data-large-file', $(this).attr('data-webp-large-file'));
537
- var jpsrcset = $(this).attr('srcset');
538
- if (typeof jpsrcset !== typeof undefined && jpsrcset !== false && jpsrcset.includes('R0lGOD')) {
539
- $(this).ewwwattr('src', $(this).attr('data-lazy-src-webp'));
540
  }
541
  }
542
- $(this).removeClass('ewww_webp_lazy_load');
543
- });
544
- $('.ewww_webp').each(function() {
545
- var ewww_img = document.createElement('img');
 
546
  if (ewww_webp_supported) {
547
- $(ewww_img).ewwwattr('src', $(this).attr('data-webp'));
548
- $(ewww_img).ewwwattr('srcset', $(this).attr('data-srcset-webp'));
549
- $(ewww_img).ewwwattr('data-orig-file', $(this).attr('data-orig-file'));
550
- $(ewww_img).ewwwattr('data-orig-file', $(this).attr('data-webp-orig-file'));
551
- $(ewww_img).ewwwattr('data-medium-file', $(this).attr('data-medium-file'));
552
- $(ewww_img).ewwwattr('data-medium-file', $(this).attr('data-webp-medium-file'));
553
- $(ewww_img).ewwwattr('data-large-file', $(this).attr('data-large-file'));
554
- $(ewww_img).ewwwattr('data-large-file', $(this).attr('data-webp-large-file'));
555
- $(ewww_img).ewwwattr('data-large_image', $(this).attr('data-large_image'));
556
- $(ewww_img).ewwwattr('data-large_image', $(this).attr('data-webp-large_image'));
557
- $(ewww_img).ewwwattr('data-src', $(this).attr('data-src'));
558
- $(ewww_img).ewwwattr('data-src', $(this).attr('data-webp-src'));
559
  } else {
560
- $(ewww_img).ewwwattr('src', $(this).attr('data-img'));
561
- $(ewww_img).ewwwattr('srcset', $(this).attr('data-srcset-img'));
562
- $(ewww_img).ewwwattr('data-orig-file', $(this).attr('data-orig-file'));
563
- $(ewww_img).ewwwattr('data-medium-file', $(this).attr('data-medium-file'));
564
- $(ewww_img).ewwwattr('data-large-file', $(this).attr('data-large-file'));
565
- $(ewww_img).ewwwattr('data-large_image', $(this).attr('data-large_image'));
566
- $(ewww_img).ewwwattr('data-src', $(this).attr('data-src'));
567
  }
568
- ewww_img = ewww_copy_attrs(this, ewww_img);
569
- $(this).after(ewww_img);
570
- $(this).removeClass('ewww_webp');
571
- });
572
- // $(document.body).trigger('post-load');
573
- })(jQuery);
574
- if (jQuery.fn.isotope && jQuery.fn.imagesLoaded) {
575
  jQuery('.fusion-posts-container-infinite').imagesLoaded( function() {
576
  if ( jQuery( '.fusion-posts-container-infinite' ).hasClass( 'isotope' ) ) {
577
  jQuery( '.fusion-posts-container-infinite' ).isotope();
@@ -582,18 +582,17 @@ function ewww_load_images(ewww_webp_supported) {
582
  });
583
  }
584
  }
585
- var ewww_jquery_waiting_timer = 0;
586
- ewww_jquery_waiting = setInterval(function () {
587
- if (window.jQuery) {
588
- check_webp_feature('alpha', ewww_load_images);
589
- check_webp_feature('alpha', ewww_ngg_plus_load_galleries);
590
  document.arrive('.ewww_webp', function() {
591
- check_webp_feature('alpha', ewww_load_images);
592
  });
593
  var ewww_ngg_galleries_timer = 0;
594
  var ewww_ngg_galleries = setInterval(function() {
595
  if ( typeof galleries !== 'undefined' ) {
596
- check_webp_feature('alpha', ewww_ngg_plus_parse_galleries);
597
  clearInterval(ewww_ngg_galleries);
598
  }
599
  ewww_ngg_galleries_timer += 25;
@@ -601,78 +600,67 @@ ewww_jquery_waiting = setInterval(function () {
601
  clearInterval(ewww_ngg_galleries);
602
  }
603
  }, 25);
604
- clearInterval(ewww_jquery_waiting);
605
- }
606
- ewww_jquery_waiting_timer +=100;
607
- if (ewww_jquery_waiting_timer > 10000) {
608
- clearInterval(ewww_jquery_waiting);
609
  }
610
- }, 100);
611
- function ewww_ngg_plus_parse_galleries(ewww_webp_supported) {
612
  if (ewww_webp_supported) {
613
- (function($) {
614
- $.each(galleries, function(galleryIndex, gallery) {
615
- galleries[galleryIndex].images_list = ewww_ngg_plus_parse_image_list(gallery.images_list);
616
- });
617
- })(jQuery);
618
  }
619
  }
620
- function ewww_ngg_plus_load_galleries(ewww_webp_supported) {
621
  if (ewww_webp_supported) {
622
- (function($) {
623
- $(window).on('ngg.galleria.themeadded', function(event, themename) {
624
- window.ngg_galleria._create_backup = window.ngg_galleria.create;
625
- window.ngg_galleria.create = function(gallery_parent, themename) {
626
- var gallery_id = $(gallery_parent).data('id');
627
- galleries['gallery_' + gallery_id].images_list = ewww_ngg_plus_parse_image_list(galleries['gallery_' + gallery_id].images_list);
628
- return window.ngg_galleria._create_backup(gallery_parent, themename);
629
- };
630
- });
631
- $(window).on('override_nplModal_methods', function(e, methods) {
632
- methods._set_events_backup = methods.set_events;
633
- methods.set_events = function() {
634
- $('#npl_content').bind('npl_images_ready', function(event, gallery_id) {
635
- var cache = methods.fetch_images.gallery_image_cache[gallery_id];
636
- cache = ewww_ngg_plus_parse_image_list(cache);
637
- });
638
- return methods._set_events_backup();
639
- }
640
- });
641
- })(jQuery);
642
  }
643
  }
644
- function ewww_ngg_plus_parse_image_list(images_list) {
645
- (function($) {
646
- $.each(images_list, function(nggIndex, nggImage) {
647
- if (typeof nggImage['image-webp'] !== typeof undefined) {
648
- images_list[nggIndex]['image'] = nggImage['image-webp'];
649
- delete images_list[nggIndex]['image-webp'];
650
- }
651
- if (typeof nggImage['thumb-webp'] !== typeof undefined) {
652
- images_list[nggIndex]['thumb'] = nggImage['thumb-webp'];
653
- delete images_list[nggIndex]['thumb-webp'];
654
- }
655
- if (typeof nggImage['full_image_webp'] !== typeof undefined) {
656
- images_list[nggIndex]['full_image'] = nggImage['full_image_webp'];
657
- delete images_list[nggIndex]['full_image_webp'];
658
- }
659
- if (typeof nggImage['srcsets'] !== typeof undefined) {
660
- $.each(nggImage['srcsets'], function(nggSrcsetIndex, nggSrcset) {
661
- if (typeof nggImage['srcsets'][nggSrcsetIndex + '-webp'] !== typeof undefined) {
662
- images_list[nggIndex]['srcsets'][nggSrcsetIndex] = nggImage['srcsets'][nggSrcsetIndex + '-webp'];
663
- delete images_list[nggIndex]['srcsets'][nggSrcsetIndex + '-webp'];
664
- }
665
- });
 
666
  }
667
- if (typeof nggImage['full_srcsets'] !== typeof undefined) {
668
- $.each(nggImage['full_srcsets'], function(nggFSrcsetIndex, nggFSrcset) {
669
- if (typeof nggImage['full_srcsets'][nggFSrcsetIndex + '-webp'] !== typeof undefined) {
670
- images_list[nggIndex]['full_srcsets'][nggFSrcsetIndex] = nggImage['full_srcsets'][nggFSrcsetIndex + '-webp'];
671
- delete images_list[nggIndex]['full_srcsets'][nggFSrcsetIndex + '-webp'];
672
- }
673
- });
 
674
  }
675
- });
676
- })(jQuery);
677
  return images_list;
678
  }
477
  };
478
  img.src = "data:image/webp;base64," + kTestImages[feature];
479
  }
480
+ function ewwwLoadImages(ewww_webp_supported) {
 
 
 
 
 
 
 
 
 
481
  var attr_prefix = 'data-';
482
+ function ewwwCopyAttrs(ewww_nscript, ewww_img) {
483
  var attrs = ['align','alt','border','crossorigin','height','hspace','ismap','longdesc','usemap','vspace','width','accesskey','class','contenteditable','contextmenu','dir','draggable','dropzone','hidden','id','lang','spellcheck','style','tabindex','title','translate','sizes','data-caption','data-attachment-id','data-permalink','data-orig-size','data-comments-opened','data-image-meta','data-image-title','data-image-description','data-event-trigger','data-highlight-color','data-highlight-opacity','data-highlight-border-color','data-highlight-border-width','data-highlight-border-opacity','data-no-lazy','data-lazy','data-large_image_width','data-large_image_height'];
484
  for (var i = 0, len = attrs.length; i < len; i++) {
485
+ ewwwAttr(ewww_img, attrs[i], ewww_nscript.getAttribute(attr_prefix + attrs[i]));
486
  }
487
  return ewww_img;
488
  }
489
  if (ewww_webp_supported) {
490
+ var nggImages = document.querySelectorAll('.batch-image img, .image-wrapper a, .ngg-pro-masonry-item a, .ngg-galleria-offscreen-seo-wrapper a');
491
+ for (var i = 0, len = nggImages.length; i < len; i++){
492
+ ewwwAttr(nggImages[i], 'data-src', nggImages[i].getAttribute('data-webp'));
493
+ //$(this).ewwwattr('data-src', $(this).attr('data-webp'));
494
+ ewwwAttr(nggImages[i], 'data-thumbnail', nggImages[i].getAttribute('data-webp-thumbnail'));
495
+ //$(this).ewwwattr('data-thumbnail', $(this).attr('data-webp-thumbnail'));
496
+ }
497
+ // TODO: not sure we want to muck with the links, but maybe we have to.
498
+ /*var nggImages = document.querySelectorAll('.image-wrapper a, .ngg-pro-masonry-item a');
499
+ for (var i = 0, len = nggImages.length; i < len; i++){
500
+ ewwwAttr(nggImages[i], 'href', nggImages[i].getAttribute('data-webp'));
501
+ }*/
502
+ var revImages = document.querySelectorAll('.rev_slider ul li');
503
+ for (var i = 0, len = revImages.length; i < len; i++){
504
+ ewwwAttr(revImages[i], 'data-thumb', revImages[i].getAttribute('data-webp-thumb'));
505
  var param_num = 1;
506
  while ( param_num < 11 ) {
507
+ ewwwAttr(revImages[i], 'data-param' + param_num, revImages[i].getAttribute('data-webp-param' + param_num));
508
  param_num++;
509
  }
510
+ }
511
+ var revImages = document.querySelectorAll('.rev_slider img');
512
+ for (var i = 0, len = revImages.length; i < len; i++){
513
+ ewwwAttr(revImages[i], 'data-lazyload', revImages[i].getAttribute('data-webp-lazyload'));
514
+ }
515
+ var wooImages = document.querySelectorAll('div.woocommerce-product-gallery__image');
516
+ for (var i = 0, len = wooImages.length; i < len; i++){
517
+ ewwwAttr(wooImages[i], 'data-thumb', wooImages[i].getAttribute('data-webp-thumb'));
518
+ }
519
  }
520
+ var videos = document.querySelectorAll('videos');
521
+ for (var i = 0, len = videos.length; i < len; i++){
522
  if (ewww_webp_supported) {
523
+ ewwwAttr(videos[i], 'poster', videos[i].getAttribute('data-poster-webp'));
524
  } else {
525
+ ewwwAttr(videos[i], 'poster', videos[i].getAttribute('data-poster-image'));
526
  }
527
+ }
528
+ var lazies = document.querySelectorAll('img.ewww_webp_lazy_load');
529
+ for (var i = 0, len = lazies.length; i < len; i++){
530
  if (ewww_webp_supported) {
531
+ ewwwAttr(lazies[i], 'data-lazy-srcset', lazies[i].getAttribute('data-lazy-srcset-webp'));
532
+ ewwwAttr(lazies[i], 'data-srcset', lazies[i].getAttribute('data-srcset-webp'));
533
+ ewwwAttr(lazies[i], 'data-lazy-src', lazies[i].getAttribute('data-lazy-src-webp'));
534
+ ewwwAttr(lazies[i], 'data-src', lazies[i].getAttribute('data-src-webp'));
535
+ ewwwAttr(lazies[i], 'data-orig-file', lazies[i].getAttribute('data-webp-orig-file'));
536
+ ewwwAttr(lazies[i], 'data-medium-file', lazies[i].getAttribute('data-webp-medium-file'));
537
+ ewwwAttr(lazies[i], 'data-large-file', lazies[i].getAttribute('data-webp-large-file'));
538
+ var jpsrcset = lazies[i].getAttribute('srcset');
539
+ if (jpsrcset != null && jpsrcset !== false && jpsrcset.includes('R0lGOD')) {
540
+ ewwwAttr(lazies[i], 'src', lazies[i].getAttribute('data-lazy-src-webp'));
541
  }
542
  }
543
+ lazies[i].className = lazies[i].className.replace(/\bewww_webp_lazy_load\b/, '');
544
+ }
545
+ var elems = document.querySelectorAll('.ewww_webp');
546
+ for (var i = 0, len = elems.length; i < len; i++){
547
+ var ewwwImg = document.createElement('img');
548
  if (ewww_webp_supported) {
549
+ ewwwAttr(ewwwImg, 'src', elems[i].getAttribute('data-webp'));
550
+ ewwwAttr(ewwwImg, 'srcset', elems[i].getAttribute('data-srcset-webp'));
551
+ ewwwAttr(ewwwImg, 'data-orig-file', elems[i].getAttribute('data-orig-file'));
552
+ ewwwAttr(ewwwImg, 'data-orig-file', elems[i].getAttribute('data-webp-orig-file'));
553
+ ewwwAttr(ewwwImg, 'data-medium-file', elems[i].getAttribute('data-medium-file'));
554
+ ewwwAttr(ewwwImg, 'data-medium-file', elems[i].getAttribute('data-webp-medium-file'));
555
+ ewwwAttr(ewwwImg, 'data-large-file', elems[i].getAttribute('data-large-file'));
556
+ ewwwAttr(ewwwImg, 'data-large-file', elems[i].getAttribute('data-webp-large-file'));
557
+ ewwwAttr(ewwwImg, 'data-large_image', elems[i].getAttribute('data-large_image'));
558
+ ewwwAttr(ewwwImg, 'data-large_image', elems[i].getAttribute('data-webp-large_image'));
559
+ ewwwAttr(ewwwImg, 'data-src', elems[i].getAttribute('data-src'));
560
+ ewwwAttr(ewwwImg, 'data-src', elems[i].getAttribute('data-webp-src'));
561
  } else {
562
+ ewwwAttr(ewwwImg, 'src', elems[i].getAttribute('data-img'));
563
+ ewwwAttr(ewwwImg, 'srcset', elems[i].getAttribute('data-srcset-img'));
564
+ ewwwAttr(ewwwImg, 'data-orig-file', elems[i].getAttribute('data-orig-file'));
565
+ ewwwAttr(ewwwImg, 'data-medium-file', elems[i].getAttribute('data-medium-file'));
566
+ ewwwAttr(ewwwImg, 'data-large-file', elems[i].getAttribute('data-large-file'));
567
+ ewwwAttr(ewwwImg, 'data-large_image', elems[i].getAttribute('data-large_image'));
568
+ ewwwAttr(ewwwImg, 'data-src', elems[i].getAttribute('data-src'));
569
  }
570
+ ewwwImg = ewwwCopyAttrs(elems[i], ewwwImg);
571
+ elems[i].parentNode.insertBefore(ewwwImg, elems[i].nextSibling);
572
+ elems[i].className = elems[i].className.replace(/\bewww_webp\b/, '');
573
+ }
574
+ if (window.jQuery && jQuery.fn.isotope && jQuery.fn.imagesLoaded) {
 
 
575
  jQuery('.fusion-posts-container-infinite').imagesLoaded( function() {
576
  if ( jQuery( '.fusion-posts-container-infinite' ).hasClass( 'isotope' ) ) {
577
  jQuery( '.fusion-posts-container-infinite' ).isotope();
582
  });
583
  }
584
  }
585
+ check_webp_feature('alpha', ewwwWebPInit);
586
+ function ewwwWebPInit(ewww_webp_supported) {
587
+ ewwwLoadImages(ewww_webp_supported);
588
+ ewwwNggLoadGalleries(ewww_webp_supported);
 
589
  document.arrive('.ewww_webp', function() {
590
+ ewwwLoadImages(ewww_webp_supported);
591
  });
592
  var ewww_ngg_galleries_timer = 0;
593
  var ewww_ngg_galleries = setInterval(function() {
594
  if ( typeof galleries !== 'undefined' ) {
595
+ ewwwNggParseGalleries(ewww_webp_supported);
596
  clearInterval(ewww_ngg_galleries);
597
  }
598
  ewww_ngg_galleries_timer += 25;
600
  clearInterval(ewww_ngg_galleries);
601
  }
602
  }, 25);
603
+
604
+ }
605
+ function ewwwAttr(elem, attr, value) {
606
+ if (value != null && value !== false) {
607
+ elem.setAttribute(attr, value);
608
  }
609
+ }
610
+ function ewwwNggParseGalleries(ewww_webp_supported) {
611
  if (ewww_webp_supported) {
612
+ for(var galleryIndex in galleries) {
613
+ var gallery = galleries[galleryIndex];
614
+ galleries[galleryIndex].images_list = ewwwNggParseImageList(gallery.images_list);
615
+ }
 
616
  }
617
  }
618
+ function ewwwNggLoadGalleries(ewww_webp_supported) {
619
  if (ewww_webp_supported) {
620
+ document.addEventListener('ngg.galleria.themeadded', function(event, themename){
621
+ window.ngg_galleria._create_backup = window.ngg_galleria.create;
622
+ window.ngg_galleria.create = function(gallery_parent, themename) {
623
+ var gallery_id = $(gallery_parent).data('id');
624
+ galleries['gallery_' + gallery_id].images_list = ewwwNggParseImageList(galleries['gallery_' + gallery_id].images_list);
625
+ return window.ngg_galleria._create_backup(gallery_parent, themename);
626
+ };
627
+ });
 
 
 
 
 
 
 
 
 
 
 
 
628
  }
629
  }
630
+ function ewwwNggParseImageList(images_list) {
631
+ console.log('parsing gallery images');
632
+ for(var nggIndex in images_list) {
633
+ var nggImage = images_list[nggIndex];
634
+ if (typeof nggImage['image-webp'] !== typeof undefined) {
635
+ images_list[nggIndex]['image'] = nggImage['image-webp'];
636
+ delete images_list[nggIndex]['image-webp'];
637
+ }
638
+ if (typeof nggImage['thumb-webp'] !== typeof undefined) {
639
+ images_list[nggIndex]['thumb'] = nggImage['thumb-webp'];
640
+ delete images_list[nggIndex]['thumb-webp'];
641
+ }
642
+ if (typeof nggImage['full_image_webp'] !== typeof undefined) {
643
+ images_list[nggIndex]['full_image'] = nggImage['full_image_webp'];
644
+ delete images_list[nggIndex]['full_image_webp'];
645
+ }
646
+ if (typeof nggImage['srcsets'] !== typeof undefined) {
647
+ for(var nggSrcsetIndex in nggImage['srcsets']) {
648
+ nggSrcset = nggImage['srcsets'][nggSrcsetIndex];
649
+ if (typeof nggImage['srcsets'][nggSrcsetIndex + '-webp'] !== typeof undefined) {
650
+ images_list[nggIndex]['srcsets'][nggSrcsetIndex] = nggImage['srcsets'][nggSrcsetIndex + '-webp'];
651
+ delete images_list[nggIndex]['srcsets'][nggSrcsetIndex + '-webp'];
652
+ }
653
  }
654
+ }
655
+ if (typeof nggImage['full_srcsets'] !== typeof undefined) {
656
+ for(var nggFSrcsetIndex in nggImage['full_srcsets']) {
657
+ nggFSrcset = nggImage['full_srcsets'][nggFSrcsetIndex];
658
+ if (typeof nggImage['full_srcsets'][nggFSrcsetIndex + '-webp'] !== typeof undefined) {
659
+ images_list[nggIndex]['full_srcsets'][nggFSrcsetIndex] = nggImage['full_srcsets'][nggFSrcsetIndex + '-webp'];
660
+ delete images_list[nggIndex]['full_srcsets'][nggFSrcsetIndex + '-webp'];
661
+ }
662
  }
663
+ }
664
+ }
665
  return images_list;
666
  }
includes/load_webp.min.js CHANGED
@@ -1 +1 @@
1
- var Arrive=function(c,e,w){"use strict";if(c.MutationObserver&&"undefined"!=typeof HTMLElement){var a,t,r=0,d=(a=HTMLElement.prototype.matches||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector,{matchesSelector:function(e,t){return e instanceof HTMLElement&&a.call(e,t)},addMethod:function(e,t,a){var r=e[t];e[t]=function(){return a.length==arguments.length?a.apply(this,arguments):"function"==typeof r?r.apply(this,arguments):void 0}},callCallbacks:function(e,t){t&&t.options.onceOnly&&1==t.firedElems.length&&(e=[e[0]]);for(var a,r=0;a=e[r];r++)a&&a.callback&&a.callback.call(a.elem,a.elem);t&&t.options.onceOnly&&1==t.firedElems.length&&t.me.unbindEventWithSelectorAndCallback.call(t.target,t.selector,t.callback)},checkChildNodesRecursively:function(e,t,a,r){for(var i,n=0;i=e[n];n++)a(i,t,r)&&r.push({callback:t.callback,elem:i}),0<i.childNodes.length&&d.checkChildNodesRecursively(i.childNodes,t,a,r)},mergeArrays:function(e,t){var a,r={};for(a in e)e.hasOwnProperty(a)&&(r[a]=e[a]);for(a in t)t.hasOwnProperty(a)&&(r[a]=t[a]);return r},toElementsArray:function(e){return void 0===e||"number"==typeof e.length&&e!==c||(e=[e]),e}}),u=((t=function(){this._eventsBucket=[],this._beforeAdding=null,this._beforeRemoving=null}).prototype.addEvent=function(e,t,a,r){var i={target:e,selector:t,options:a,callback:r,firedElems:[]};return this._beforeAdding&&this._beforeAdding(i),this._eventsBucket.push(i),i},t.prototype.removeEvent=function(e){for(var t,a=this._eventsBucket.length-1;t=this._eventsBucket[a];a--)if(e(t)){this._beforeRemoving&&this._beforeRemoving(t);var r=this._eventsBucket.splice(a,1);r&&r.length&&(r[0].callback=null)}},t.prototype.beforeAdding=function(e){this._beforeAdding=e},t.prototype.beforeRemoving=function(e){this._beforeRemoving=e},t),l=function(i,n){var l=new u,s=this,o={fireOnAttributesModification:!1};return l.beforeAdding(function(t){var e,a=t.target;a!==c.document&&a!==c||(a=document.getElementsByTagName("html")[0]),e=new MutationObserver(function(e){n.call(this,e,t)});var r=i(t.options);e.observe(a,r),t.observer=e,t.me=s}),l.beforeRemoving(function(e){e.observer.disconnect()}),this.bindEvent=function(e,t,a){t=d.mergeArrays(o,t);for(var r=d.toElementsArray(this),i=0;i<r.length;i++)l.addEvent(r[i],e,t,a)},this.unbindEvent=function(){var a=d.toElementsArray(this);l.removeEvent(function(e){for(var t=0;t<a.length;t++)if(this===w||e.target===a[t])return!0;return!1})},this.unbindEventWithSelectorOrCallback=function(a){var e,r=d.toElementsArray(this),i=a;e="function"==typeof a?function(e){for(var t=0;t<r.length;t++)if((this===w||e.target===r[t])&&e.callback===i)return!0;return!1}:function(e){for(var t=0;t<r.length;t++)if((this===w||e.target===r[t])&&e.selector===a)return!0;return!1},l.removeEvent(e)},this.unbindEventWithSelectorAndCallback=function(a,r){var i=d.toElementsArray(this);l.removeEvent(function(e){for(var t=0;t<i.length;t++)if((this===w||e.target===i[t])&&e.selector===a&&e.callback===r)return!0;return!1})},this},i=new function(){var o={fireOnAttributesModification:!1,onceOnly:!1,existing:!1};function n(e,t,a){return!(!d.matchesSelector(e,t.selector)||(e._id===w&&(e._id=r++),-1!=t.firedElems.indexOf(e._id))||(t.firedElems.push(e._id),0))}var c=(i=new l(function(e){var t={attributes:!1,childList:!0,subtree:!0};return e.fireOnAttributesModification&&(t.attributes=!0),t},function(e,i){e.forEach(function(e){var t=e.addedNodes,a=e.target,r=[];null!==t&&0<t.length?d.checkChildNodesRecursively(t,i,n,r):"attributes"===e.type&&n(a,i)&&r.push({callback:i.callback,elem:a}),d.callCallbacks(r,i)})})).bindEvent;return i.bindEvent=function(e,t,a){void 0===a?(a=t,t=o):t=d.mergeArrays(o,t);var r=d.toElementsArray(this);if(t.existing){for(var i=[],n=0;n<r.length;n++)for(var l=r[n].querySelectorAll(e),s=0;s<l.length;s++)i.push({callback:a,elem:l[s]});if(t.onceOnly&&i.length)return a.call(i[0].elem,i[0].elem);setTimeout(d.callCallbacks,1,i)}c.call(this,e,t,a)},i},s=new function(){var r={};function i(e,t){return d.matchesSelector(e,t.selector)}var n=(s=new l(function(){return{childList:!0,subtree:!0}},function(e,r){e.forEach(function(e){var t=e.removedNodes,a=[];null!==t&&0<t.length&&d.checkChildNodesRecursively(t,r,i,a),d.callCallbacks(a,r)})})).bindEvent;return s.bindEvent=function(e,t,a){void 0===a?(a=t,t=r):t=d.mergeArrays(r,t),n.call(this,e,t,a)},s};e&&h(e.fn),h(HTMLElement.prototype),h(NodeList.prototype),h(HTMLCollection.prototype),h(HTMLDocument.prototype),h(Window.prototype);var n={};return o(i,n,"unbindAllArrive"),o(s,n,"unbindAllLeave"),n}function o(e,t,a){d.addMethod(t,a,e.unbindEvent),d.addMethod(t,a,e.unbindEventWithSelectorOrCallback),d.addMethod(t,a,e.unbindEventWithSelectorAndCallback)}function h(e){e.arrive=i.bindEvent,o(i,e,"unbindArrive"),e.leave=s.bindEvent,o(s,e,"unbindLeave")}}(window,"undefined"==typeof jQuery?null:jQuery,void 0);function check_webp_feature(e,t){var a=new Image;a.onload=function(){var e=0<a.width&&0<a.height;t(e)},a.onerror=function(){t(!1)},a.src="data:image/webp;base64,"+{alpha:"UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",animation:"UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"}[e]}function ewww_load_images(t){!function(n){n.fn.extend({ewwwattr:function(e,t){return void 0!==t&&!1!==t&&this.attr(e,t),this}});t&&(n(".batch-image img, .image-wrapper a, .ngg-pro-masonry-item a, .ngg-galleria-offscreen-seo-wrapper a").each(function(){n(this).ewwwattr("data-src",n(this).attr("data-webp")),n(this).ewwwattr("data-thumbnail",n(this).attr("data-webp-thumbnail"))}),n(".image-wrapper a, .ngg-pro-masonry-item a").each(function(){n(this).ewwwattr("href",n(this).attr("data-webp"))}),n(".rev_slider ul li").each(function(){n(this).ewwwattr("data-thumb",n(this).attr("data-webp-thumb"));for(var e=1;e<11;)n(this).ewwwattr("data-param"+e,n(this).attr("data-webp-param"+e)),e++}),n(".rev_slider img").each(function(){n(this).ewwwattr("data-lazyload",n(this).attr("data-webp-lazyload"))}),n("div.woocommerce-product-gallery__image").each(function(){n(this).ewwwattr("data-thumb",n(this).attr("data-webp-thumb"))})),n("video").each(function(){t?n(this).ewwwattr("poster",n(this).attr("data-poster-webp")):n(this).ewwwattr("poster",n(this).attr("data-poster-image"))}),n("img.ewww_webp_lazy_load").each(function(){if(t){n(this).ewwwattr("data-lazy-srcset",n(this).attr("data-lazy-srcset-webp")),n(this).ewwwattr("data-srcset",n(this).attr("data-srcset-webp")),n(this).ewwwattr("data-lazy-src",n(this).attr("data-lazy-src-webp")),n(this).ewwwattr("data-src",n(this).attr("data-src-webp")),n(this).ewwwattr("data-orig-file",n(this).attr("data-webp-orig-file")),n(this).ewwwattr("data-medium-file",n(this).attr("data-webp-medium-file")),n(this).ewwwattr("data-large-file",n(this).attr("data-webp-large-file"));var e=n(this).attr("srcset");void 0!==e&&!1!==e&&e.includes("R0lGOD")&&n(this).ewwwattr("src",n(this).attr("data-lazy-src-webp"))}n(this).removeClass("ewww_webp_lazy_load")}),n(".ewww_webp").each(function(){var e=document.createElement("img");t?(n(e).ewwwattr("src",n(this).attr("data-webp")),n(e).ewwwattr("srcset",n(this).attr("data-srcset-webp")),n(e).ewwwattr("data-orig-file",n(this).attr("data-orig-file")),n(e).ewwwattr("data-orig-file",n(this).attr("data-webp-orig-file")),n(e).ewwwattr("data-medium-file",n(this).attr("data-medium-file")),n(e).ewwwattr("data-medium-file",n(this).attr("data-webp-medium-file")),n(e).ewwwattr("data-large-file",n(this).attr("data-large-file")),n(e).ewwwattr("data-large-file",n(this).attr("data-webp-large-file")),n(e).ewwwattr("data-large_image",n(this).attr("data-large_image")),n(e).ewwwattr("data-large_image",n(this).attr("data-webp-large_image")),n(e).ewwwattr("data-src",n(this).attr("data-src")),n(e).ewwwattr("data-src",n(this).attr("data-webp-src"))):(n(e).ewwwattr("src",n(this).attr("data-img")),n(e).ewwwattr("srcset",n(this).attr("data-srcset-img")),n(e).ewwwattr("data-orig-file",n(this).attr("data-orig-file")),n(e).ewwwattr("data-medium-file",n(this).attr("data-medium-file")),n(e).ewwwattr("data-large-file",n(this).attr("data-large-file")),n(e).ewwwattr("data-large_image",n(this).attr("data-large_image")),n(e).ewwwattr("data-src",n(this).attr("data-src"))),e=function(e,t){for(var a=["align","alt","border","crossorigin","height","hspace","ismap","longdesc","usemap","vspace","width","accesskey","class","contenteditable","contextmenu","dir","draggable","dropzone","hidden","id","lang","spellcheck","style","tabindex","title","translate","sizes","data-caption","data-attachment-id","data-permalink","data-orig-size","data-comments-opened","data-image-meta","data-image-title","data-image-description","data-event-trigger","data-highlight-color","data-highlight-opacity","data-highlight-border-color","data-highlight-border-width","data-highlight-border-opacity","data-no-lazy","data-lazy","data-large_image_width","data-large_image_height"],r=0,i=a.length;r<i;r++)n(t).ewwwattr(a[r],n(e).attr("data-"+a[r]));return t}(this,e),n(this).after(e),n(this).removeClass("ewww_webp")})}(jQuery),jQuery.fn.isotope&&jQuery.fn.imagesLoaded&&(jQuery(".fusion-posts-container-infinite").imagesLoaded(function(){jQuery(".fusion-posts-container-infinite").hasClass("isotope")&&jQuery(".fusion-posts-container-infinite").isotope()}),jQuery(".fusion-portfolio:not(.fusion-recent-works) .fusion-portfolio-wrapper").imagesLoaded(function(){jQuery(".fusion-portfolio:not(.fusion-recent-works) .fusion-portfolio-wrapper").isotope()}))}var ewww_jquery_waiting_timer=0;function ewww_ngg_plus_parse_galleries(e){e&&jQuery.each(galleries,function(e,t){galleries[e].images_list=ewww_ngg_plus_parse_image_list(t.images_list)})}function ewww_ngg_plus_load_galleries(e){var i;e&&((i=jQuery)(window).on("ngg.galleria.themeadded",function(e,t){window.ngg_galleria._create_backup=window.ngg_galleria.create,window.ngg_galleria.create=function(e,t){var a=i(e).data("id");return galleries["gallery_"+a].images_list=ewww_ngg_plus_parse_image_list(galleries["gallery_"+a].images_list),window.ngg_galleria._create_backup(e,t)}}),i(window).on("override_nplModal_methods",function(e,r){r._set_events_backup=r.set_events,r.set_events=function(){return i("#npl_content").bind("npl_images_ready",function(e,t){var a=r.fetch_images.gallery_image_cache[t];a=ewww_ngg_plus_parse_image_list(a)}),r._set_events_backup()}}))}function ewww_ngg_plus_parse_image_list(i){var e;return(e=jQuery).each(i,function(a,r){void 0!==r["image-webp"]&&(i[a].image=r["image-webp"],delete i[a]["image-webp"]),void 0!==r["thumb-webp"]&&(i[a].thumb=r["thumb-webp"],delete i[a]["thumb-webp"]),void 0!==r.full_image_webp&&(i[a].full_image=r.full_image_webp,delete i[a].full_image_webp),void 0!==r.srcsets&&e.each(r.srcsets,function(e,t){void 0!==r.srcsets[e+"-webp"]&&(i[a].srcsets[e]=r.srcsets[e+"-webp"],delete i[a].srcsets[e+"-webp"])}),void 0!==r.full_srcsets&&e.each(r.full_srcsets,function(e,t){void 0!==r.full_srcsets[e+"-webp"]&&(i[a].full_srcsets[e]=r.full_srcsets[e+"-webp"],delete i[a].full_srcsets[e+"-webp"])})}),i}ewww_jquery_waiting=setInterval(function(){if(window.jQuery){check_webp_feature("alpha",ewww_load_images),check_webp_feature("alpha",ewww_ngg_plus_load_galleries),document.arrive(".ewww_webp",function(){check_webp_feature("alpha",ewww_load_images)});var e=0,t=setInterval(function(){"undefined"!=typeof galleries&&(check_webp_feature("alpha",ewww_ngg_plus_parse_galleries),clearInterval(t)),1e3<(e+=25)&&clearInterval(t)},25);clearInterval(ewww_jquery_waiting)}1e4<(ewww_jquery_waiting_timer+=100)&&clearInterval(ewww_jquery_waiting)},100);
1
+ var Arrive=function(c,e,d){"use strict";if(c.MutationObserver&&"undefined"!=typeof HTMLElement){var r,t,a=0,u=(r=HTMLElement.prototype.matches||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector,{matchesSelector:function(e,t){return e instanceof HTMLElement&&r.call(e,t)},addMethod:function(e,t,r){var a=e[t];e[t]=function(){return r.length==arguments.length?r.apply(this,arguments):"function"==typeof a?a.apply(this,arguments):void 0}},callCallbacks:function(e,t){t&&t.options.onceOnly&&1==t.firedElems.length&&(e=[e[0]]);for(var r,a=0;r=e[a];a++)r&&r.callback&&r.callback.call(r.elem,r.elem);t&&t.options.onceOnly&&1==t.firedElems.length&&t.me.unbindEventWithSelectorAndCallback.call(t.target,t.selector,t.callback)},checkChildNodesRecursively:function(e,t,r,a){for(var i,n=0;i=e[n];n++)r(i,t,a)&&a.push({callback:t.callback,elem:i}),0<i.childNodes.length&&u.checkChildNodesRecursively(i.childNodes,t,r,a)},mergeArrays:function(e,t){var r,a={};for(r in e)e.hasOwnProperty(r)&&(a[r]=e[r]);for(r in t)t.hasOwnProperty(r)&&(a[r]=t[r]);return a},toElementsArray:function(e){return void 0===e||"number"==typeof e.length&&e!==c||(e=[e]),e}}),w=((t=function(){this._eventsBucket=[],this._beforeAdding=null,this._beforeRemoving=null}).prototype.addEvent=function(e,t,r,a){var i={target:e,selector:t,options:r,callback:a,firedElems:[]};return this._beforeAdding&&this._beforeAdding(i),this._eventsBucket.push(i),i},t.prototype.removeEvent=function(e){for(var t,r=this._eventsBucket.length-1;t=this._eventsBucket[r];r--)if(e(t)){this._beforeRemoving&&this._beforeRemoving(t);var a=this._eventsBucket.splice(r,1);a&&a.length&&(a[0].callback=null)}},t.prototype.beforeAdding=function(e){this._beforeAdding=e},t.prototype.beforeRemoving=function(e){this._beforeRemoving=e},t),l=function(i,n){var l=new w,o=this,s={fireOnAttributesModification:!1};return l.beforeAdding(function(t){var e,r=t.target;r!==c.document&&r!==c||(r=document.getElementsByTagName("html")[0]),e=new MutationObserver(function(e){n.call(this,e,t)});var a=i(t.options);e.observe(r,a),t.observer=e,t.me=o}),l.beforeRemoving(function(e){e.observer.disconnect()}),this.bindEvent=function(e,t,r){t=u.mergeArrays(s,t);for(var a=u.toElementsArray(this),i=0;i<a.length;i++)l.addEvent(a[i],e,t,r)},this.unbindEvent=function(){var r=u.toElementsArray(this);l.removeEvent(function(e){for(var t=0;t<r.length;t++)if(this===d||e.target===r[t])return!0;return!1})},this.unbindEventWithSelectorOrCallback=function(r){var e,a=u.toElementsArray(this),i=r;e="function"==typeof r?function(e){for(var t=0;t<a.length;t++)if((this===d||e.target===a[t])&&e.callback===i)return!0;return!1}:function(e){for(var t=0;t<a.length;t++)if((this===d||e.target===a[t])&&e.selector===r)return!0;return!1},l.removeEvent(e)},this.unbindEventWithSelectorAndCallback=function(r,a){var i=u.toElementsArray(this);l.removeEvent(function(e){for(var t=0;t<i.length;t++)if((this===d||e.target===i[t])&&e.selector===r&&e.callback===a)return!0;return!1})},this},i=new function(){var s={fireOnAttributesModification:!1,onceOnly:!1,existing:!1};function n(e,t,r){return!(!u.matchesSelector(e,t.selector)||(e._id===d&&(e._id=a++),-1!=t.firedElems.indexOf(e._id))||(t.firedElems.push(e._id),0))}var c=(i=new l(function(e){var t={attributes:!1,childList:!0,subtree:!0};return e.fireOnAttributesModification&&(t.attributes=!0),t},function(e,i){e.forEach(function(e){var t=e.addedNodes,r=e.target,a=[];null!==t&&0<t.length?u.checkChildNodesRecursively(t,i,n,a):"attributes"===e.type&&n(r,i)&&a.push({callback:i.callback,elem:r}),u.callCallbacks(a,i)})})).bindEvent;return i.bindEvent=function(e,t,r){t=void 0===r?(r=t,s):u.mergeArrays(s,t);var a=u.toElementsArray(this);if(t.existing){for(var i=[],n=0;n<a.length;n++)for(var l=a[n].querySelectorAll(e),o=0;o<l.length;o++)i.push({callback:r,elem:l[o]});if(t.onceOnly&&i.length)return r.call(i[0].elem,i[0].elem);setTimeout(u.callCallbacks,1,i)}c.call(this,e,t,r)},i},o=new function(){var a={};function i(e,t){return u.matchesSelector(e,t.selector)}var n=(o=new l(function(){return{childList:!0,subtree:!0}},function(e,a){e.forEach(function(e){var t=e.removedNodes,r=[];null!==t&&0<t.length&&u.checkChildNodesRecursively(t,a,i,r),u.callCallbacks(r,a)})})).bindEvent;return o.bindEvent=function(e,t,r){t=void 0===r?(r=t,a):u.mergeArrays(a,t),n.call(this,e,t,r)},o};e&&g(e.fn),g(HTMLElement.prototype),g(NodeList.prototype),g(HTMLCollection.prototype),g(HTMLDocument.prototype),g(Window.prototype);var n={};return s(i,n,"unbindAllArrive"),s(o,n,"unbindAllLeave"),n}function s(e,t,r){u.addMethod(t,r,e.unbindEvent),u.addMethod(t,r,e.unbindEventWithSelectorOrCallback),u.addMethod(t,r,e.unbindEventWithSelectorAndCallback)}function g(e){e.arrive=i.bindEvent,s(i,e,"unbindArrive"),e.leave=o.bindEvent,s(o,e,"unbindLeave")}}(window,"undefined"==typeof jQuery?null:jQuery,void 0);function check_webp_feature(e,t){var r=new Image;r.onload=function(){var e=0<r.width&&0<r.height;t(e)},r.onerror=function(){t(!1)},r.src="data:image/webp;base64,"+{alpha:"UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",animation:"UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"}[e]}function ewwwLoadImages(e){var n="data-";function t(e,t){for(var r=["align","alt","border","crossorigin","height","hspace","ismap","longdesc","usemap","vspace","width","accesskey","class","contenteditable","contextmenu","dir","draggable","dropzone","hidden","id","lang","spellcheck","style","tabindex","title","translate","sizes","data-caption","data-attachment-id","data-permalink","data-orig-size","data-comments-opened","data-image-meta","data-image-title","data-image-description","data-event-trigger","data-highlight-color","data-highlight-opacity","data-highlight-border-color","data-highlight-border-width","data-highlight-border-opacity","data-no-lazy","data-lazy","data-large_image_width","data-large_image_height"],a=0,i=r.length;a<i;a++)ewwwAttr(t,r[a],e.getAttribute(n+r[a]));return t}if(e){for(var r=document.querySelectorAll(".batch-image img, .image-wrapper a, .ngg-pro-masonry-item a, .ngg-galleria-offscreen-seo-wrapper a"),a=0,i=r.length;a<i;a++)ewwwAttr(r[a],"data-src",r[a].getAttribute("data-webp")),ewwwAttr(r[a],"data-thumbnail",r[a].getAttribute("data-webp-thumbnail"));for(a=0,i=(o=document.querySelectorAll(".rev_slider ul li")).length;a<i;a++){ewwwAttr(o[a],"data-thumb",o[a].getAttribute("data-webp-thumb"));for(var l=1;l<11;)ewwwAttr(o[a],"data-param"+l,o[a].getAttribute("data-webp-param"+l)),l++}var o;for(a=0,i=(o=document.querySelectorAll(".rev_slider img")).length;a<i;a++)ewwwAttr(o[a],"data-lazyload",o[a].getAttribute("data-webp-lazyload"));var s=document.querySelectorAll("div.woocommerce-product-gallery__image");for(a=0,i=s.length;a<i;a++)ewwwAttr(s[a],"data-thumb",s[a].getAttribute("data-webp-thumb"))}var c=document.querySelectorAll("videos");for(a=0,i=c.length;a<i;a++)ewwwAttr(c[a],"poster",e?c[a].getAttribute("data-poster-webp"):c[a].getAttribute("data-poster-image"));var d=document.querySelectorAll("img.ewww_webp_lazy_load");for(a=0,i=d.length;a<i;a++){if(e){ewwwAttr(d[a],"data-lazy-srcset",d[a].getAttribute("data-lazy-srcset-webp")),ewwwAttr(d[a],"data-srcset",d[a].getAttribute("data-srcset-webp")),ewwwAttr(d[a],"data-lazy-src",d[a].getAttribute("data-lazy-src-webp")),ewwwAttr(d[a],"data-src",d[a].getAttribute("data-src-webp")),ewwwAttr(d[a],"data-orig-file",d[a].getAttribute("data-webp-orig-file")),ewwwAttr(d[a],"data-medium-file",d[a].getAttribute("data-webp-medium-file")),ewwwAttr(d[a],"data-large-file",d[a].getAttribute("data-webp-large-file"));var u=d[a].getAttribute("srcset");null!=u&&!1!==u&&u.includes("R0lGOD")&&ewwwAttr(d[a],"src",d[a].getAttribute("data-lazy-src-webp"))}d[a].className=d[a].className.replace(/\bewww_webp_lazy_load\b/,"")}var w=document.querySelectorAll(".ewww_webp");for(a=0,i=w.length;a<i;a++){var g=document.createElement("img");e?(ewwwAttr(g,"src",w[a].getAttribute("data-webp")),ewwwAttr(g,"srcset",w[a].getAttribute("data-srcset-webp")),ewwwAttr(g,"data-orig-file",w[a].getAttribute("data-orig-file")),ewwwAttr(g,"data-orig-file",w[a].getAttribute("data-webp-orig-file")),ewwwAttr(g,"data-medium-file",w[a].getAttribute("data-medium-file")),ewwwAttr(g,"data-medium-file",w[a].getAttribute("data-webp-medium-file")),ewwwAttr(g,"data-large-file",w[a].getAttribute("data-large-file")),ewwwAttr(g,"data-large-file",w[a].getAttribute("data-webp-large-file")),ewwwAttr(g,"data-large_image",w[a].getAttribute("data-large_image")),ewwwAttr(g,"data-large_image",w[a].getAttribute("data-webp-large_image")),ewwwAttr(g,"data-src",w[a].getAttribute("data-src")),ewwwAttr(g,"data-src",w[a].getAttribute("data-webp-src"))):(ewwwAttr(g,"src",w[a].getAttribute("data-img")),ewwwAttr(g,"srcset",w[a].getAttribute("data-srcset-img")),ewwwAttr(g,"data-orig-file",w[a].getAttribute("data-orig-file")),ewwwAttr(g,"data-medium-file",w[a].getAttribute("data-medium-file")),ewwwAttr(g,"data-large-file",w[a].getAttribute("data-large-file")),ewwwAttr(g,"data-large_image",w[a].getAttribute("data-large_image")),ewwwAttr(g,"data-src",w[a].getAttribute("data-src"))),g=t(w[a],g),w[a].parentNode.insertBefore(g,w[a].nextSibling),w[a].className=w[a].className.replace(/\bewww_webp\b/,"")}window.jQuery&&jQuery.fn.isotope&&jQuery.fn.imagesLoaded&&(jQuery(".fusion-posts-container-infinite").imagesLoaded(function(){jQuery(".fusion-posts-container-infinite").hasClass("isotope")&&jQuery(".fusion-posts-container-infinite").isotope()}),jQuery(".fusion-portfolio:not(.fusion-recent-works) .fusion-portfolio-wrapper").imagesLoaded(function(){jQuery(".fusion-portfolio:not(.fusion-recent-works) .fusion-portfolio-wrapper").isotope()}))}function ewwwWebPInit(e){ewwwLoadImages(e),ewwwNggLoadGalleries(e),document.arrive(".ewww_webp",function(){ewwwLoadImages(e)});var t=0,r=setInterval(function(){"undefined"!=typeof galleries&&(ewwwNggParseGalleries(e),clearInterval(r)),1e3<(t+=25)&&clearInterval(r)},25)}function ewwwAttr(e,t,r){null!=r&&!1!==r&&e.setAttribute(t,r)}function ewwwNggParseGalleries(e){if(e)for(var t in galleries){var r=galleries[t];galleries[t].images_list=ewwwNggParseImageList(r.images_list)}}function ewwwNggLoadGalleries(e){e&&document.addEventListener("ngg.galleria.themeadded",function(e,t){window.ngg_galleria._create_backup=window.ngg_galleria.create,window.ngg_galleria.create=function(e,t){var r=$(e).data("id");return galleries["gallery_"+r].images_list=ewwwNggParseImageList(galleries["gallery_"+r].images_list),window.ngg_galleria._create_backup(e,t)}})}function ewwwNggParseImageList(e){for(var t in console.log("parsing gallery images"),e){var r=e[t];if(void 0!==r["image-webp"]&&(e[t].image=r["image-webp"],delete e[t]["image-webp"]),void 0!==r["thumb-webp"]&&(e[t].thumb=r["thumb-webp"],delete e[t]["thumb-webp"]),void 0!==r.full_image_webp&&(e[t].full_image=r.full_image_webp,delete e[t].full_image_webp),void 0!==r.srcsets)for(var a in r.srcsets)nggSrcset=r.srcsets[a],void 0!==r.srcsets[a+"-webp"]&&(e[t].srcsets[a]=r.srcsets[a+"-webp"],delete e[t].srcsets[a+"-webp"]);if(void 0!==r.full_srcsets)for(var i in r.full_srcsets)nggFSrcset=r.full_srcsets[i],void 0!==r.full_srcsets[i+"-webp"]&&(e[t].full_srcsets[i]=r.full_srcsets[i+"-webp"],delete e[t].full_srcsets[i+"-webp"])}return e}check_webp_feature("alpha",ewwwWebPInit);
includes/ls.unveilhooks.js ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ This plugin extends lazySizes to lazyLoad:
3
+ background images, videos/posters and scripts
4
+
5
+ Background-Image:
6
+ For background images, use data-bg attribute:
7
+ <div class="lazyload" data-bg="bg-img.jpg"></div>
8
+
9
+ Video:
10
+ For video/audio use data-poster and preload="none":
11
+ <video class="lazyload" data-poster="poster.jpg" preload="none">
12
+ <!-- sources -->
13
+ </video>
14
+
15
+ Scripts:
16
+ For scripts use data-script:
17
+ <div class="lazyload" data-script="module-name.js"></div>
18
+
19
+
20
+ Script modules using require:
21
+ For modules using require use data-require:
22
+ <div class="lazyload" data-require="module-name"></div>
23
+ */
24
+
25
+ (function(window, factory) {
26
+ var globalInstall = function(){
27
+ factory(window.lazySizes);
28
+ window.removeEventListener('lazyunveilread', globalInstall, true);
29
+ };
30
+
31
+ factory = factory.bind(null, window, window.document);
32
+
33
+ if(typeof module == 'object' && module.exports){
34
+ factory(require('lazysizes'));
35
+ } else if(window.lazySizes) {
36
+ globalInstall();
37
+ } else {
38
+ window.addEventListener('lazyunveilread', globalInstall, true);
39
+ }
40
+ }(window, function(window, document, lazySizes) {
41
+ /*jshint eqnull:true */
42
+ 'use strict';
43
+ var bgLoad, regBgUrlEscape;
44
+ var uniqueUrls = {};
45
+
46
+ if(document.addEventListener){
47
+ regBgUrlEscape = /\(|\)|\s|'/;
48
+
49
+ bgLoad = function (url, cb){
50
+ var img = document.createElement('img');
51
+ img.onload = function(){
52
+ img.onload = null;
53
+ img.onerror = null;
54
+ img = null;
55
+ cb();
56
+ };
57
+ img.onerror = img.onload;
58
+
59
+ img.src = url;
60
+
61
+ if(img && img.complete && img.onload){
62
+ img.onload();
63
+ }
64
+ };
65
+
66
+ addEventListener('lazybeforeunveil', function(e){
67
+ if(e.detail.instance != lazySizes){return;}
68
+
69
+ var load, bg, bgWebP, poster;
70
+ if(!e.defaultPrevented) {
71
+
72
+ if(e.target.preload == 'none'){
73
+ e.target.preload = 'auto';
74
+ }
75
+
76
+ // handle data-bg
77
+ bg = e.target.getAttribute('data-bg');
78
+ if (bg) {
79
+ if(ewww_webp_supported) {
80
+ bgWebP = e.target.getAttribute('data-bg-webp');
81
+ if (bgWebP) {
82
+ bg = bgWebP;
83
+ }
84
+ }
85
+ bg = constrainSrc(bg,e.target.offsetWidth,e.target.offsetHeight);
86
+ e.detail.firesLoad = true;
87
+ load = function(){
88
+ e.target.style.backgroundImage = 'url(' + (regBgUrlEscape.test(bg) ? JSON.stringify(bg) : bg ) + ')';
89
+ e.detail.firesLoad = false;
90
+ lazySizes.fire(e.target, '_lazyloaded', {}, true, true);
91
+ };
92
+
93
+ bgLoad(bg, load);
94
+ }
95
+
96
+ // handle data-poster
97
+ poster = e.target.getAttribute('data-poster');
98
+ if(poster){
99
+ e.detail.firesLoad = true;
100
+ load = function(){
101
+ e.target.poster = poster;
102
+ e.detail.firesLoad = false;
103
+ lazySizes.fire(e.target, '_lazyloaded', {}, true, true);
104
+ };
105
+
106
+ bgLoad(poster, load);
107
+
108
+ }
109
+ }
110
+ }, false);
111
+
112
+ }
113
+
114
+ function addStyleScript(src, style){
115
+ if(uniqueUrls[src]){
116
+ return;
117
+ }
118
+ var elem = document.createElement(style ? 'link' : 'script');
119
+ var insertElem = document.getElementsByTagName('script')[0];
120
+
121
+ if(style){
122
+ elem.rel = 'stylesheet';
123
+ elem.href = src;
124
+ } else {
125
+ elem.src = src;
126
+ }
127
+ uniqueUrls[src] = true;
128
+ uniqueUrls[elem.src || elem.href] = true;
129
+ insertElem.parentNode.insertBefore(elem, insertElem);
130
+ }
131
+ }));
includes/resize_detection.js CHANGED
@@ -1,37 +1,47 @@
1
- // @name Show scaled images
2
- // @namespace http://nedbatchelder.com/
3
-
4
  window.onload = function() {
5
  checkImageSizes();
6
  var adminBarButton = document.getElementById('wp-admin-bar-resize-detection');
7
  if (adminBarButton) {
8
  adminBarButton.onclick = function() {
 
9
  checkImageSizes();
10
  };
11
  }
12
  }
13
  function checkImageSizes() {
14
- // Find images which have width or height different than their natural
15
- // width or height, and give them a stark and ugly marker, as well
16
- // as a useful title.
17
- var imgs = document.getElementsByTagName("img");
18
- for (i = 0; i < imgs.length; i++) {
19
- var img = imgs[i];
 
 
 
 
 
20
  if (img.naturalWidth) {
21
- if ((img.naturalWidth != 1) && (img.naturalHeight != 1)) {
22
- // For each image with a natural width which isn't
23
- // a 1x1 image, check its size.
24
- var wrongWidth = (img.width * 1.5 < img.naturalWidth);
25
- var wrongHeight = (img.height * 1.5 < img.naturalHeight);
26
- if (wrongWidth || wrongHeight) {
27
- img.style.border = "3px #3eadc9 dotted";
28
- img.style.margin = "-3px";
29
- img.title = "Forced to wrong size: " +
30
- img.width + "x" + img.height + ", natural is " +
31
- img.naturalWidth + "x" + img.naturalHeight + "!";
32
- }
33
- }
34
  }
35
- }
36
- return false;
37
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  window.onload = function() {
2
  checkImageSizes();
3
  var adminBarButton = document.getElementById('wp-admin-bar-resize-detection');
4
  if (adminBarButton) {
5
  adminBarButton.onclick = function() {
6
+ clearScaledImages();
7
  checkImageSizes();
8
  };
9
  }
10
  }
11
  function checkImageSizes() {
12
+ // Find images which have width or height different than their natural
13
+ // width or height, and give them a stark and ugly marker, as well
14
+ // as a useful title.
15
+ var imgs = document.getElementsByTagName("img");
16
+ for (i = 0; i < imgs.length; i++) {
17
+ imgs[i].classList.remove('scaled-image');
18
+ checkImageScale(imgs[i]);
19
+ }
20
+ return false;
21
+ }
22
+ function checkImageScale(img) {
23
  if (img.naturalWidth) {
24
+ if ((img.naturalWidth != 1) && (img.naturalHeight != 1)) {
25
+ // For each image with a natural width which isn't
26
+ // a 1x1 image, check its size.
27
+ var wrongWidth = (img.clientWidth * 1.5 < img.naturalWidth);
28
+ var wrongHeight = (img.clientHeight * 1.5 < img.naturalHeight);
29
+ if (wrongWidth || wrongHeight) {
30
+ img.classList.add('scaled-image');
31
+ img.title = "Forced to wrong size: " +
32
+ img.clientWidth + "x" + img.clientHeight + ", natural is " +
33
+ img.naturalWidth + "x" + img.naturalHeight + "!";
34
+ }
35
+ }
 
36
  }
 
 
37
  }
38
+ function clearScaledImages() {
39
+ var scaledImages = document.querySelectorAll('img.scaled-image');
40
+ for (var i = 0, len = scaledImages.length; i < len; i++){
41
+ scaledImages[i].classList.remove('scaled-image');
42
+ }
43
+ }
44
+ document.addEventListener('lazyloaded', function(e){
45
+ e.target.classList.remove('scaled-image');
46
+ checkImageScale(e.target);
47
+ });
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: image, compress, resize, optimize, optimization, lossless, lossy, seo, web
5
  Requires at least: 4.9
6
  Tested up to: 5.1
7
  Requires PHP: 5.6
8
- Stable tag: 4.6.3
9
  License: GPLv3
10
 
11
  Speed up your website and improve your visitors' experience by automatically compressing and resizing images and PDFs. Boost SEO and improve sales.
@@ -174,6 +174,32 @@ http://developer.yahoo.com/performance/rules.html#opt_images
174
  * Feature requests can be viewed and submitted at https://github.com/nosilver4u/ewww-image-optimizer/labels/enhancement
175
  * If you would like to help translate this plugin in your language, get started here: https://translate.wordpress.org/projects/wp-plugins/ewww-image-optimizer/
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  = 4.6.3 =
178
  * changed: folders to ignore setting applies to resizing also
179
  * fixed: lazy load placeholders have inconsistent URLs with ExactDN
5
  Requires at least: 4.9
6
  Tested up to: 5.1
7
  Requires PHP: 5.6
8
+ Stable tag: 4.7.0
9
  License: GPLv3
10
 
11
  Speed up your website and improve your visitors' experience by automatically compressing and resizing images and PDFs. Boost SEO and improve sales.
174
  * Feature requests can be viewed and submitted at https://github.com/nosilver4u/ewww-image-optimizer/labels/enhancement
175
  * If you would like to help translate this plugin in your language, get started here: https://translate.wordpress.org/projects/wp-plugins/ewww-image-optimizer/
176
 
177
+ = 4.7.0 =
178
+ * added: lazy load (on ExactDN tab for now)
179
+ * added: JS WebP supports background images via lazy load (div elements only for now)
180
+ * added: ExactDN supports compression of background images (div elements only for now)
181
+ * added: compat with Google Cloud Storage via WP Offload Media
182
+ * added: automatic PNG to JPG conversion for ExactDN
183
+ * added: ExactDN parsing for legacy WooCommerce API (current API works as-is)
184
+ * changed: responsive image 'sizes' attribute can be auto-calculated by lazy load
185
+ * changed: JS WebP no longer requires jQuery
186
+ * changed: ExactDN srcset multipliers include fullscreen value of 1920px
187
+ * changed: force resize function to ignore filesize with ewww_image_optimizer_resize_filesize_ignore filter
188
+ * changed: prevent .php script/style generators from going through ExactDN
189
+ * changed: ExactDN sites can dismiss exec notice to disable local compression
190
+ * changed: automatic compression disabled during WooCommerce regen with admin notice
191
+ * changed: use wp_resource_hints filter to include ExactDN dns-prefetch earlier in the page header
192
+ * changed: gather debugging information on settings page even when debugging is not enabled yet
193
+ * fixed: Bulk Optimize scanner does not update queue in some cases
194
+ * fixed: ExactDN does not handle themes that support wide and full-screen images in block editor
195
+ * fixed: ExactDN constrains images to 640px in Twenty Nineteen theme
196
+ * fixed: ExactDN mangles Flatsome lazy load placeholder image URL
197
+ * fixed: empty attributes not recognized properly by HTML parser, resulting in broken markup
198
+ * fixed: table nav button styling broken in WP 5.1
199
+ * fixed: ExactDN applies resizing args during image_downsize() even when full/original image is too small
200
+ * fixed: animated GIF resizing breaks the use of image_resize_dimensions filter in WP_Image_Editor_GD
201
+ * fixed: NextGen bulk optimizer unable to decode meta_data
202
+
203
  = 4.6.3 =
204
  * changed: folders to ignore setting applies to resizing also
205
  * fixed: lazy load placeholders have inconsistent URLs with ExactDN
uninstall.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Uninstaller for plugin.
4
+ *
5
+ * @link https://ewww.io
6
+ * @package EWWW_Image_Optimizer
7
+ */
8
+
9
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
10
+ die;
11
+ }
12
+ if ( ! function_exists( 'ewww_image_optimizer_htaccess_path' ) ) {
13
+ /**
14
+ * Figure out where the .htaccess file should live.
15
+ *
16
+ * @return string The path to the .htaccess file.
17
+ */
18
+ function ewww_image_optimizer_htaccess_path() {
19
+ $htpath = get_home_path();
20
+ if ( get_option( 'siteurl' ) !== get_option( 'home' ) ) {
21
+ $path_diff = str_replace( get_option( 'home' ), '', get_option( 'siteurl' ) );
22
+ $newhtpath = trailingslashit( rtrim( $htpath, '/' ) . '/' . ltrim( $path_diff, '/' ) ) . '.htaccess';
23
+ if ( is_file( $newhtpath ) ) {
24
+ return $newhtpath;
25
+ }
26
+ }
27
+ return $htpath . '.htaccess';
28
+ }
29
+ }
30
+
31
+ if ( current_user_can( 'delete_plugins' ) ) {
32
+ if ( extract_from_markers( ewww_image_optimizer_htaccess_path(), 'EWWWIO' ) ) {
33
+ insert_with_markers( ewww_image_optimizer_htaccess_path(), 'EWWWIO', '' );
34
+ }
35
+ global $wpdb;
36
+ $wpdb->query( $wpdb->prepare( "DELETE from $wpdb->ewwwio_queue WHERE gallery = %s", 'media' ) );
37
+ $wpdb->query( $wpdb->prepare( "DELETE from $wpdb->ewwwio_queue WHERE gallery = %s", 'flag' ) );
38
+ $wpdb->query( $wpdb->prepare( "DELETE from $wpdb->ewwwio_queue WHERE gallery = %s", 'nextgen' ) );
39
+ $wpdb->query( $wpdb->prepare( "DELETE from $wpdb->ewwwio_queue WHERE gallery = %s", 'nextcell' ) );
40
+ }
unique.php CHANGED
@@ -14,6 +14,8 @@ if ( ! defined( 'ABSPATH' ) ) {
14
 
15
  // Installation routine for PNGOUT.
16
  add_action( 'admin_action_ewww_image_optimizer_install_pngout', 'ewww_image_optimizer_install_pngout_wrapper' );
 
 
17
  // Removes the binaries when the plugin is deactivated.
18
  register_deactivation_hook( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE, 'ewww_image_optimizer_remove_binaries' );
19
 
@@ -66,7 +68,7 @@ function ewww_image_optimizer_exec_init() {
66
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_NOEXEC' ) ) {
67
  define( 'EWWW_IMAGE_OPTIMIZER_NOEXEC', true );
68
  }
69
- ewwwio_debug_message( 'wp.com site, disabling tools' );
70
  ewww_image_optimizer_disable_tools();
71
  // Check if this is an unsupported OS (not Linux or Mac OSX or FreeBSD or Windows or SunOS).
72
  } elseif ( 'Linux' != PHP_OS && 'Darwin' != PHP_OS && 'FreeBSD' != PHP_OS && 'WINNT' != PHP_OS && 'SunOS' != PHP_OS ) {
@@ -112,14 +114,34 @@ function ewww_image_optimizer_tool_init() {
112
  */
113
  function ewww_image_optimizer_set_defaults() {
114
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
115
- add_site_option( 'ewww_image_optimizer_disable_pngout', true );
116
- add_site_option( 'ewww_image_optimizer_optipng_level', 2 );
117
- add_site_option( 'ewww_image_optimizer_pngout_level', 2 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  add_site_option( 'ewww_image_optimizer_metadata_remove', true );
119
  add_site_option( 'ewww_image_optimizer_jpg_level', '10' );
120
  add_site_option( 'ewww_image_optimizer_png_level', '10' );
121
  add_site_option( 'ewww_image_optimizer_gif_level', '10' );
122
  add_site_option( 'ewww_image_optimizer_pdf_level', '0' );
 
 
 
 
123
  add_site_option( 'exactdn_lossy', true );
124
  }
125
 
@@ -144,7 +166,7 @@ function ewww_image_optimizer_notice_hosting_requires_api() {
144
  return;
145
  }
146
  $settings_url = admin_url( "$options_page?page=" . plugin_basename( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ) );
147
- echo "<div id='ewww-image-optimizer-cloud-key-required' class='error'><p><strong>" .
148
  /* translators: %s: Name of a web host, like WordPress.com or Pantheon. */
149
  sprintf( esc_html__( 'The EWWW Image Optimizer requires an API key or an ExactDN subscription to optimize images on %s sites.', 'ewww-image-optimizer-cloud' ), $webhost ) .
150
  "</strong> <a href='https://ewww.io/plans/'>" . esc_html__( 'Purchase a subscription.', 'ewww-image-optimizer-cloud' ) .
@@ -156,7 +178,7 @@ function ewww_image_optimizer_notice_hosting_requires_api() {
156
  */
157
  function ewww_image_optimizer_notice_os() {
158
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
159
- echo "<div id='ewww-image-optimizer-warning-os' class='error'><p><strong>" . esc_html__( 'EWWW Image Optimizer is supported on Linux, FreeBSD, Mac OSX, and Windows', 'ewww-image-optimizer' ) . '.</strong> ' .
160
  /* translators: %s: An operating system. */
161
  sprintf( esc_html__( 'Unfortunately, the EWWW Image Optimizer plugin does not work with %s', 'ewww-image-optimizer' ), htmlentities( PHP_OS ) ) . '.</p></div>';
162
  }
@@ -273,7 +295,7 @@ function ewww_image_optimizer_check_permissions( $file, $minimum ) {
273
  * Alert the user when the tool folder could not be created.
274
  */
275
  function ewww_image_optimizer_tool_folder_notice() {
276
- echo "<div id='ewww-image-optimizer-warning-tool-folder-create' class='error'><p><strong>" . esc_html__( 'EWWW Image Optimizer could not create the tool folder', 'ewww-image-optimizer' ) . ': ' . htmlentities( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ) . '.</strong> ' . esc_html__( 'Please adjust permissions or create the folder', 'ewww-image-optimizer' ) . '.</p></div>';
277
  }
278
 
279
  /**
@@ -289,7 +311,7 @@ function ewww_image_optimizer_tool_folder_permissions_notice() {
289
  } else {
290
  $settings_page = 'options-general.php?page=' . EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE_REL;
291
  }
292
- echo "<div id='ewww-image-optimizer-warning-tool-folder-permissions' class='error'><p><strong>" .
293
  /* translators: %s: Folder location where executables should be installed */
294
  sprintf( esc_html__( 'EWWW Image Optimizer could not install tools in %s', 'ewww-image-optimizer' ), htmlentities( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ) ) . '.</strong> ' .
295
  esc_html__( 'Please adjust permissions or create the folder. If you have installed the tools elsewhere on your system, check the option to Use System Paths.', 'ewww-image-optimizer' ) . ' ' .
@@ -310,7 +332,7 @@ function ewww_image_optimizer_tool_installation_failed_notice() {
310
  } else {
311
  $settings_page = 'options-general.php?page=' . EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE_REL;
312
  }
313
- echo "<div id='ewww-image-optimizer-warning-tool-install' class='error'><p><strong>" .
314
  /* translators: %s: Folder location where executables should be installed */
315
  sprintf( esc_html__( 'EWWW Image Optimizer could not install tools in %s', 'ewww-image-optimizer' ), htmlentities( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ) ) . '.</strong> ' .
316
  esc_html__( 'Please adjust permissions or create the folder. If you have installed the tools elsewhere on your system, check the option to Use System Paths.', 'ewww-image-optimizer' ) . ' ' .
@@ -504,6 +526,23 @@ function ewww_image_optimizer_define_noexec() {
504
  }
505
  }
506
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
507
  /**
508
  * Checks for safe mode and exec, then displays an error if needed.
509
  *
@@ -519,11 +558,25 @@ function ewww_image_optimizer_notice_utils( $quiet = null ) {
519
  }
520
  // Need to be a little particular with the quiet parameter.
521
  if ( 'quiet' !== $quiet && ! $no_compression ) {
 
522
  // Display a warning if exec() is disabled, can't run local tools without it.
523
- echo "<div id='ewww-image-optimizer-warning-exec' class='error'><p>" . esc_html__( 'EWWW Image Optimizer requires exec() to perform local compression. Your system administrator has disabled the exec() function, ask them to enable it.', 'ewww-image-optimizer' ) .
524
- '<br>' . esc_html__( 'An API key or ExactDN subscription will allow you to offload the compression to our dedicated servers instead.', 'ewww-image-optimizer' ) .
525
- ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ? '<br>' . esc_html__( 'Sites that use ExactDN already have built-in image optimization and may disable the compression options on the Basic tab to dismiss this notice.', 'ewww-image-optimizer' ) : '' ) .
526
  '</p></div>';
 
 
 
 
 
 
 
 
 
 
 
 
 
527
  }
528
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_NOEXEC' ) ) {
529
  define( 'EWWW_IMAGE_OPTIMIZER_NOEXEC', true );
@@ -625,7 +678,7 @@ function ewww_image_optimizer_notice_utils( $quiet = null ) {
625
  } elseif ( ! is_writable( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ) ) {
626
  ewww_image_optimizer_tool_folder_permissions_notice();
627
  }
628
- echo "<div id='ewww-image-optimizer-warning-opt-missing' class='error'><p>" .
629
  /* translators: 1-6: jpegtran, optipng, pngout, pngquant, gifsicle, and cwebp (links) 7: Settings Page (link) 8: Installation Instructions (link) */
630
  sprintf( esc_html__( 'EWWW Image Optimizer uses %1$s, %2$s, %3$s, %4$s, %5$s, and %6$s. You are missing: %7$s. Please install via the %8$s or the %9$s.', 'ewww-image-optimizer' ), "<a href='http://jpegclub.org/jpegtran/'>jpegtran</a>", "<a href='http://optipng.sourceforge.net/'>optipng</a>", "<a href='http://advsys.net/ken/utils.htm'>pngout</a>", "<a href='http://pngquant.org/'>pngquant</a>", "<a href='http://www.lcdf.org/gifsicle/'>gifsicle</a>", "<a href='https://developers.google.com/speed/webp/'>cwebp</a>", $msg, "<a href='$settings_page'>" . esc_html__( 'Settings Page', 'ewww-image-optimizer' ) . '</a>', "<a href='https://docs.ewww.io/'>" . esc_html__( 'Installation Instructions', 'ewww-image-optimizer' ) . '</a>' ) . '</p></div>';
631
  ewwwio_memory( __FUNCTION__ );
@@ -1051,7 +1104,7 @@ function ewww_image_optimizer_mimetype( $path, $case ) {
1051
  ewwwio_debug_message( "testing mimetype: $path" );
1052
  $type = false;
1053
  // For S3 images/files, don't attempt to read the file, just use the quick (filename) mime check.
1054
- if ( 'i' === $case && strpos( $path, 's3' ) === 0 ) {
1055
  return ewww_image_optimizer_quick_mimetype( $path );
1056
  }
1057
  if ( 'i' === $case && preg_match( '/^RIFF.+WEBPVP8/', file_get_contents( $path, null, null, 0, 16 ) ) ) {
@@ -1492,13 +1545,18 @@ function ewww_image_optimizer_find_nix_binary( $binary, $switch ) {
1492
  /**
1493
  * Resizes an image with gifsicle to preserve animations.
1494
  *
1495
- * @param string $file The file to resize.
1496
- * @param int|null $max_w Desired image width.
1497
- * @param int|null $max_h Desired image height.
1498
- * @param bool $crop Optional. Scale by default, crop if true.
 
 
 
 
 
1499
  * @return string|WP_Error The image contents or the error message.
1500
  */
1501
- function ewww_image_optimizer_gifsicle_resize( $file, $max_w, $max_h, $crop = false ) {
1502
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1503
  $tools = ewww_image_optimizer_path_check(
1504
  false,
@@ -1516,37 +1574,22 @@ function ewww_image_optimizer_gifsicle_resize( $file, $max_w, $max_h, $crop = fa
1516
  );
1517
  }
1518
  ewwwio_debug_message( "file: $file " );
1519
- ewwwio_debug_message( "width: $max_w" );
1520
- ewwwio_debug_message( "height: $max_h" );
1521
- $orig_dimensions = getimagesize( $file );
1522
- if ( empty( $orig_dimensions ) ) {
1523
- return new WP_Error( 'image_resize_error', __( 'Invalid image dimensions.', 'ewww-image-optimizer' ) );
1524
- }
1525
- $orig_w = $orig_dimensions[0];
1526
- $orig_h = $orig_dimensions[1];
1527
 
1528
  $outfile = "$file.tmp";
1529
  // Run gifsicle.
1530
- if ( $crop ) {
1531
- $dims = ewwwio_crop_dimensions( $orig_w, $orig_h, $max_w, $max_h );
1532
- if ( ! $dims ) {
1533
- return new WP_Error( 'error_getting_dimensions', __( 'Could not calculate resized image dimensions' ), $file );
1534
- }
1535
- ewwwio_debug_message( implode( ',', $dims ) );
1536
- list( $src_x, $src_y, $dst_w, $dst_h ) = $dims;
1537
-
1538
- list( $new_w, $new_h ) = wp_constrain_dimensions( $dst_w, $dst_h, $max_w, $max_h );
1539
-
1540
- $dim_string = $new_w . 'x' . $new_h;
1541
- $crop_string = $src_x . ',' . $src_y . '+' . $dst_w . 'x' . $dst_h;
1542
  ewwwio_debug_message( "resize to $dim_string" );
1543
  ewwwio_debug_message( "crop to $crop_string" );
1544
  exec( "{$tools['GIFSICLE']} --crop $crop_string -o " . ewww_image_optimizer_escapeshellarg( $outfile ) . ' ' . ewww_image_optimizer_escapeshellarg( $file ) );
1545
  exec( "{$tools['GIFSICLE']} --resize-fit $dim_string -b " . ewww_image_optimizer_escapeshellarg( $outfile ) );
1546
  } else {
1547
- list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $max_w, $max_h );
1548
-
1549
- $dim_string = $new_w . 'x' . $new_h;
1550
  exec( "{$tools['GIFSICLE']} --resize-fit $dim_string -o " . ewww_image_optimizer_escapeshellarg( $outfile ) . ' ' . ewww_image_optimizer_escapeshellarg( $file ) );
1551
  }
1552
  ewwwio_debug_message( "$file resized to $outfile" );
@@ -1699,7 +1742,7 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
1699
  if ( empty( $s3_uploads_image ) ) {
1700
  $s3_uploads_image = false;
1701
  }
1702
- if ( strpos( $file, 's3' ) === 0 && class_exists( 'S3_Uploads' ) ) {
1703
  $s3_uploads_image = $file;
1704
  $s3_uploads_instance = S3_Uploads::get_instance();
1705
  $s3_uploads_instance->setup();
@@ -1715,20 +1758,14 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
1715
  /* translators: %s: Image filename */
1716
  $msg = sprintf( __( 'Could not find %s', 'ewww-image-optimizer' ), $file );
1717
  ewwwio_debug_message( "file doesn't appear to exist: $file" );
1718
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
1719
- unlink( $file );
1720
- unset( $s3_uploads_image );
1721
- }
1722
  return array( false, $msg, $converted, $original );
1723
  }
1724
  if ( false === is_writable( $file ) ) {
1725
  /* translators: %s: Image filename */
1726
  $msg = sprintf( __( '%s is not writable', 'ewww-image-optimizer' ), $file );
1727
  ewwwio_debug_message( "couldn't write to the file $file" );
1728
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
1729
- unlink( $file );
1730
- unset( $s3_uploads_image );
1731
- }
1732
  return array( false, $msg, $converted, $original );
1733
  }
1734
  $file_perms = 'unknown';
@@ -1749,20 +1786,14 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
1749
  $type = ewww_image_optimizer_mimetype( $file, 'i' );
1750
  if ( ! $type ) {
1751
  ewwwio_debug_message( 'could not find any functions for mimetype detection' );
 
1752
  // Otherwise we store an error message since we couldn't get the mime-type.
1753
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
1754
- unlink( $file );
1755
- unset( $s3_uploads_image );
1756
- }
1757
  return array( false, __( 'Unknown file type', 'ewww-image-optimizer' ), $converted, $original );
1758
  }
1759
  // Not an image or pdf.
1760
  if ( strpos( $type, 'image' ) === false && strpos( $type, 'pdf' ) === false ) {
1761
  ewwwio_debug_message( "unsupported mimetype: $type" );
1762
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
1763
- unlink( $file );
1764
- unset( $s3_uploads_image );
1765
- }
1766
  return array( false, __( 'Unsupported file type', 'ewww-image-optimizer' ) . ": $type", $converted, $original );
1767
  }
1768
  if ( ! is_object( $ewww_image ) || ! $ewww_image instanceof EWWW_Image || $ewww_image->file != $file ) {
@@ -1825,20 +1856,14 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
1825
  ewwwio_debug_message( "original filesize: $orig_size" );
1826
  if ( $orig_size < ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_size' ) ) {
1827
  ewwwio_debug_message( "optimization bypassed due to filesize: $file" );
 
1828
  // Tell the user optimization was skipped.
1829
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
1830
- unlink( $file );
1831
- unset( $s3_uploads_image );
1832
- }
1833
  return array( false, __( 'Optimization skipped', 'ewww-image-optimizer' ), $converted, $file );
1834
  }
1835
  if ( 'image/png' == $type && ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_png_size' ) && $orig_size > ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_png_size' ) ) {
1836
  ewwwio_debug_message( "optimization bypassed due to filesize: $file" );
 
1837
  // Tell the user optimization was skipped.
1838
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
1839
- unlink( $file );
1840
- unset( $s3_uploads_image );
1841
- }
1842
  return array( false, __( 'Optimization skipped', 'ewww-image-optimizer' ), $converted, $file );
1843
  }
1844
  $backup_hash = '';
@@ -1874,11 +1899,7 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
1874
  if ( empty( $_REQUEST['ewww_force'] ) && ! ( $new && $convert ) ) {
1875
  $results_msg = ewww_image_optimizer_check_table( $file, $orig_size );
1876
  if ( $results_msg ) {
1877
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
1878
- unlink( $file );
1879
- $file = $s3_uploads_image;
1880
- unset( $s3_uploads_image );
1881
- }
1882
  return array( $file, $results_msg, $converted, $original );
1883
  }
1884
  }
@@ -2131,11 +2152,7 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
2131
  if ( empty( $_REQUEST['ewww_force'] ) && ! ( $new && $convert ) ) {
2132
  $results_msg = ewww_image_optimizer_check_table( $file, $orig_size );
2133
  if ( $results_msg ) {
2134
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
2135
- unlink( $file );
2136
- $file = $s3_uploads_image;
2137
- unset( $s3_uploads_image );
2138
- }
2139
  return array( $file, $results_msg, $converted, $original );
2140
  }
2141
  }
@@ -2422,11 +2439,7 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
2422
  if ( empty( $_REQUEST['ewww_force'] ) && ! ( $new && $convert ) ) {
2423
  $results_msg = ewww_image_optimizer_check_table( $file, $orig_size );
2424
  if ( $results_msg ) {
2425
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
2426
- unlink( $file );
2427
- $file = $s3_uploads_image;
2428
- unset( $s3_uploads_image );
2429
- }
2430
  return array( $file, $results_msg, $converted, $original );
2431
  }
2432
  }
@@ -2564,11 +2577,7 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
2564
  if ( empty( $_REQUEST['ewww_force'] ) ) {
2565
  $results_msg = ewww_image_optimizer_check_table( $file, $orig_size );
2566
  if ( $results_msg ) {
2567
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
2568
- unlink( $file );
2569
- $file = $s3_uploads_image;
2570
- unset( $s3_uploads_image );
2571
- }
2572
  return array( $file, $results_msg, false, $original );
2573
  }
2574
  }
@@ -2579,10 +2588,7 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
2579
  break;
2580
  default:
2581
  // If not a JPG, PNG, or GIF, tell the user we don't work with strangers.
2582
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
2583
- unlink( $file );
2584
- unset( $s3_uploads_image );
2585
- }
2586
  return array( false, __( 'Unsupported file type', 'ewww-image-optimizer' ) . ": $type", $converted, $original );
2587
  } // End switch().
2588
  // Allow other plugins to run operations on the images after optimization.
@@ -2590,10 +2596,7 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
2590
  do_action( 'ewww_image_optimizer_post_optimization', $file, $type, $fullsize );
2591
  // If their cloud api license limit has been exceeded.
2592
  if ( 'exceeded' == $result ) {
2593
- if ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
2594
- unlink( $file );
2595
- unset( $s3_uploads_image );
2596
- }
2597
  return array( false, __( 'License exceeded', 'ewww-image-optimizer' ), $converted, $original );
2598
  }
2599
  if ( ! empty( $new_size ) ) {
@@ -2607,15 +2610,12 @@ function ewww_image_optimizer( $file, $gallery_type = 4, $converted = false, $ne
2607
  $results_msg = ewww_image_optimizer_update_table( $file, $new_size, $orig_size, $original, $backup_hash );
2608
  if ( $s3_uploads_image && strpos( $file, 's3-uploads' ) === false ) {
2609
  copy( $file, $s3_uploads_image );
2610
- unlink( $file );
2611
- $file = $s3_uploads_image;
2612
- unset( $s3_uploads_image );
2613
  }
 
2614
  ewwwio_memory( __FUNCTION__ );
2615
  return array( $file, $results_msg, $converted, $original );
2616
- } elseif ( strpos( $file, 's3' ) !== 0 && strpos( $file, 's3-uploads' ) === false && $s3_uploads_image && is_file( $file ) ) {
2617
- unset( $s3_uploads_image );
2618
- unlink( $file );
2619
  }
2620
  ewwwio_memory( __FUNCTION__ );
2621
  // Otherwise, send back the filename, the results (some sort of error message), the $converted flag, and the name of the original image.
14
 
15
  // Installation routine for PNGOUT.
16
  add_action( 'admin_action_ewww_image_optimizer_install_pngout', 'ewww_image_optimizer_install_pngout_wrapper' );
17
+ // AJAX action hook to dismiss the exec notice May be extended to other notices in the future.
18
+ add_action( 'wp_ajax_ewww_dismiss_exec_notice', 'ewww_image_optimizer_dismiss_exec_notice' );
19
  // Removes the binaries when the plugin is deactivated.
20
  register_deactivation_hook( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE, 'ewww_image_optimizer_remove_binaries' );
21
 
68
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_NOEXEC' ) ) {
69
  define( 'EWWW_IMAGE_OPTIMIZER_NOEXEC', true );
70
  }
71
+ ewwwio_debug_message( 'wp.com/pantheon site, disabling tools' );
72
  ewww_image_optimizer_disable_tools();
73
  // Check if this is an unsupported OS (not Linux or Mac OSX or FreeBSD or Windows or SunOS).
74
  } elseif ( 'Linux' != PHP_OS && 'Darwin' != PHP_OS && 'FreeBSD' != PHP_OS && 'WINNT' != PHP_OS && 'SunOS' != PHP_OS ) {
114
  */
115
  function ewww_image_optimizer_set_defaults() {
116
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
117
+ // Set defaults for all options that need to be autoloaded.
118
+ add_option( 'ewww_image_optimizer_noauto', false );
119
+ add_option( 'ewww_image_optimizer_disable_editor', false );
120
+ add_option( 'ewww_image_optimizer_debug', false );
121
+ add_option( 'ewww_image_optimizer_metadata_remove', true );
122
+ add_option( 'ewww_image_optimizer_jpg_level', '10' );
123
+ add_option( 'ewww_image_optimizer_png_level', '10' );
124
+ add_option( 'ewww_image_optimizer_gif_level', '10' );
125
+ add_option( 'ewww_image_optimizer_pdf_level', '0' );
126
+ add_option( 'ewww_image_optimizer_exactdn', false );
127
+ add_option( 'exactdn_all_the_things', true );
128
+ add_option( 'exactdn_lossy', true );
129
+ add_option( 'ewww_image_optimizer_lazy_load', false );
130
+ add_option( 'ewww_image_optimizer_disable_pngout', true );
131
+ add_option( 'ewww_image_optimizer_optipng_level', 2 );
132
+ add_option( 'ewww_image_optimizer_pngout_level', 2 );
133
+ add_option( 'ewww_image_optimizer_webp_for_cdn', false );
134
+
135
+ // Set network defaults.
136
  add_site_option( 'ewww_image_optimizer_metadata_remove', true );
137
  add_site_option( 'ewww_image_optimizer_jpg_level', '10' );
138
  add_site_option( 'ewww_image_optimizer_png_level', '10' );
139
  add_site_option( 'ewww_image_optimizer_gif_level', '10' );
140
  add_site_option( 'ewww_image_optimizer_pdf_level', '0' );
141
+ add_site_option( 'ewww_image_optimizer_disable_pngout', true );
142
+ add_site_option( 'ewww_image_optimizer_optipng_level', 2 );
143
+ add_site_option( 'ewww_image_optimizer_pngout_level', 2 );
144
+ add_site_option( 'exactdn_all_the_things', true );
145
  add_site_option( 'exactdn_lossy', true );
146
  }
147
 
166
  return;
167
  }
168
  $settings_url = admin_url( "$options_page?page=" . plugin_basename( EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE ) );
169
+ echo "<div id='ewww-image-optimizer-cloud-key-required' class='notice notice-error'><p><strong>" .
170
  /* translators: %s: Name of a web host, like WordPress.com or Pantheon. */
171
  sprintf( esc_html__( 'The EWWW Image Optimizer requires an API key or an ExactDN subscription to optimize images on %s sites.', 'ewww-image-optimizer-cloud' ), $webhost ) .
172
  "</strong> <a href='https://ewww.io/plans/'>" . esc_html__( 'Purchase a subscription.', 'ewww-image-optimizer-cloud' ) .
178
  */
179
  function ewww_image_optimizer_notice_os() {
180
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
181
+ echo "<div id='ewww-image-optimizer-warning-os' class='notice notice-error'><p><strong>" . esc_html__( 'EWWW Image Optimizer is supported on Linux, FreeBSD, Mac OSX, and Windows', 'ewww-image-optimizer' ) . '.</strong> ' .
182
  /* translators: %s: An operating system. */
183
  sprintf( esc_html__( 'Unfortunately, the EWWW Image Optimizer plugin does not work with %s', 'ewww-image-optimizer' ), htmlentities( PHP_OS ) ) . '.</p></div>';
184
  }
295
  * Alert the user when the tool folder could not be created.
296
  */
297
  function ewww_image_optimizer_tool_folder_notice() {
298
+ echo "<div id='ewww-image-optimizer-warning-tool-folder-create' class='notice notice-error'><p><strong>" . esc_html__( 'EWWW Image Optimizer could not create the tool folder', 'ewww-image-optimizer' ) . ': ' . htmlentities( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ) . '.</strong> ' . esc_html__( 'Please adjust permissions or create the folder', 'ewww-image-optimizer' ) . '.</p></div>';
299
  }
300
 
301
  /**
311
  } else {
312
  $settings_page = 'options-general.php?page=' . EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE_REL;
313
  }
314
+ echo "<div id='ewww-image-optimizer-warning-tool-folder-permissions' class='notice notice-error'><p><strong>" .
315
  /* translators: %s: Folder location where executables should be installed */
316
  sprintf( esc_html__( 'EWWW Image Optimizer could not install tools in %s', 'ewww-image-optimizer' ), htmlentities( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ) ) . '.</strong> ' .
317
  esc_html__( 'Please adjust permissions or create the folder. If you have installed the tools elsewhere on your system, check the option to Use System Paths.', 'ewww-image-optimizer' ) . ' ' .
332
  } else {
333
  $settings_page = 'options-general.php?page=' . EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE_REL;
334
  }
335
+ echo "<div id='ewww-image-optimizer-warning-tool-install' class='notice notice-error'><p><strong>" .
336
  /* translators: %s: Folder location where executables should be installed */
337
  sprintf( esc_html__( 'EWWW Image Optimizer could not install tools in %s', 'ewww-image-optimizer' ), htmlentities( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ) ) . '.</strong> ' .
338
  esc_html__( 'Please adjust permissions or create the folder. If you have installed the tools elsewhere on your system, check the option to Use System Paths.', 'ewww-image-optimizer' ) . ' ' .
526
  }
527
  }
528
 
529
+ /**
530
+ * Disables local compression when exec notice is dismissed by ExactDN user.
531
+ */
532
+ function ewww_image_optimizer_dismiss_exec_notice() {
533
+ ewwwio_ob_clean();
534
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
535
+ // Verify that the user is properly authorized.
536
+ if ( ! current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', 'manage_options' ) ) ) {
537
+ wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) );
538
+ }
539
+ update_option( 'ewww_image_optimizer_jpg_level', 0 );
540
+ update_option( 'ewww_image_optimizer_png_level', 0 );
541
+ update_option( 'ewww_image_optimizer_gif_level', 0 );
542
+ update_option( 'ewww_image_optimizer_pdf_level', 0 );
543
+ wp_die();
544
+ }
545
+
546
  /**
547
  * Checks for safe mode and exec, then displays an error if needed.
548
  *
558
  }
559
  // Need to be a little particular with the quiet parameter.
560
  if ( 'quiet' !== $quiet && ! $no_compression ) {
561
+ $exactdn_dismiss = ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ? true : false;
562
  // Display a warning if exec() is disabled, can't run local tools without it.
563
+ echo "<div id='ewww-image-optimizer-warning-exec' " . ( $exactdn_dismiss ? "class='notice notice-warning is-dismissible'" : "class='notice notice-error'" ) . '><p>' . esc_html__( 'EWWW Image Optimizer requires exec() to perform local compression. Your system administrator has disabled the exec() function, ask them to enable it.', 'ewww-image-optimizer' ) .
564
+ ( ! $exactdn_dismiss ? '<br>' . esc_html__( 'An API key or ExactDN subscription will allow you to offload the compression to our dedicated servers instead.', 'ewww-image-optimizer' )
565
+ : '<br>' . esc_html__( 'Sites that use ExactDN already have built-in image optimization and may dismiss this notice to disable local compression.', 'ewww-image-optimizer' ) ) .
566
  '</p></div>';
567
+ echo
568
+ "<script>\n" .
569
+ "jQuery(document).on('click', '#ewww-image-optimizer-warning-exec .notice-dismiss', function() {\n" .
570
+ "\tvar ewww_dismiss_exec_data = {\n" .
571
+ "\t\taction: 'ewww_dismiss_exec_notice',\n" .
572
+ "\t};\n" .
573
+ "\tjQuery.post(ajaxurl, ewww_dismiss_exec_data, function(response) {\n" .
574
+ "\t\tif (response) {\n" .
575
+ "\t\t\tconsole.log(response);\n" .
576
+ "\t\t}\n" .
577
+ "\t});\n" .
578
+ "});\n" .
579
+ "</script>\n";
580
  }
581
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_NOEXEC' ) ) {
582
  define( 'EWWW_IMAGE_OPTIMIZER_NOEXEC', true );
678
  } elseif ( ! is_writable( EWWW_IMAGE_OPTIMIZER_TOOL_PATH ) ) {
679
  ewww_image_optimizer_tool_folder_permissions_notice();
680
  }
681
+ echo "<div id='ewww-image-optimizer-warning-opt-missing' class='notice notice-error'><p>" .
682
  /* translators: 1-6: jpegtran, optipng, pngout, pngquant, gifsicle, and cwebp (links) 7: Settings Page (link) 8: Installation Instructions (link) */
683
  sprintf( esc_html__( 'EWWW Image Optimizer uses %1$s, %2$s, %3$s, %4$s, %5$s, and %6$s. You are missing: %7$s. Please install via the %8$s or the %9$s.', 'ewww-image-optimizer' ), "<a href='http://jpegclub.org/jpegtran/'>jpegtran</a>", "<a href='http://optipng.sourceforge.net/'>optipng</a>", "<a href='http://advsys.net/ken/utils.htm'>pngout</a>", "<a href='http://pngquant.org/'>pngquant</a>", "<a href='http://www.lcdf.org/gifsicle/'>gifsicle</a>", "<a href='https://developers.google.com/speed/webp/'>cwebp</a>", $msg, "<a href='$settings_page'>" . esc_html__( 'Settings Page', 'ewww-image-optimizer' ) . '</a>', "<a href='https://docs.ewww.io/'>" . esc_html__( 'Installation Instructions', 'ewww-image-optimizer' ) . '</a>' ) . '</p></div>';
684
  ewwwio_memory( __FUNCTION__ );
1104
  ewwwio_debug_message( "testing mimetype: $path" );
1105
  $type = false;
1106
  // For S3 images/files, don't attempt to read the file, just use the quick (filename) mime check.
1107
+ if ( 'i' === $case && ewww_image_optimizer_stream_wrapped( $path ) ) {
1108
  return ewww_image_optimizer_quick_mimetype( $path );
1109
  }
1110
  if ( 'i' === $case && preg_match( '/^RIFF.+WEBPVP8/', file_get_contents( $path, null, null, 0, 16 ) ) ) {
1545
  /**
1546
  * Resizes an image with gifsicle to preserve animations.
1547
  *
1548
+ * @param string $file The file to resize.
1549
+ * @param int $dst_x X-coordinate of destination image (usually 0).
1550
+ * @param int $dst_y Y-coordinate of destination image (usually 0).
1551
+ * @param int $src_x X-coordinate of source image (usually 0 unless cropping).
1552
+ * @param int $src_y Y-coordinate of source image (usually 0 unless cropping).
1553
+ * @param int $dst_w Desired image width.
1554
+ * @param int $dst_h Desired image height.
1555
+ * @param int $src_w Source width.
1556
+ * @param int $src_h Source height.
1557
  * @return string|WP_Error The image contents or the error message.
1558
  */
1559
+ function ewww_image_optimizer_gifsicle_resize( $file, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) {
1560
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1561
  $tools = ewww_image_optimizer_path_check(
1562
  false,
1574
  );
1575
  }
1576
  ewwwio_debug_message( "file: $file " );
1577
+ ewwwio_debug_message( "width: $dst_w" );
1578
+ ewwwio_debug_message( "height: $dst_h" );
1579
+
1580
+ list( $orig_w, $orig_h ) = getimagesize( $file );
 
 
 
 
1581
 
1582
  $outfile = "$file.tmp";
1583
  // Run gifsicle.
1584
+ if ( $orig_w != $src_w || $orig_h != $src_h ) {
1585
+ $dim_string = $dst_w . 'x' . $dst_h;
1586
+ $crop_string = $src_x . ',' . $src_y . '+' . $src_w . 'x' . $src_h;
 
 
 
 
 
 
 
 
 
1587
  ewwwio_debug_message( "resize to $dim_string" );
1588
  ewwwio_debug_message( "crop to $crop_string" );
1589
  exec( "{$tools['GIFSICLE']} --crop $crop_string -o " . ewww_image_optimizer_escapeshellarg( $outfile ) . ' ' . ewww_image_optimizer_escapeshellarg( $file ) );
1590
  exec( "{$tools['GIFSICLE']} --resize-fit $dim_string -b " . ewww_image_optimizer_escapeshellarg( $outfile ) );
1591
  } else {
1592
+ $dim_string = $dst_w . 'x' . $dst_h;
 
 
1593
  exec( "{$tools['GIFSICLE']} --resize-fit $dim_string -o " . ewww_image_optimizer_escapeshellarg( $outfile ) . ' ' . ewww_image_optimizer_escapeshellarg( $file ) );
1594
  }
1595
  ewwwio_debug_message( "$file resized to $outfile" );
1742
  if ( empty( $s3_uploads_image ) ) {
1743
  $s3_uploads_image = false;
1744
  }
1745
+ if ( ewww_image_optimizer_stream_wrapped( $file ) && class_exists( 'S3_Uploads' ) ) {
1746
  $s3_uploads_image = $file;
1747
  $s3_uploads_instance = S3_Uploads::get_instance();
1748
  $s3_uploads_instance->setup();
1758
  /* translators: %s: Image filename */
1759
  $msg = sprintf( __( 'Could not find %s', 'ewww-image-optimizer' ), $file );
1760
  ewwwio_debug_message( "file doesn't appear to exist: $file" );
1761
+ ewww_image_optimizer_s3_uploads_image_cleanup( $file );
 
 
 
1762
  return array( false, $msg, $converted, $original );
1763
  }
1764
  if ( false === is_writable( $file ) ) {
1765
  /* translators: %s: Image filename */
1766
  $msg = sprintf( __( '%s is not writable', 'ewww-image-optimizer' ), $file );
1767
  ewwwio_debug_message( "couldn't write to the file $file" );
1768
+ ewww_image_optimizer_s3_uploads_image_cleanup( $file );
 
 
 
1769
  return array( false, $msg, $converted, $original );
1770
  }
1771
  $file_perms = 'unknown';
1786
  $type = ewww_image_optimizer_mimetype( $file, 'i' );
1787
  if ( ! $type ) {
1788
  ewwwio_debug_message( 'could not find any functions for mimetype detection' );
1789
+ ewww_image_optimizer_s3_uploads_image_cleanup( $file );
1790
  // Otherwise we store an error message since we couldn't get the mime-type.
 
 
 
 
1791
  return array( false, __( 'Unknown file type', 'ewww-image-optimizer' ), $converted, $original );
1792
  }
1793
  // Not an image or pdf.
1794
  if ( strpos( $type, 'image' ) === false && strpos( $type, 'pdf' ) === false ) {
1795
  ewwwio_debug_message( "unsupported mimetype: $type" );
1796
+ ewww_image_optimizer_s3_uploads_image_cleanup( $file );
 
 
 
1797
  return array( false, __( 'Unsupported file type', 'ewww-image-optimizer' ) . ": $type", $converted, $original );
1798
  }
1799
  if ( ! is_object( $ewww_image ) || ! $ewww_image instanceof EWWW_Image || $ewww_image->file != $file ) {
1856
  ewwwio_debug_message( "original filesize: $orig_size" );
1857
  if ( $orig_size < ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_size' ) ) {
1858
  ewwwio_debug_message( "optimization bypassed due to filesize: $file" );
1859
+ ewww_image_optimizer_s3_uploads_image_cleanup( $file );
1860
  // Tell the user optimization was skipped.
 
 
 
 
1861
  return array( false, __( 'Optimization skipped', 'ewww-image-optimizer' ), $converted, $file );
1862
  }
1863
  if ( 'image/png' == $type && ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_png_size' ) && $orig_size > ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_png_size' ) ) {
1864
  ewwwio_debug_message( "optimization bypassed due to filesize: $file" );
1865
+ ewww_image_optimizer_s3_uploads_image_cleanup( $file );
1866
  // Tell the user optimization was skipped.
 
 
 
 
1867
  return array( false, __( 'Optimization skipped', 'ewww-image-optimizer' ), $converted, $file );
1868
  }
1869
  $backup_hash = '';
1899
  if ( empty( $_REQUEST['ewww_force'] ) && ! ( $new && $convert ) ) {
1900
  $results_msg = ewww_image_optimizer_check_table( $file, $orig_size );
1901
  if ( $results_msg ) {
1902
+ $file = ewww_image_optimizer_s3_uploads_image_cleanup( $file );
 
 
 
 
1903
  return array( $file, $results_msg, $converted, $original );
1904
  }
1905
  }
2152
  if ( empty( $_REQUEST['ewww_force'] ) && ! ( $new && $convert ) ) {
2153
  $results_msg = ewww_image_optimizer_check_table( $file, $orig_size );
2154
  if ( $results_msg ) {
2155
+ $file = ewww_image_optimizer_s3_uploads_image_cleanup( $file );
 
 
 
 
2156
  return array( $file, $results_msg, $converted, $original );
2157
  }
2158
  }
2439
  if ( empty( $_REQUEST['ewww_force'] ) && ! ( $new && $convert ) ) {
2440
  $results_msg = ewww_image_optimizer_check_table( $file, $orig_size );
2441
  if ( $results_msg ) {
2442
+ $file = ewww_image_optimizer_s3_uploads_image_cleanup( $file );
 
 
 
 
2443
  return array( $file, $results_msg, $converted, $original );
2444
  }
2445
  }
2577
  if ( empty( $_REQUEST['ewww_force'] ) ) {
2578
  $results_msg = ewww_image_optimizer_check_table( $file, $orig_size );
2579
  if ( $results_msg ) {
2580
+ $file = ewww_image_optimizer_s3_uploads_image_cleanup( $file );
 
 
 
 
2581
  return array( $file, $results_msg, false, $original );
2582
  }
2583
  }
2588
  break;
2589
  default:
2590
  // If not a JPG, PNG, or GIF, tell the user we don't work with strangers.
2591
+ ewww_image_optimizer_s3_uploads_image_cleanup( $file );
 
 
 
2592
  return array( false, __( 'Unsupported file type', 'ewww-image-optimizer' ) . ": $type", $converted, $original );
2593
  } // End switch().
2594
  // Allow other plugins to run operations on the images after optimization.
2596
  do_action( 'ewww_image_optimizer_post_optimization', $file, $type, $fullsize );
2597
  // If their cloud api license limit has been exceeded.
2598
  if ( 'exceeded' == $result ) {
2599
+ ewww_image_optimizer_s3_uploads_image_cleanup( $file );
 
 
 
2600
  return array( false, __( 'License exceeded', 'ewww-image-optimizer' ), $converted, $original );
2601
  }
2602
  if ( ! empty( $new_size ) ) {
2610
  $results_msg = ewww_image_optimizer_update_table( $file, $new_size, $orig_size, $original, $backup_hash );
2611
  if ( $s3_uploads_image && strpos( $file, 's3-uploads' ) === false ) {
2612
  copy( $file, $s3_uploads_image );
 
 
 
2613
  }
2614
+ $file = ewww_image_optimizer_s3_uploads_image_cleanup( $file );
2615
  ewwwio_memory( __FUNCTION__ );
2616
  return array( $file, $results_msg, $converted, $original );
2617
+ } else {
2618
+ ewww_image_optimizer_s3_uploads_image_cleanup( $file );
 
2619
  }
2620
  ewwwio_memory( __FUNCTION__ );
2621
  // Otherwise, send back the filename, the results (some sort of error message), the $converted flag, and the name of the original image.