EWWW Image Optimizer - Version 6.8.0

Version Description

  • added: ability to store image backups on local storage
  • added: tool to bulk restore images under Tools menu and WP-CLI
  • added: WebP cleanup tool can be resumed and run via WP-CLI
  • added: Delete Originals can be run via WP-CLI
  • added: remove originals after conversion (like PNG to JPG) via WP-CLI
  • added: exclude by page for Easy IO, Lazy Load, and WebP delivery methods
  • changed: ensure full-size image is optimized after resizing with Imsanity
  • fixed: incorrect cfasync attribute used for JS WebP scripts
Download this release

Release Info

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

Code changes from version 6.7.0 to 6.8.0

aux-optimize.php CHANGED
@@ -93,6 +93,7 @@ function ewww_image_optimizer_aux_images_table() {
93
  ewwwio_ob_clean();
94
  die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) );
95
  }
 
96
  global $wpdb;
97
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
98
  ewww_image_optimizer_db_init();
@@ -107,7 +108,7 @@ function ewww_image_optimizer_aux_images_table() {
107
  $total = empty( $_POST['ewww_total_pages'] ) ? 0 : (int) $_POST['ewww_total_pages'];
108
  $output = array();
109
  if ( ! empty( $search ) ) {
110
- ewwwio_debug_message( $ewwwdb->prepare( "SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,updates,trace,UNIX_TIMESTAMP(updated) AS updated FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d AND path LIKE %s ORDER BY " . ( $debug_query ? 'updates DESC,id' : 'id' ) . ' DESC LIMIT %d,%d', $debug_query, '%' . $ewwwdb->esc_like( $search ) . '%', $offset, $per_page ) );
111
  ewwwio_debug_message( $ewwwdb->prepare( "SELECT COUNT(*) FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d AND path LIKE %s", $debug_query, '%' . $ewwwdb->esc_like( $search ) . '%' ) );
112
  $already_optimized = $ewwwdb->get_results( $ewwwdb->prepare( "SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,updates,trace,UNIX_TIMESTAMP(updated) AS updated FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d AND path LIKE %s ORDER BY " . ( $debug_query ? 'updates DESC,id' : 'id' ) . ' DESC LIMIT %d,%d', $debug_query, '%' . $ewwwdb->esc_like( $search ) . '%', $offset, $per_page ), ARRAY_A );
113
  $search_count = $ewwwdb->get_var( $ewwwdb->prepare( "SELECT COUNT(*) FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d AND path LIKE %s", $debug_query, '%' . $ewwwdb->esc_like( $search ) . '%' ) );
@@ -120,7 +121,7 @@ function ewww_image_optimizer_aux_images_table() {
120
  }
121
  $total = ceil( $search_count / $per_page );
122
  } else {
123
- ewwwio_debug_message( $ewwwdb->prepare( "SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,updates,trace,UNIX_TIMESTAMP(updated) AS updated FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d ORDER BY " . ( $debug_query ? 'updates DESC,id' : 'id' ) . ' DESC LIMIT %d,%d', $debug_query, $offset, $per_page ) );
124
  $already_optimized = $ewwwdb->get_results( $ewwwdb->prepare( "SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,updates,trace,UNIX_TIMESTAMP(updated) AS updated FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d ORDER BY " . ( $debug_query ? 'updates DESC,id' : 'id' ) . ' DESC LIMIT %d,%d', $debug_query, $offset, $per_page ), ARRAY_A );
125
  if ( $debug_query ) {
126
  ewwwio_debug_message( $ewwwdb->prepare( "SELECT COUNT(*) FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d", $debug_query ) );
@@ -170,9 +171,6 @@ function ewww_image_optimizer_aux_images_table() {
170
  }
171
  $image_name = esc_html( $image_name );
172
  $savings = esc_html( ewww_image_optimizer_image_results( $optimized_image['orig_size'], $optimized_image['image_size'] ) );
173
- if ( DAY_IN_SECONDS * 30 + $optimized_image['updated'] < time() ) {
174
- $optimized_image['backup'] = '';
175
- }
176
  if ( 946684800 > $optimized_image['updated'] ) {
177
  $last_updated = '';
178
  } else {
@@ -212,7 +210,7 @@ function ewww_image_optimizer_aux_images_table() {
212
  $output['table'] .= "<td>$last_updated</td>";
213
  $output['table'] .= "<td>$savings<br>$size_string<br>" .
214
  '<a class="ewww-remove-image" data-id="' . (int) $optimized_image['id'] . '">' . esc_html__( 'Remove from history', 'ewww-image-optimizer' ) . '</a>' .
215
- ( $optimized_image['backup'] ? '<br><a class="ewww-restore-image" data-id="' . (int) $optimized_image['id'] . '">' . esc_html__( 'Restore original', 'ewww-image-optimizer' ) . '</a>' : '' ) .
216
  '</td>';
217
  $output['table'] .= '</tr>';
218
  $alternate = ! $alternate;
@@ -265,7 +263,7 @@ function ewww_image_optimizer_aux_images_table() {
265
  $output['table'] .= "<td>$savings<br>$size_string<br>" .
266
  '<a class="ewww-remove-image" data-id="' . (int) $optimized_image['id'] . '">' . esc_html__( 'Remove from history', 'ewww-image-optimizer' ) . '</a>' .
267
  $webp_info .
268
- ( $optimized_image['backup'] ? '<br><a class="ewww-restore-image" data-id="' . (int) $optimized_image['id'] . '">' . esc_html__( 'Restore original', 'ewww-image-optimizer' ) . '</a>' : '' ) .
269
  '</td>';
270
  $output['table'] .= '</tr>';
271
  $alternate = ! $alternate;
@@ -316,7 +314,7 @@ function ewww_image_optimizer_aux_images_table() {
316
  /**
317
  * Removes an image from the auxiliary images table.
318
  *
319
- * Called via AJAX, this function will remove the record in provided by the
320
  * POST variable 'ewww_image_id' and return a '1' if successful.
321
  *
322
  * @global object $wpdb
@@ -370,6 +368,93 @@ function ewww_image_optimizer_aux_images_clear_all() {
370
  die();
371
  }
372
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  /**
374
  * Find the number of converted images in the ewwwio_images table.
375
  *
@@ -452,7 +537,7 @@ function ewww_image_optimizer_aux_images_converted_clean() {
452
  *
453
  * @global object $wpdb
454
  */
455
- function ewww_image_optimizer_aux_images_webp_clean() {
456
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
457
  // Verify that an authorized user has called function.
458
  $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' );
@@ -469,12 +554,14 @@ function ewww_image_optimizer_aux_images_webp_clean() {
469
  }
470
  $completed = 0;
471
  $per_page = 50;
472
- $offset = empty( $_POST['ewww_offset'] ) ? 0 : (int) $_POST['ewww_offset'];
 
473
 
474
- ewwwio_debug_message( "searching for $per_page records starting at $offset" );
475
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT path,converted,id FROM $wpdb->ewwwio_images WHERE pending = 0 AND image_size > 0 AND updates > 0 ORDER BY id DESC LIMIT %d,%d", $offset, $per_page ), ARRAY_A );
476
 
477
  if ( empty( $optimized_images ) || ! is_countable( $optimized_images ) || 0 === count( $optimized_images ) ) {
 
478
  die( wp_json_encode( array( 'finished' => 1 ) ) );
479
  }
480
 
@@ -483,41 +570,75 @@ function ewww_image_optimizer_aux_images_webp_clean() {
483
 
484
  foreach ( $optimized_images as $optimized_image ) {
485
  $completed++;
486
- $file = ewww_image_optimizer_absolutize_path( $optimized_image['path'] );
487
- ewwwio_debug_message( "looking for $file.webp" );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
  if ( ! ewww_image_optimizer_stream_wrapped( $file ) && ewwwio_is_file( $file ) && ewwwio_is_file( $file . '.webp' ) ) {
489
  ewwwio_debug_message( "removing: $file.webp" );
490
  if ( ewwwio_delete_file( $file . '.webp' ) ) {
491
  ewwwio_debug_message( "removed $file.webp" );
492
  } else {
493
- /* translators: %s: file name */
494
- die( wp_json_encode( array( 'error' => sprintf( esc_html__( 'Could not delete %s, please remove manually or fix permissions and try again.', 'ewww-image-optimizer' ), esc_html( $file . '.webp' ) ) ) ) );
495
- }
496
- }
497
- if ( ! empty( $optimized_image['converted'] ) ) {
498
- $file = ewww_image_optimizer_absolutize_path( $optimized_image['converted'] );
499
- ewwwio_debug_message( "$file was converted, checking if webp version exists" );
500
- if ( ! ewww_image_optimizer_stream_wrapped( $file ) && ewwwio_is_file( $file ) && ewwwio_is_file( $file . '.webp' ) ) {
501
- ewwwio_debug_message( "removing: $file.webp" );
502
- if ( ewwwio_delete_file( $file . '.webp' ) ) {
503
- ewwwio_debug_message( "removed $file.webp" );
504
- } else {
505
  /* translators: %s: file name */
506
  die( wp_json_encode( array( 'error' => sprintf( esc_html__( 'Could not delete %s, please remove manually or fix permissions and try again.', 'ewww-image-optimizer' ), esc_html( $file . '.webp' ) ) ) ) );
 
 
 
 
 
 
 
 
507
  }
508
  }
509
  }
510
- } // End foreach().
511
- die( wp_json_encode( array( 'completed' => $completed ) ) );
512
  }
513
 
514
  /**
515
- * Cleans up WebP images via AJAX for a particular attachment.
516
  *
517
  * @global object $wpdb
518
  * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity.
519
  */
520
- function ewww_image_optimizer_delete_webp() {
521
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
522
  // Verify that an authorized user has called function.
523
  $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' );
@@ -532,14 +653,52 @@ function ewww_image_optimizer_delete_webp() {
532
  } else {
533
  $ewwwdb = $wpdb;
534
  }
535
- if ( empty( $_POST['attachment_id'] ) ) {
536
- die;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  }
538
 
539
  // Because some plugins might have loose filters (looking at you WPML).
540
  remove_all_filters( 'wp_delete_file' );
541
 
542
- $id = (int) $_POST['attachment_id'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
543
  // Finds non-meta images to remove from disk, and from db, as well as converted originals.
544
  $optimized_images = $ewwwdb->get_results( "SELECT path,converted FROM $ewwwdb->ewwwio_images WHERE attachment_id = $id AND gallery = 'media'", ARRAY_A );
545
  if ( $optimized_images ) {
@@ -549,6 +708,7 @@ function ewww_image_optimizer_delete_webp() {
549
  $image['path'] = ewww_image_optimizer_absolutize_path( $image['path'] );
550
  }
551
  if ( ! empty( $image['path'] ) ) {
 
552
  if ( ewwwio_is_file( $image['path'] ) && ewwwio_is_file( $image['path'] . '.webp' ) ) {
553
  ewwwio_debug_message( 'removing: ' . $image['path'] . '.webp' );
554
  ewwwio_delete_file( $image['path'] . '.webp' );
@@ -657,6 +817,7 @@ function ewww_image_optimizer_delete_webp() {
657
  }
658
  }
659
  }
 
660
  if ( ewwwio_is_file( $file_path ) && ewwwio_is_file( $file_path . '.webp' ) ) {
661
  ewwwio_debug_message( 'removing: ' . $file_path . '.webp' );
662
  ewwwio_delete_file( $image['path'] . '.webp' );
@@ -670,7 +831,6 @@ function ewww_image_optimizer_delete_webp() {
670
  ewwwio_debug_message( 'removing: ' . $webpfileold );
671
  ewwwio_delete_file( $webpfileold );
672
  }
673
- die( wp_json_encode( array( 'completed' => 1 ) ) );
674
  }
675
 
676
  /**
@@ -981,6 +1141,33 @@ function ewww_image_optimizer_get_all_attachments() {
981
  die( wp_json_encode( $attachments ) );
982
  }
983
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
984
  /**
985
  * Retrieve an image ID from the ewwwio_queue table.
986
  *
@@ -1114,9 +1301,6 @@ function ewww_image_optimizer_image_scan( $dir, $started = 0 ) {
1114
  ewwwio_debug_message( "$dir already completed" );
1115
  return;
1116
  }
1117
- if ( ! class_exists( 'WP_Background_Process' ) ) {
1118
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
1119
- }
1120
  global $wpdb;
1121
  global $optimized_list;
1122
  global $ewww_scan;
@@ -1596,11 +1780,16 @@ add_action( 'wp_ajax_bulk_aux_images_table', 'ewww_image_optimizer_aux_images_ta
1596
  add_action( 'wp_ajax_bulk_aux_images_table_count', 'ewww_image_optimizer_aux_images_table_count' );
1597
  add_action( 'wp_ajax_bulk_aux_images_table_clear', 'ewww_image_optimizer_aux_images_clear_all' );
1598
  add_action( 'wp_ajax_bulk_aux_images_remove', 'ewww_image_optimizer_aux_images_remove' );
 
1599
  add_action( 'wp_ajax_bulk_aux_images_count_converted', 'ewww_image_optimizer_aux_images_count_converted' );
1600
  add_action( 'wp_ajax_bulk_aux_images_converted_clean', 'ewww_image_optimizer_aux_images_converted_clean' );
1601
  add_action( 'wp_ajax_bulk_aux_images_table_clean', 'ewww_image_optimizer_aux_images_clean' );
1602
  add_action( 'wp_ajax_bulk_aux_images_meta_clean', 'ewww_image_optimizer_aux_meta_clean' );
1603
- add_action( 'wp_ajax_bulk_aux_images_webp_clean', 'ewww_image_optimizer_aux_images_webp_clean' );
1604
- add_action( 'wp_ajax_bulk_aux_images_delete_webp', 'ewww_image_optimizer_delete_webp' );
1605
  add_action( 'wp_ajax_bulk_aux_images_delete_original', 'ewww_image_optimizer_ajax_delete_original' );
1606
  add_action( 'wp_ajax_ewwwio_get_all_attachments', 'ewww_image_optimizer_get_all_attachments' );
 
 
 
 
93
  ewwwio_ob_clean();
94
  die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) );
95
  }
96
+ global $eio_backup;
97
  global $wpdb;
98
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
99
  ewww_image_optimizer_db_init();
108
  $total = empty( $_POST['ewww_total_pages'] ) ? 0 : (int) $_POST['ewww_total_pages'];
109
  $output = array();
110
  if ( ! empty( $search ) ) {
111
+ ewwwio_debug_message( $ewwwdb->prepare( "SELECT id,path,orig_size,image_size,backup,attachment_id,gallery,updates,trace,UNIX_TIMESTAMP(updated) AS updated FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d AND path LIKE %s ORDER BY " . ( $debug_query ? 'updates DESC,id' : 'id' ) . ' DESC LIMIT %d,%d', $debug_query, '%' . $ewwwdb->esc_like( $search ) . '%', $offset, $per_page ) );
112
  ewwwio_debug_message( $ewwwdb->prepare( "SELECT COUNT(*) FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d AND path LIKE %s", $debug_query, '%' . $ewwwdb->esc_like( $search ) . '%' ) );
113
  $already_optimized = $ewwwdb->get_results( $ewwwdb->prepare( "SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,updates,trace,UNIX_TIMESTAMP(updated) AS updated FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d AND path LIKE %s ORDER BY " . ( $debug_query ? 'updates DESC,id' : 'id' ) . ' DESC LIMIT %d,%d', $debug_query, '%' . $ewwwdb->esc_like( $search ) . '%', $offset, $per_page ), ARRAY_A );
114
  $search_count = $ewwwdb->get_var( $ewwwdb->prepare( "SELECT COUNT(*) FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d AND path LIKE %s", $debug_query, '%' . $ewwwdb->esc_like( $search ) . '%' ) );
121
  }
122
  $total = ceil( $search_count / $per_page );
123
  } else {
124
+ ewwwio_debug_message( $ewwwdb->prepare( "SELECT id,path,orig_size,image_size,backup,attachment_id,gallery,updates,trace,UNIX_TIMESTAMP(updated) AS updated FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d ORDER BY " . ( $debug_query ? 'updates DESC,id' : 'id' ) . ' DESC LIMIT %d,%d', $debug_query, $offset, $per_page ) );
125
  $already_optimized = $ewwwdb->get_results( $ewwwdb->prepare( "SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,updates,trace,UNIX_TIMESTAMP(updated) AS updated FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d ORDER BY " . ( $debug_query ? 'updates DESC,id' : 'id' ) . ' DESC LIMIT %d,%d', $debug_query, $offset, $per_page ), ARRAY_A );
126
  if ( $debug_query ) {
127
  ewwwio_debug_message( $ewwwdb->prepare( "SELECT COUNT(*) FROM $ewwwdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > %d", $debug_query ) );
171
  }
172
  $image_name = esc_html( $image_name );
173
  $savings = esc_html( ewww_image_optimizer_image_results( $optimized_image['orig_size'], $optimized_image['image_size'] ) );
 
 
 
174
  if ( 946684800 > $optimized_image['updated'] ) {
175
  $last_updated = '';
176
  } else {
210
  $output['table'] .= "<td>$last_updated</td>";
211
  $output['table'] .= "<td>$savings<br>$size_string<br>" .
212
  '<a class="ewww-remove-image" data-id="' . (int) $optimized_image['id'] . '">' . esc_html__( 'Remove from history', 'ewww-image-optimizer' ) . '</a>' .
213
+ ( $eio_backup->is_backup_available( $optimized_image['path'], $optimized_image ) ? '<br><a class="ewww-restore-image" data-id="' . (int) $optimized_image['id'] . '">' . esc_html__( 'Restore original', 'ewww-image-optimizer' ) . '</a>' : '' ) .
214
  '</td>';
215
  $output['table'] .= '</tr>';
216
  $alternate = ! $alternate;
263
  $output['table'] .= "<td>$savings<br>$size_string<br>" .
264
  '<a class="ewww-remove-image" data-id="' . (int) $optimized_image['id'] . '">' . esc_html__( 'Remove from history', 'ewww-image-optimizer' ) . '</a>' .
265
  $webp_info .
266
+ ( $eio_backup->is_backup_available( $optimized_image['path'], $optimized_image ) ? '<br><a class="ewww-restore-image" data-id="' . (int) $optimized_image['id'] . '">' . esc_html__( 'Restore original', 'ewww-image-optimizer' ) . '</a>' : '' ) .
267
  '</td>';
268
  $output['table'] .= '</tr>';
269
  $alternate = ! $alternate;
314
  /**
315
  * Removes an image from the auxiliary images table.
316
  *
317
+ * Called via AJAX, this function will remove the record provided by the
318
  * POST variable 'ewww_image_id' and return a '1' if successful.
319
  *
320
  * @global object $wpdb
368
  die();
369
  }
370
 
371
+ /**
372
+ * Reset the progress/position of the WebP cleanup routine.
373
+ */
374
+ function ewww_image_optimizer_reset_webp_clean() {
375
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
376
+ $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' );
377
+ if ( ! current_user_can( $permissions ) ) {
378
+ wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) );
379
+ }
380
+ delete_option( 'ewww_image_optimizer_webp_clean_position' );
381
+ wp_safe_redirect( wp_get_referer() );
382
+ exit;
383
+ }
384
+
385
+ /**
386
+ * Restore backups for images using records from the ewwwio_images table.
387
+ *
388
+ * @global object $wpdb
389
+ * @global object $eio_backup
390
+ */
391
+ function ewww_image_optimizer_bulk_restore_handler() {
392
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
393
+
394
+ session_write_close();
395
+ $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' );
396
+ if ( ! current_user_can( $permissions ) ) {
397
+ ewwwio_ob_clean();
398
+ wp_die( wp_json_encode( array( 'error' => esc_html__( 'You do not have permission to optimize images.', 'ewww-image-optimizer' ) ) ) );
399
+ }
400
+ if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) ) {
401
+ ewwwio_ob_clean();
402
+ wp_die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) );
403
+ }
404
+
405
+ global $eio_backup;
406
+ global $wpdb;
407
+ if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
408
+ ewww_image_optimizer_db_init();
409
+ global $ewwwdb;
410
+ } else {
411
+ $ewwwdb = $wpdb;
412
+ }
413
+
414
+ $completed = 0;
415
+ $position = (int) get_option( 'ewww_image_optimizer_bulk_restore_position' );
416
+ $per_page = (int) apply_filters( 'ewww_image_optimizer_bulk_restore_batch_size', 20 );
417
+ $started = time();
418
+
419
+ ewwwio_debug_message( "searching for $per_page records starting at $position" );
420
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE id > %d AND pending = 0 AND image_size > 0 AND updates > 0 ORDER BY id LIMIT %d", $position, $per_page ), ARRAY_A );
421
+
422
+ if ( empty( $optimized_images ) || ! is_countable( $optimized_images ) || 0 === count( $optimized_images ) ) {
423
+ ewwwio_debug_message( 'no more images, all done!' );
424
+ delete_option( 'ewww_image_optimizer_bulk_restore_position' );
425
+ ewwwio_ob_clean();
426
+ wp_die( wp_json_encode( array( 'finished' => 1 ) ) );
427
+ }
428
+
429
+ // Because some plugins might have loose filters (looking at you WPML).
430
+ remove_all_filters( 'wp_delete_file' );
431
+
432
+ $messages = '';
433
+ foreach ( $optimized_images as $optimized_image ) {
434
+ $completed++;
435
+ ewwwio_debug_message( "submitting {$optimized_image['id']} to be restored" );
436
+ $eio_backup->restore_file( $optimized_image );
437
+ $error_message = $eio_backup->get_error();
438
+ if ( $error_message ) {
439
+ $messages .= esc_html( $error_message ) . '<br>';
440
+ }
441
+ update_option( 'ewww_image_optimizer_bulk_restore_position', $optimized_image['id'], false );
442
+ if ( time() > $started + 20 ) {
443
+ break;
444
+ }
445
+ } // End foreach().
446
+
447
+ ewwwio_ob_clean();
448
+ wp_die(
449
+ wp_json_encode(
450
+ array(
451
+ 'completed' => $completed,
452
+ 'messages' => $messages,
453
+ )
454
+ )
455
+ );
456
+ }
457
+
458
  /**
459
  * Find the number of converted images in the ewwwio_images table.
460
  *
537
  *
538
  * @global object $wpdb
539
  */
540
+ function ewww_image_optimizer_aux_images_webp_clean_handler() {
541
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
542
  // Verify that an authorized user has called function.
543
  $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' );
554
  }
555
  $completed = 0;
556
  $per_page = 50;
557
+ $resume = get_option( 'ewww_image_optimizer_webp_clean_position' );
558
+ $position = is_array( $resume ) && ! empty( $resume['stage2'] ) ? (int) $resume['stage2'] : 0;
559
 
560
+ ewwwio_debug_message( "searching for $per_page records starting at $position" );
561
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE id > %d AND pending = 0 AND image_size > 0 AND updates > 0 ORDER BY id LIMIT %d", $position, $per_page ), ARRAY_A );
562
 
563
  if ( empty( $optimized_images ) || ! is_countable( $optimized_images ) || 0 === count( $optimized_images ) ) {
564
+ delete_option( 'ewww_image_optimizer_webp_clean_position' );
565
  die( wp_json_encode( array( 'finished' => 1 ) ) );
566
  }
567
 
570
 
571
  foreach ( $optimized_images as $optimized_image ) {
572
  $completed++;
573
+ ewww_image_optimizer_aux_images_webp_clean( $optimized_image );
574
+ }
575
+
576
+ $resume['stage2'] = $optimized_image['id'];
577
+ update_option( 'ewww_image_optimizer_webp_clean_position', $resume, false );
578
+
579
+ die( wp_json_encode( array( 'completed' => $completed ) ) );
580
+ }
581
+
582
+ /**
583
+ * Remove WebP images via db record.
584
+ *
585
+ * @param array $optimized_image The database record for an image from the optimization history.
586
+ */
587
+ function ewww_image_optimizer_aux_images_webp_clean( $optimized_image ) {
588
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
589
+ $file = ewww_image_optimizer_absolutize_path( $optimized_image['path'] );
590
+ ewwwio_debug_message( "looking for $file.webp" );
591
+ if ( ! ewww_image_optimizer_stream_wrapped( $file ) && ewwwio_is_file( $file ) && ewwwio_is_file( $file . '.webp' ) ) {
592
+ ewwwio_debug_message( "removing: $file.webp" );
593
+ if ( ewwwio_delete_file( $file . '.webp' ) ) {
594
+ ewwwio_debug_message( "removed $file.webp" );
595
+ } else {
596
+ if ( wp_doing_ajax() ) {
597
+ /* translators: %s: file name */
598
+ die( wp_json_encode( array( 'error' => sprintf( esc_html__( 'Could not delete %s, please remove manually or fix permissions and try again.', 'ewww-image-optimizer' ), esc_html( $file . '.webp' ) ) ) ) );
599
+ } elseif ( defined( 'WP_CLI' ) && WP_CLI ) {
600
+ WP_CLI::error(
601
+ sprintf(
602
+ /* translators: %s: file name */
603
+ esc_html__( 'Could not delete %s, please remove manually or fix permissions and try again.', 'ewww-image-optimizer' ),
604
+ esc_html( $file . '.webp' )
605
+ )
606
+ );
607
+ }
608
+ }
609
+ }
610
+ if ( ! empty( $optimized_image['converted'] ) ) {
611
+ $file = ewww_image_optimizer_absolutize_path( $optimized_image['converted'] );
612
+ ewwwio_debug_message( "$file was converted, checking if webp version exists" );
613
  if ( ! ewww_image_optimizer_stream_wrapped( $file ) && ewwwio_is_file( $file ) && ewwwio_is_file( $file . '.webp' ) ) {
614
  ewwwio_debug_message( "removing: $file.webp" );
615
  if ( ewwwio_delete_file( $file . '.webp' ) ) {
616
  ewwwio_debug_message( "removed $file.webp" );
617
  } else {
618
+ if ( wp_doing_ajax() ) {
 
 
 
 
 
 
 
 
 
 
 
619
  /* translators: %s: file name */
620
  die( wp_json_encode( array( 'error' => sprintf( esc_html__( 'Could not delete %s, please remove manually or fix permissions and try again.', 'ewww-image-optimizer' ), esc_html( $file . '.webp' ) ) ) ) );
621
+ } elseif ( defined( 'WP_CLI' ) && WP_CLI ) {
622
+ WP_CLI::error(
623
+ sprintf(
624
+ /* translators: %s: file name */
625
+ esc_html__( 'Could not delete %s, please remove manually or fix permissions and try again.', 'ewww-image-optimizer' ),
626
+ esc_html( $file . '.webp' )
627
+ )
628
+ );
629
  }
630
  }
631
  }
632
+ }
 
633
  }
634
 
635
  /**
636
+ * Cleanup WebP images via AJAX for a particular attachment.
637
  *
638
  * @global object $wpdb
639
  * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity.
640
  */
641
+ function ewww_image_optimizer_delete_webp_handler() {
642
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
643
  // Verify that an authorized user has called function.
644
  $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' );
653
  } else {
654
  $ewwwdb = $wpdb;
655
  }
656
+ // if ( empty( $_POST['attachment_id'] ) ) {
657
+ // die;
658
+ // }.
659
+ $resume = get_option( 'ewww_image_optimizer_webp_clean_position' );
660
+ $position = is_array( $resume ) && ! empty( $resume['stage1'] ) ? (int) $resume['stage1'] : 0;
661
+
662
+ $id = (int) $wpdb->get_var(
663
+ $wpdb->prepare(
664
+ "SELECT ID FROM $wpdb->posts WHERE ID > %d AND (post_type = 'attachment' OR post_type = 'ims_image') AND (post_mime_type LIKE %s OR post_mime_type LIKE %s) ORDER BY ID LIMIT 1",
665
+ (int) $position,
666
+ '%image%',
667
+ '%pdf%'
668
+ )
669
+ );
670
+ if ( ! $id ) {
671
+ die( wp_json_encode( array( 'finished' => 1 ) ) );
672
  }
673
 
674
  // Because some plugins might have loose filters (looking at you WPML).
675
  remove_all_filters( 'wp_delete_file' );
676
 
677
+ ewww_image_optimizer_delete_webp( $id );
678
+ $resume['stage1'] = (int) $id;
679
+ update_option( 'ewww_image_optimizer_webp_clean_position', $resume, false );
680
+
681
+ die( wp_json_encode( array( 'completed' => 1 ) ) );
682
+ }
683
+
684
+ /**
685
+ * Cleanup WebP images for a particular attachment.
686
+ *
687
+ * @global object $wpdb
688
+ * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity.
689
+ *
690
+ * @param int $id Attachment ID number for an image.
691
+ */
692
+ function ewww_image_optimizer_delete_webp( $id ) {
693
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
694
+ global $wpdb;
695
+ if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
696
+ ewww_image_optimizer_db_init();
697
+ global $ewwwdb;
698
+ } else {
699
+ $ewwwdb = $wpdb;
700
+ }
701
+
702
  // Finds non-meta images to remove from disk, and from db, as well as converted originals.
703
  $optimized_images = $ewwwdb->get_results( "SELECT path,converted FROM $ewwwdb->ewwwio_images WHERE attachment_id = $id AND gallery = 'media'", ARRAY_A );
704
  if ( $optimized_images ) {
708
  $image['path'] = ewww_image_optimizer_absolutize_path( $image['path'] );
709
  }
710
  if ( ! empty( $image['path'] ) ) {
711
+ ewwwio_debug_message( 'looking for: ' . $image['path'] . '.webp' );
712
  if ( ewwwio_is_file( $image['path'] ) && ewwwio_is_file( $image['path'] . '.webp' ) ) {
713
  ewwwio_debug_message( 'removing: ' . $image['path'] . '.webp' );
714
  ewwwio_delete_file( $image['path'] . '.webp' );
817
  }
818
  }
819
  }
820
+ ewwwio_debug_message( "looking for: $file_path.webp" );
821
  if ( ewwwio_is_file( $file_path ) && ewwwio_is_file( $file_path . '.webp' ) ) {
822
  ewwwio_debug_message( 'removing: ' . $file_path . '.webp' );
823
  ewwwio_delete_file( $image['path'] . '.webp' );
831
  ewwwio_debug_message( 'removing: ' . $webpfileold );
832
  ewwwio_delete_file( $webpfileold );
833
  }
 
834
  }
835
 
836
  /**
1141
  die( wp_json_encode( $attachments ) );
1142
  }
1143
 
1144
+ /**
1145
+ * Count all the image (and PDF) attachments that are remaining for WebP cleanup.
1146
+ *
1147
+ * @global object $wpdb
1148
+ */
1149
+ function ewww_image_optimizer_webp_attachment_count() {
1150
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
1151
+ $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' );
1152
+ if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) {
1153
+ ewwwio_ob_clean();
1154
+ die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) );
1155
+ }
1156
+ $resume = get_option( 'ewww_image_optimizer_webp_clean_position' );
1157
+ $start_id = is_array( $resume ) && ! empty( $resume['stage1'] ) ? (int) $resume['stage1'] : 0;
1158
+
1159
+ global $wpdb;
1160
+ $total_attachments = (int) $wpdb->get_var(
1161
+ $wpdb->prepare(
1162
+ "SELECT count(ID) FROM $wpdb->posts WHERE ID > %d AND (post_type = 'attachment' OR post_type = 'ims_image') AND (post_mime_type LIKE %s OR post_mime_type LIKE %s)",
1163
+ (int) $start_id,
1164
+ '%image%',
1165
+ '%pdf%'
1166
+ )
1167
+ );
1168
+ die( wp_json_encode( array( 'total' => (int) $total_attachments ) ) );
1169
+ }
1170
+
1171
  /**
1172
  * Retrieve an image ID from the ewwwio_queue table.
1173
  *
1301
  ewwwio_debug_message( "$dir already completed" );
1302
  return;
1303
  }
 
 
 
1304
  global $wpdb;
1305
  global $optimized_list;
1306
  global $ewww_scan;
1780
  add_action( 'wp_ajax_bulk_aux_images_table_count', 'ewww_image_optimizer_aux_images_table_count' );
1781
  add_action( 'wp_ajax_bulk_aux_images_table_clear', 'ewww_image_optimizer_aux_images_clear_all' );
1782
  add_action( 'wp_ajax_bulk_aux_images_remove', 'ewww_image_optimizer_aux_images_remove' );
1783
+ add_action( 'wp_ajax_bulk_aux_images_restore_original', 'ewww_image_optimizer_bulk_restore_handler' );
1784
  add_action( 'wp_ajax_bulk_aux_images_count_converted', 'ewww_image_optimizer_aux_images_count_converted' );
1785
  add_action( 'wp_ajax_bulk_aux_images_converted_clean', 'ewww_image_optimizer_aux_images_converted_clean' );
1786
  add_action( 'wp_ajax_bulk_aux_images_table_clean', 'ewww_image_optimizer_aux_images_clean' );
1787
  add_action( 'wp_ajax_bulk_aux_images_meta_clean', 'ewww_image_optimizer_aux_meta_clean' );
1788
+ add_action( 'wp_ajax_bulk_aux_images_webp_clean', 'ewww_image_optimizer_aux_images_webp_clean_handler' );
1789
+ add_action( 'wp_ajax_bulk_aux_images_delete_webp', 'ewww_image_optimizer_delete_webp_handler' );
1790
  add_action( 'wp_ajax_bulk_aux_images_delete_original', 'ewww_image_optimizer_ajax_delete_original' );
1791
  add_action( 'wp_ajax_ewwwio_get_all_attachments', 'ewww_image_optimizer_get_all_attachments' );
1792
+ add_action( 'wp_ajax_ewwwio_webp_attachment_count', 'ewww_image_optimizer_webp_attachment_count' );
1793
+ // Non-AJAX handler(s) to reset tool resume option/placeholder.
1794
+ add_action( 'admin_action_ewww_image_optimizer_reset_bulk_restore', 'ewww_image_optimizer_reset_bulk_restore' );
1795
+ add_action( 'admin_action_ewww_image_optimizer_reset_webp_clean', 'ewww_image_optimizer_reset_webp_clean' );
bulk.php CHANGED
@@ -18,9 +18,6 @@ function ewww_image_optimizer_display_tools() {
18
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
19
  global $ewwwio_media_background;
20
  global $ewwwio_image_background;
21
- if ( ! class_exists( 'WP_Background_Process' ) ) {
22
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
23
- }
24
  if (
25
  ! empty( $_POST['ewww_nonce'] ) &&
26
  wp_verify_nonce( sanitize_key( $_POST['ewww_nonce'] ), 'ewww_image_optimizer_clear_queue' ) &&
@@ -82,6 +79,7 @@ function ewww_image_optimizer_display_tools() {
82
  } else {
83
  echo esc_html__( 'There are no images in the queue currently.', 'ewww-image-optimizer' ) . "</p>\n";
84
  }
 
85
  echo '<hr class="ewww-tool-divider">';
86
  echo "<div>\n<p id='ewww-clear-table-info' class='ewww-tool-info'>" .
87
  esc_html__( 'The optimization history prevents the plugin from re-optimizing images, but you may erase the history to reduce database size or to force the plugin to re-optimize all images.', 'ewww-image-optimizer' );
@@ -90,6 +88,43 @@ function ewww_image_optimizer_display_tools() {
90
  "<input type='submit' class='button-secondary action' value='" . esc_attr__( 'Erase Optimization History', 'ewww-image-optimizer' ) . "' />\n" .
91
  "</form>\n</div>\n";
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  echo '<hr class="ewww-tool-divider">';
94
  echo "<div>\n<p id='ewww-clean-originals-info' class='ewww-tool-info'>" .
95
  esc_html__( 'When WordPress scales down large images, it keeps the original on disk for thumbnail generation. You may delete them to save disk space.', 'ewww-image-optimizer' ) . "</p>\n";
@@ -114,7 +149,18 @@ function ewww_image_optimizer_display_tools() {
114
  esc_html__( 'You may remove all the WebP images from your site if you no longer need them. For example, sites that use Easy IO do not need local WebP images.', 'ewww-image-optimizer' ) . "</p>\n";
115
  echo "<form id='ewww-clean-webp' class='ewww-tool-form' method='post' action=''>\n" .
116
  "<input type='submit' class='button-secondary action' value='" . esc_attr__( 'Remove WebP Images', 'ewww-image-optimizer' ) . "' />\n" .
117
- "</form>\n</div>\n";
 
 
 
 
 
 
 
 
 
 
 
118
  echo "<div id='ewww-clean-webp-progressbar' style='display:none;'></div>";
119
  echo "<div id='ewww-clean-webp-progress' style='display:none;'></div>";
120
 
@@ -204,7 +250,13 @@ function ewww_image_optimizer_tool_script( $hook ) {
204
  $erase_warning = esc_html__( 'Warning: this cannot be undone. Re-optimizing images will use additional API credits.', 'ewww-image-optimizer' );
205
  }
206
  global $wpdb;
207
- $attachment_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%%') ORDER BY ID DESC" );
 
 
 
 
 
 
208
  wp_localize_script(
209
  'ewww-tool-script',
210
  'ewww_vars',
@@ -227,6 +279,9 @@ function ewww_image_optimizer_tool_script( $hook ) {
227
  'batch' => esc_html__( 'batch', 'ewww-image-optimizer' ),
228
  'erase_warning' => $erase_warning,
229
  'tool_warning' => esc_html__( 'Please be sure to backup your site before proceeding. Do you wish to continue?', 'ewww-image-optimizer' ),
 
 
 
230
  )
231
  );
232
  // Load the stylesheet for the jquery progressbar.
@@ -264,7 +319,7 @@ function ewww_image_optimizer_bulk_preview() {
264
  </p>
265
  </div>
266
  <?php
267
- } else {
268
  ?>
269
  <div id="ewww-bulk-warning" class="ewww-bulk-info notice notice-warning">
270
  <p>
18
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
19
  global $ewwwio_media_background;
20
  global $ewwwio_image_background;
 
 
 
21
  if (
22
  ! empty( $_POST['ewww_nonce'] ) &&
23
  wp_verify_nonce( sanitize_key( $_POST['ewww_nonce'] ), 'ewww_image_optimizer_clear_queue' ) &&
79
  } else {
80
  echo esc_html__( 'There are no images in the queue currently.', 'ewww-image-optimizer' ) . "</p>\n";
81
  }
82
+
83
  echo '<hr class="ewww-tool-divider">';
84
  echo "<div>\n<p id='ewww-clear-table-info' class='ewww-tool-info'>" .
85
  esc_html__( 'The optimization history prevents the plugin from re-optimizing images, but you may erase the history to reduce database size or to force the plugin to re-optimize all images.', 'ewww-image-optimizer' );
88
  "<input type='submit' class='button-secondary action' value='" . esc_attr__( 'Erase Optimization History', 'ewww-image-optimizer' ) . "' />\n" .
89
  "</form>\n</div>\n";
90
 
91
+ $backup_mode = '';
92
+ if ( 'local' === ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
93
+ $backup_mode = __( 'local', 'ewww-image-optimizer' );
94
+ } elseif ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
95
+ $backup_mode = __( 'cloud', 'ewww-image-optimizer' );
96
+ }
97
+ echo '<hr class="ewww-tool-divider">';
98
+ echo "<div>\n<p id='ewww-restore-originals-info' class='ewww-tool-info'>";
99
+ if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
100
+ /* translators: %s: 'cloud' or 'local', translated separately */
101
+ printf( esc_html__( 'Restore all your images from %s backups in case of image corruption or degraded quality.', 'ewww-image-optimizer' ), esc_html( $backup_mode ) );
102
+ if ( ! get_option( 'ewww_image_optimizer_bulk_restore_position' ) ) {
103
+ echo '<br>';
104
+ esc_html_e( '*As such things are quite rare, it is highly recommended to contact support first, as this may be due to a plugin conflict.', 'ewww-image-optimizer' );
105
+ }
106
+ } else {
107
+ esc_html_e( 'Backups are currently disabled in the Local settings.', 'ewww-image-optimizer' );
108
+ }
109
+ echo "</p>\n";
110
+ echo "<form id='ewww-restore-originals' class='ewww-tool-form' method='post' action=''>\n" .
111
+ "<input type='submit' class='button-secondary action' value='" . esc_attr__( 'Restore Images', 'ewww-image-optimizer' ) . "' " . disabled( (bool) ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ), false, false ) . " />\n" .
112
+ "</form>\n";
113
+ if ( get_option( 'ewww_image_optimizer_bulk_restore_position' ) ) {
114
+ ?>
115
+ <p class="description ewww-tool-info">
116
+ <i><?php esc_html_e( 'Will resume from previous position.', 'ewww-image-optimizer' ); ?></i> -
117
+ <a href='<?php echo esc_url( admin_url( 'admin.php?action=ewww_image_optimizer_reset_bulk_restore' ) ); ?>'>
118
+ <?php esc_html_e( 'Reset position', 'ewww-image-optimizer' ); ?>
119
+ </a>
120
+ </p>
121
+ <?php
122
+ }
123
+ echo "</div>\n";
124
+ echo "<div id='ewww-restore-originals-progressbar' style='display:none;'></div>";
125
+ echo "<div id='ewww-restore-originals-progress' style='display:none;'></div>";
126
+ echo "<div id='ewww-restore-originals-messages' style='display:none;'></div>";
127
+
128
  echo '<hr class="ewww-tool-divider">';
129
  echo "<div>\n<p id='ewww-clean-originals-info' class='ewww-tool-info'>" .
130
  esc_html__( 'When WordPress scales down large images, it keeps the original on disk for thumbnail generation. You may delete them to save disk space.', 'ewww-image-optimizer' ) . "</p>\n";
149
  esc_html__( 'You may remove all the WebP images from your site if you no longer need them. For example, sites that use Easy IO do not need local WebP images.', 'ewww-image-optimizer' ) . "</p>\n";
150
  echo "<form id='ewww-clean-webp' class='ewww-tool-form' method='post' action=''>\n" .
151
  "<input type='submit' class='button-secondary action' value='" . esc_attr__( 'Remove WebP Images', 'ewww-image-optimizer' ) . "' />\n" .
152
+ "</form>\n";
153
+ if ( get_option( 'ewww_image_optimizer_webp_clean_position' ) ) {
154
+ ?>
155
+ <p class="description ewww-tool-info">
156
+ <i><?php esc_html_e( 'Will resume from previous position.', 'ewww-image-optimizer' ); ?></i> -
157
+ <a href='<?php echo esc_url( admin_url( 'admin.php?action=ewww_image_optimizer_reset_webp_clean' ) ); ?>'>
158
+ <?php esc_html_e( 'Reset position', 'ewww-image-optimizer' ); ?>
159
+ </a>
160
+ </p>
161
+ <?php
162
+ }
163
+ echo "</div>\n";
164
  echo "<div id='ewww-clean-webp-progressbar' style='display:none;'></div>";
165
  echo "<div id='ewww-clean-webp-progress' style='display:none;'></div>";
166
 
250
  $erase_warning = esc_html__( 'Warning: this cannot be undone. Re-optimizing images will use additional API credits.', 'ewww-image-optimizer' );
251
  }
252
  global $wpdb;
253
+ $attachment_count = (int) $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%%') ORDER BY ID DESC" );
254
+ $restore_position = (int) get_option( 'ewww_image_optimizer_bulk_restore_position' );
255
+ $restorable_images = (int) $wpdb->get_var( $wpdb->prepare( "SELECT count(id) FROM $wpdb->ewwwio_images WHERE id > %d AND pending = 0 AND image_size > 0 AND updates > 0", $restore_position ) );
256
+ $webp_clean_resume = get_option( 'ewww_image_optimizer_webp_clean_position' );
257
+ $webp_position = is_array( $webp_clean_resume ) && ! empty( $webp_clean_resume['stage2'] ) ? (int) $webp_clean_resume['stage2'] : 0;
258
+ $webp_cleanable = (int) $wpdb->get_var( $wpdb->prepare( "SELECT count(id) FROM $wpdb->ewwwio_images WHERE id > %d AND pending = 0 AND image_size > 0 AND updates > 0", $webp_position ) );
259
+
260
  wp_localize_script(
261
  'ewww-tool-script',
262
  'ewww_vars',
279
  'batch' => esc_html__( 'batch', 'ewww-image-optimizer' ),
280
  'erase_warning' => $erase_warning,
281
  'tool_warning' => esc_html__( 'Please be sure to backup your site before proceeding. Do you wish to continue?', 'ewww-image-optimizer' ),
282
+ 'too_far' => esc_html__( 'More images have been processed than expected. Unless you have added new images, you should refresh the page to stop the process and contact support.', 'ewww-image-optimizer' ),
283
+ 'restorable_images' => $restorable_images,
284
+ 'webp_cleanable' => $webp_cleanable,
285
  )
286
  );
287
  // Load the stylesheet for the jquery progressbar.
319
  </p>
320
  </div>
321
  <?php
322
+ } elseif ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
323
  ?>
324
  <div id="ewww-bulk-warning" class="ewww-bulk-info notice notice-warning">
325
  <p>
changelog.txt CHANGED
@@ -1,3 +1,13 @@
 
 
 
 
 
 
 
 
 
 
1
  = 6.7.0 =
2
  * added: API keys can be used to auto-register sites for Easy IO, including sub-keys
3
  * changed: expose legacy resize dimensions with removal option
1
+ = 6.8.0 =
2
+ * added: ability to store image backups on local storage
3
+ * added: tool to bulk restore images under Tools menu and WP-CLI
4
+ * added: WebP cleanup tool can be resumed and run via WP-CLI
5
+ * added: Delete Originals can be run via WP-CLI
6
+ * added: remove originals after conversion (like PNG to JPG) via WP-CLI
7
+ * added: exclude by page for Easy IO, Lazy Load, and WebP delivery methods
8
+ * changed: ensure full-size image is optimized after resizing with Imsanity
9
+ * fixed: incorrect cfasync attribute used for JS WebP scripts
10
+
11
  = 6.7.0 =
12
  * added: API keys can be used to auto-register sites for Easy IO, including sub-keys
13
  * changed: expose legacy resize dimensions with removal option
classes/class-eio-backup.php ADDED
@@ -0,0 +1,436 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Implements backup/restore functions.
4
+ *
5
+ * @link https://ewww.io
6
+ * @package EIO
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
+
13
+ /**
14
+ * Backup & Restore images from both local and cloud locations.
15
+ */
16
+ class EIO_Backup extends EIO_Base {
17
+
18
+ /**
19
+ * An error from a restore operation.
20
+ *
21
+ * @access protected
22
+ * @var string $error_message
23
+ */
24
+ protected $error_message = '';
25
+
26
+ /**
27
+ * A list of exclusions.
28
+ *
29
+ * @access protected
30
+ * @var array $exclusions
31
+ */
32
+ protected $exclusions = array();
33
+
34
+ /**
35
+ * Backup mode (local/cloud).
36
+ *
37
+ * @var string $backup_mode
38
+ */
39
+ protected $backup_mode = '';
40
+
41
+ /**
42
+ * Backup location.
43
+ *
44
+ * @var string $backup_dir
45
+ */
46
+ protected $backup_dir = '';
47
+
48
+ /**
49
+ * Register (once) actions and filters for Backup and Restore.
50
+ */
51
+ function __construct() {
52
+ global $eio_backup;
53
+ if ( is_object( $eio_backup ) ) {
54
+ return $eio_backup;
55
+ }
56
+ parent::__construct();
57
+ $this->debug_message( '<b>' . __METHOD__ . '()</b>' );
58
+ if ( 'local' === $this->get_option( 'ewww_image_optimizer_backup_files' ) ) {
59
+ $this->backup_mode = 'local';
60
+ // Sub-folders of the content directory will be stored directly in the image-backup/ folder.
61
+ $this->backup_dir = trailingslashit( $this->content_dir ) . trailingslashit( 'image-backup' );
62
+ // Sub-folders of the content directory will be stored directly in the image-backup/ folder.
63
+ $this->backup_uploads_dir = trailingslashit( $this->backup_dir ) . trailingslashit( 'uploads' );
64
+ // Folders outside the content dir, and relative to ABSPATH will be stored in the root/ directory.
65
+ $this->backup_root_dir = trailingslashit( $this->backup_dir ) . trailingslashit( 'root' );
66
+ } elseif ( $this->get_option( 'ewww_image_optimizer_cloud_key' ) && $this->get_option( 'ewww_image_optimizer_backup_files' ) ) {
67
+ $this->backup_mode = 'cloud';
68
+ }
69
+
70
+ // AJAX action hook for manually restoring a single image from cloud/local backups.
71
+ add_action( 'wp_ajax_ewww_manual_image_restore_single', array( $this, 'restore_single_image_handler' ) );
72
+ add_action( 'ewww_image_optimizer_pre_optimization', array( $this, 'store_local_backup' ) );
73
+
74
+ $this->exclusions = array(
75
+ $this->content_dir,
76
+ '/wp-admin/',
77
+ '/wp-includes/',
78
+ '/cache/',
79
+ '/dynamic/', // Nextgen dynamic images.
80
+ );
81
+ $this->exclusions = apply_filters( 'ewww_image_optimizer_backup_exclusions', $this->exclusions );
82
+ }
83
+
84
+ /**
85
+ * Gets the error message from the most recent restore operation, if any.
86
+ *
87
+ * @return string An error message.
88
+ */
89
+ public function get_error() {
90
+ return (string) $this->error_message;
91
+ }
92
+
93
+ /**
94
+ * Sets the error message for restore operations.
95
+ *
96
+ * @param string $error An error message.
97
+ */
98
+ public function throw_error( $error ) {
99
+ if ( is_string( $error ) ) {
100
+ $this->error_message = sanitize_text_field( $error );
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Checks whether a file is in the uploads dir, content dir, or within the ABSPATH/root.
106
+ *
107
+ * This helps to deal with cases where folks have upload and/or content dirs outside ABSPATH.
108
+ *
109
+ * @param string $file The filename to backup.
110
+ * @return string The backup location for the file.
111
+ */
112
+ public function get_backup_location( $file ) {
113
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
114
+ if ( \ewww_image_optimizer_stream_wrapped( $file ) ) {
115
+ return '';
116
+ }
117
+ $upload_dir = wp_get_upload_dir();
118
+ $upload_dir = trailingslashit( realpath( $upload_dir['basedir'] ) );
119
+ if ( $upload_dir && strpos( $file, $upload_dir ) === 0 ) {
120
+ $this->debug_message( 'using ' . $this->backup_uploads_dir );
121
+ return str_replace( $upload_dir, $this->backup_uploads_dir, $file );
122
+ }
123
+ $content_dir = trailingslashit( realpath( WP_CONTENT_DIR ) );
124
+ if ( $content_dir && strpos( $file, $content_dir ) === 0 ) {
125
+ $this->debug_message( 'using ' . $this->backup_dir );
126
+ return str_replace( $content_dir, $this->backup_dir, $file );
127
+ }
128
+ $wp_dir = trailingslashit( realpath( ABSPATH ) );
129
+ if ( $wp_dir && strpos( $file, $wp_dir ) === 0 ) {
130
+ $this->debug_message( 'using ' . $this->backup_root_dir );
131
+ return str_replace( $wp_dir, $this->backup_root_dir, $file );
132
+ }
133
+ return '';
134
+ }
135
+
136
+ /**
137
+ * Checks to see if a backup is available for a given file.
138
+ *
139
+ * @param string $file The image file to search for a backup.
140
+ * @param array $record The database record for the file. Optional.
141
+ * @return bool True if a backup is available, false otherwise.
142
+ */
143
+ public function is_backup_available( $file, $record = false ) {
144
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
145
+ $file = \ewww_image_optimizer_absolutize_path( $file );
146
+ if ( 'local' === $this->backup_mode ) {
147
+ clearstatcache();
148
+ $backup_file = $this->get_backup_location( $file );
149
+ return $this->is_file( $backup_file );
150
+ } elseif ( 'cloud' === $this->backup_mode ) {
151
+ if ( ! $record || ! isset( $record['backup'] ) || ! isset( $record['updated'] ) ) {
152
+ $record = \ewww_image_optimizer_find_already_optimized( $file );
153
+ }
154
+ if ( $record && $this->is_iterable( $record ) && ! empty( $record['backup'] ) && ! empty( $record['updated'] ) ) {
155
+ $updated_time = strtotime( $record['updated'] );
156
+ if ( DAY_IN_SECONDS * 30 + $updated_time > time() ) {
157
+ return true;
158
+ }
159
+ }
160
+ }
161
+ return false;
162
+ }
163
+
164
+ /**
165
+ * Backup a file to local or cloud storage.
166
+ *
167
+ * @param string $file Name of the file to backup.
168
+ */
169
+ public function backup_file( $file ) {
170
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
171
+ $this->debug_message( "file: $file " );
172
+ foreach ( $this->exclusions as $exclusion ) {
173
+ if ( false !== strpos( $file, $exclusion ) ) {
174
+ return;
175
+ }
176
+ }
177
+ if ( 'local' === $this->backup_mode ) {
178
+ $this->store_local_backup( $file );
179
+ } elseif ( 'cloud' === $this->backup_mode ) {
180
+ $this->store_cloud_backup( $file );
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Copy a file to the backup location.
186
+ *
187
+ * @param string $file Name of the file to backup.
188
+ */
189
+ public function store_local_backup( $file ) {
190
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
191
+ if ( 'local' !== $this->get_option( 'ewww_image_optimizer_backup_files' ) ) {
192
+ return;
193
+ }
194
+ if ( ! $this->is_file( $file ) || ! $this->is_readable( $file ) ) {
195
+ return;
196
+ }
197
+ $backup_file = $this->get_backup_location( $file );
198
+ if ( ! $backup_file || $backup_file === $file ) {
199
+ return;
200
+ }
201
+ \clearstatcache();
202
+ if ( $this->is_file( $backup_file ) ) {
203
+ return;
204
+ }
205
+ \wp_mkdir_p( dirname( $backup_file ) );
206
+ clearstatcache();
207
+ if ( ! is_writable( dirname( $backup_file ) ) ) {
208
+ return;
209
+ }
210
+ $this->debug_message( "backing up $file to $backup_file" );
211
+ copy( $file, $backup_file );
212
+ if ( $this->filesize( $file ) !== $this->filesize( $backup_file ) ) {
213
+ // In order to not store bogus files.
214
+ $this->delete_file( $backup_file );
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Send a file to the API for backup.
220
+ *
221
+ * @param string $file Name of the file to backup.
222
+ */
223
+ protected function store_cloud_backup( $file ) {
224
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
225
+ \ewww_image_optimizer_cloud_backup( $file );
226
+ }
227
+
228
+ /**
229
+ * Restore an image from local or cloud storage.
230
+ *
231
+ * @global object $wpdb
232
+ * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity.
233
+ *
234
+ * @param int|array $image The db record/ID of the image to restore.
235
+ * @return bool True if the image was restored successfully.
236
+ */
237
+ public function restore_file( $image ) {
238
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
239
+ global $wpdb;
240
+ if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
241
+ \ewww_image_optimizer_db_init();
242
+ global $ewwwdb;
243
+ } else {
244
+ $ewwwdb = $wpdb;
245
+ }
246
+ $this->error_message = '';
247
+ if ( ! is_array( $image ) && ! empty( $image ) && is_numeric( $image ) ) {
248
+ $image = $ewwwdb->get_row( "SELECT id,path,backup FROM $ewwwdb->ewwwio_images WHERE id = $image", ARRAY_A );
249
+ }
250
+ if ( ! empty( $image['path'] ) ) {
251
+ $image['path'] = \ewww_image_optimizer_absolutize_path( $image['path'] );
252
+ }
253
+ if ( empty( $image['path'] ) ) {
254
+ return false;
255
+ }
256
+ if ( 'local' === $this->backup_mode ) {
257
+ return $this->restore_from_local( $image );
258
+ } elseif ( 'cloud' === $this->backup_mode ) {
259
+ return $this->restore_from_cloud( $image );
260
+ }
261
+ return false;
262
+ }
263
+
264
+ /**
265
+ * Restore a file from a local backup location.
266
+ *
267
+ * @param array $image The db record of the image to restore.
268
+ */
269
+ protected function restore_from_local( $image ) {
270
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
271
+ if ( 'local' !== $this->get_option( 'ewww_image_optimizer_backup_files' ) ) {
272
+ return false;
273
+ }
274
+ $file = $image['path'];
275
+ if ( ! is_writable( dirname( $file ) ) ) {
276
+ $this->debug_message( "$file (or the parent dir) is not writable" );
277
+ /* translators: %s: An image filename */
278
+ $this->error_message = sprintf( __( '%s is not writable.', 'ewww-image-optimizer' ), $file );
279
+ return false;
280
+ }
281
+ $backup_file = $this->get_backup_location( $file );
282
+ if ( ! $backup_file || $backup_file === $file ) {
283
+ $this->debug_message( "$backup_file is not a valid backup location for $file" );
284
+ /* translators: %s: An image filename */
285
+ $this->error_message = sprintf( __( 'Could not determine backup location for %s.', 'ewww-image-optimizer' ), $file );
286
+ return false;
287
+ }
288
+ \clearstatcache();
289
+ if ( ! $this->is_file( $backup_file ) ) {
290
+ $this->debug_message( "$backup_file does not exist" );
291
+ /* translators: %s: An image filename */
292
+ $this->error_message = sprintf( __( 'No backup available for %s.', 'ewww-image-optimizer' ), $file );
293
+ return false;
294
+ }
295
+ if ( \ewww_image_optimizer_mimetype( $file, 'i' ) !== \ewww_image_optimizer_mimetype( $backup_file, 'i' ) ) {
296
+ $this->debug_message( "$backup_file is different type than $file " . \ewww_image_optimizer_mimetype( $backup_file, 'i' ) . ' vs. ' . \ewww_image_optimizer_mimetype( $file, 'i' ) );
297
+ /* translators: %s: An image filename */
298
+ $this->error_message = sprintf( __( 'Backup file for %s has the wrong mime type.', 'ewww-image-optimizer' ), $file );
299
+ return false;
300
+ }
301
+ $filesize = $this->filesize( $file );
302
+ $backsize = $this->filesize( $backup_file );
303
+ if ( $filesize && $filesize === $backsize ) {
304
+ // $this->delete_file( $backup_file );
305
+ // return true; // Because restore not needed, already done!
306
+ }
307
+ $this->debug_message( "restoring $file from $backup_file" );
308
+ copy( $backup_file, $file );
309
+ if ( $this->filesize( $file ) === $this->filesize( $backup_file ) ) {
310
+ if ( $this->is_file( $file . '.webp' ) && is_writable( $file . '.webp' ) ) {
311
+ $this->delete_file( $file . '.webp' );
312
+ }
313
+ /* $this->delete_file( $backup_file ); */
314
+ global $wpdb;
315
+ // Reset the image record.
316
+ $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->ewwwio_images SET results = '', image_size = 0, updates = 0, updated=updated, level = 0 WHERE id = %d", $image['id'] ) );
317
+ return true;
318
+ }
319
+ /* translators: %s: An image filename */
320
+ $this->error_message = sprintf( __( 'Restore attempted for %s, but could not be confirmed.', 'ewww-image-optimizer' ), $file );
321
+ return false;
322
+ }
323
+
324
+ /**
325
+ * Send a file to the API for backup.
326
+ *
327
+ * @param int|array $image The db record/ID of the image to restore.
328
+ * @return bool True if the image was restored successfully.
329
+ */
330
+ protected function restore_from_cloud( $image ) {
331
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
332
+ return \ewww_image_optimizer_cloud_restore_single_image( $image );
333
+ }
334
+
335
+ /**
336
+ * Delete the local backup file. Used when deleting an attachment.
337
+ *
338
+ * @param array $file The filename of the image for which we should remove the backup.
339
+ */
340
+ public function delete_local_backup( $file ) {
341
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
342
+ if ( ! $file ) {
343
+ return;
344
+ }
345
+ $backup_file = $this->get_backup_location( $file );
346
+ if ( ! $backup_file || $backup_file === $file ) {
347
+ return;
348
+ }
349
+ \clearstatcache();
350
+ if ( ! $this->is_file( $backup_file ) || ! \is_writable( $backup_file ) ) {
351
+ return;
352
+ }
353
+ $this->delete_file( $backup_file );
354
+ }
355
+
356
+ /**
357
+ * Restore an attachment from the API or local backups.
358
+ *
359
+ * @global object $wpdb
360
+ * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity.
361
+ *
362
+ * @param int $id The attachment id number.
363
+ * @param string $gallery Optional. The gallery from whence we came. Default 'media'.
364
+ * @param array $meta Optional. The image metadata from the postmeta table.
365
+ * @return array The altered meta (if size differs), or the original value passed along.
366
+ */
367
+ public function restore_backup_from_meta_data( $id, $gallery = 'media', $meta = array() ) {
368
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
369
+ global $wpdb;
370
+ if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
371
+ ewww_image_optimizer_db_init();
372
+ global $ewwwdb;
373
+ } else {
374
+ $ewwwdb = $wpdb;
375
+ }
376
+ $images = $ewwwdb->get_results( "SELECT id,path,resize,backup FROM $ewwwdb->ewwwio_images WHERE attachment_id = $id AND gallery = '$gallery'", ARRAY_A );
377
+ foreach ( $images as $image ) {
378
+ if ( ! empty( $image['path'] ) ) {
379
+ $image['path'] = ewww_image_optimizer_absolutize_path( $image['path'] );
380
+ }
381
+ $this->restore_file( $image );
382
+ if ( 'media' === $gallery && 'full' === $image['resize'] && ! empty( $meta['width'] ) && ! empty( $meta['height'] ) ) {
383
+ list( $width, $height ) = wp_getimagesize( $image['path'] );
384
+ if ( (int) $width !== (int) $meta['width'] || (int) $height !== (int) $meta['height'] ) {
385
+ $meta['height'] = $height;
386
+ $meta['width'] = $width;
387
+ }
388
+ }
389
+ }
390
+ if ( 'media' === $gallery ) {
391
+ remove_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_update_filesize_metadata', 9 );
392
+ $meta = ewww_image_optimizer_update_filesize_metadata( $meta, $id );
393
+ }
394
+ if ( class_exists( 'S3_Uploads' ) || class_exists( 'S3_uploads\Plugin' ) ) {
395
+ ewww_image_optimizer_remote_push( $meta, $id );
396
+ $this->debug_message( 're-uploading to S3(_Uploads)' );
397
+ }
398
+ return $meta;
399
+ }
400
+
401
+ /**
402
+ * Handle the AJAX call for a single image restore.
403
+ */
404
+ public function restore_single_image_handler() {
405
+ $this->debug_message( '<b>' . __FUNCTION__ . '()</b>' );
406
+ // Check permissions of current user.
407
+ $permissions = apply_filters( 'ewww_image_optimizer_manual_permissions', '' );
408
+ if ( ! \current_user_can( $permissions ) ) {
409
+ // Display error message if insufficient permissions.
410
+ $this->ob_clean();
411
+ \wp_die( \wp_json_encode( array( 'error' => \esc_html__( 'You do not have permission to optimize images.', 'ewww-image-optimizer' ) ) ) );
412
+ }
413
+ // Make sure we didn't accidentally get to this page without an attachment to work on.
414
+ if ( empty( $_REQUEST['ewww_image_id'] ) ) {
415
+ // Display an error message since we don't have anything to work on.
416
+ $this->ob_clean();
417
+ \wp_die( \wp_json_encode( array( 'error' => \esc_html__( 'No image ID was provided.', 'ewww-image-optimizer' ) ) ) );
418
+ }
419
+ if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) ) {
420
+ $this->ob_clean();
421
+ \wp_die( \wp_json_encode( array( 'error' => \esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) );
422
+ }
423
+ \session_write_close();
424
+ $image = (int) $_REQUEST['ewww_image_id'];
425
+ $this->debug_message( "attempting restore for $image" );
426
+ if ( $this->restore_file( $image ) ) {
427
+ $this->ob_clean();
428
+ \wp_die( \wp_json_encode( array( 'success' => 1 ) ) );
429
+ }
430
+ $this->ob_clean();
431
+ \wp_die( \wp_json_encode( array( 'error' => \esc_html__( 'Unable to restore image.', 'ewww-image-optimizer' ) ) ) );
432
+ }
433
+ }
434
+
435
+ global $eio_backup;
436
+ $eio_backup = new EIO_Backup();
classes/class-eio-base.php CHANGED
@@ -523,6 +523,82 @@ if ( ! class_exists( 'EIO_Base' ) ) {
523
  return is_file( $file );
524
  }
525
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
526
 
527
  /**
528
  * Make sure an array/object can be parsed by a foreach().
@@ -587,6 +663,15 @@ if ( ! class_exists( 'EIO_Base' ) ) {
587
  return $memory_limit;
588
  }
589
 
 
 
 
 
 
 
 
 
 
590
  /**
591
  * Set an option: use 'site' setting if plugin is network activated, otherwise use 'blog' setting.
592
  *
523
  return is_file( $file );
524
  }
525
 
526
+ /**
527
+ * Check if a file/directory is readable.
528
+ *
529
+ * @param string $file The path to check.
530
+ * @return bool True if it is, false if it ain't.
531
+ */
532
+ function is_readable( $file ) {
533
+ $this->get_filesystem();
534
+ return $this->filesystem->is_readable( $file );
535
+ }
536
+
537
+ /**
538
+ * Check filesize, and prevent errors by ensuring file exists, and that the cache has been cleared.
539
+ *
540
+ * @param string $file The name of the file.
541
+ * @return int The size of the file or zero.
542
+ */
543
+ function filesize( $file ) {
544
+ $file = realpath( $file );
545
+ if ( $this->is_file( $file ) ) {
546
+ $this->get_filesystem();
547
+ // Flush the cache for filesize.
548
+ clearstatcache();
549
+ // Find out the size of the new PNG file.
550
+ return $this->filesystem->size( $file );
551
+ } else {
552
+ return 0;
553
+ }
554
+ }
555
+
556
+ /**
557
+ * Check if file is in an approved location and remove it.
558
+ *
559
+ * @param string $file The path of the file to check.
560
+ * @param string $dir The path of the folder constraint. Optional.
561
+ * @return bool True if the file was removed, false otherwise.
562
+ */
563
+ function delete_file( $file, $dir = '' ) {
564
+ $file = realpath( $file );
565
+ if ( ! empty( $dir ) ) {
566
+ return \wp_delete_file_from_directory( $file, $dir );
567
+ }
568
+
569
+ $wp_dir = realpath( ABSPATH );
570
+ $upload_dir = \wp_get_upload_dir();
571
+ $upload_dir = realpath( $upload_dir['basedir'] );
572
+ $content_dir = realpath( WP_CONTENT_DIR );
573
+
574
+ if ( false !== strpos( $file, $upload_dir ) ) {
575
+ return \wp_delete_file_from_directory( $file, $upload_dir );
576
+ }
577
+ if ( false !== strpos( $file, $content_dir ) ) {
578
+ return \wp_delete_file_from_directory( $file, $content_dir );
579
+ }
580
+ if ( false !== strpos( $file, $wp_dir ) ) {
581
+ return \wp_delete_file_from_directory( $file, $wp_dir );
582
+ }
583
+ return false;
584
+ }
585
+
586
+ /**
587
+ * Setup the filesystem class.
588
+ */
589
+ function get_filesystem() {
590
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php' );
591
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php' );
592
+ if ( ! defined( 'FS_CHMOD_DIR' ) ) {
593
+ define( 'FS_CHMOD_DIR', ( fileperms( ABSPATH ) & 0777 | 0755 ) );
594
+ }
595
+ if ( ! defined( 'FS_CHMOD_FILE' ) ) {
596
+ define( 'FS_CHMOD_FILE', ( fileperms( ABSPATH . 'index.php' ) & 0777 | 0644 ) );
597
+ }
598
+ if ( ! isset( $this->filesystem ) || ! is_object( $this->filesystem ) ) {
599
+ $this->filesystem = new \WP_Filesystem_Direct( '' );
600
+ }
601
+ }
602
 
603
  /**
604
  * Make sure an array/object can be parsed by a foreach().
663
  return $memory_limit;
664
  }
665
 
666
+ /**
667
+ * Clear output buffers without throwing a fit.
668
+ */
669
+ function ob_clean() {
670
+ if ( ob_get_length() ) {
671
+ ob_end_clean();
672
+ }
673
+ }
674
+
675
  /**
676
  * Set an option: use 'site' setting if plugin is network activated, otherwise use 'blog' setting.
677
  *
classes/class-eio-js-webp.php CHANGED
@@ -31,6 +31,14 @@ class EIO_JS_Webp extends EIO_Page_Parser {
31
  */
32
  protected $user_element_exclusions = array();
33
 
 
 
 
 
 
 
 
 
34
  /**
35
  * Base64-encoded placeholder image.
36
  *
@@ -166,6 +174,18 @@ class EIO_JS_Webp extends EIO_Page_Parser {
166
  if ( empty( $uri ) ) {
167
  $uri = $this->request_uri;
168
  }
 
 
 
 
 
 
 
 
 
 
 
 
169
  if ( false !== strpos( $uri, 'bricks=run' ) ) {
170
  return false;
171
  }
@@ -389,8 +409,7 @@ class EIO_JS_Webp extends EIO_Page_Parser {
389
  }
390
 
391
  $body_tags = $this->get_elements_from_html( $buffer, 'body' );
392
- $body_webp_script = '<script data-cfasync="false" data-no-defer="1">if(ewww_webp_supported){document.body.classList.add("webp-support");}</script>';
393
- $body_webp_script = '<script data=cfasync="false" data-no-defer="1">if(typeof ewww_webp_supported==="undefined"){var ewww_webp_supported=!1}if(ewww_webp_supported){document.body.classList.add("webp-support")}</script>';
394
  if ( $this->is_iterable( $body_tags ) && ! empty( $body_tags[0] ) && false !== strpos( $body_tags[0], '<body' ) ) {
395
  // Add the WebP script right after the opening tag.
396
  $buffer = str_replace( $body_tags[0], $body_tags[0] . "\n" . $body_webp_script, $buffer );
@@ -945,6 +964,11 @@ class EIO_JS_Webp extends EIO_Page_Parser {
945
  if ( ! is_string( $exclusion ) ) {
946
  continue;
947
  }
 
 
 
 
 
948
  if (
949
  'a' === $exclusion ||
950
  'div' === $exclusion ||
31
  */
32
  protected $user_element_exclusions = array();
33
 
34
+ /**
35
+ * A list of user-defined page/URL exclusions, populated by validate_user_exclusions().
36
+ *
37
+ * @access protected
38
+ * @var array $user_page_exclusions
39
+ */
40
+ protected $user_page_exclusions = array();
41
+
42
  /**
43
  * Base64-encoded placeholder image.
44
  *
174
  if ( empty( $uri ) ) {
175
  $uri = $this->request_uri;
176
  }
177
+ if ( $this->is_iterable( $this->user_page_exclusions ) ) {
178
+ foreach ( $this->user_page_exclusions as $page_exclusion ) {
179
+ if ( '/' === $page_exclusion && '/' === $uri ) {
180
+ return false;
181
+ } elseif ( '/' === $page_exclusion ) {
182
+ continue;
183
+ }
184
+ if ( false !== strpos( $uri, $page_exclusion ) ) {
185
+ return false;
186
+ }
187
+ }
188
+ }
189
  if ( false !== strpos( $uri, 'bricks=run' ) ) {
190
  return false;
191
  }
409
  }
410
 
411
  $body_tags = $this->get_elements_from_html( $buffer, 'body' );
412
+ $body_webp_script = '<script data-cfasync="false" data-no-defer="1">if(typeof ewww_webp_supported==="undefined"){var ewww_webp_supported=!1}if(ewww_webp_supported){document.body.classList.add("webp-support")}</script>';
 
413
  if ( $this->is_iterable( $body_tags ) && ! empty( $body_tags[0] ) && false !== strpos( $body_tags[0], '<body' ) ) {
414
  // Add the WebP script right after the opening tag.
415
  $buffer = str_replace( $body_tags[0], $body_tags[0] . "\n" . $body_webp_script, $buffer );
964
  if ( ! is_string( $exclusion ) ) {
965
  continue;
966
  }
967
+ $exclusion = trim( $exclusion );
968
+ if ( 0 === strpos( $exclusion, 'page:' ) ) {
969
+ $this->user_page_exclusions[] = str_replace( 'page:', '', $exclusion );
970
+ continue;
971
+ }
972
  if (
973
  'a' === $exclusion ||
974
  'div' === $exclusion ||
classes/class-eio-lazy-load.php CHANGED
@@ -32,6 +32,14 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
32
  */
33
  protected $user_element_exclusions = array();
34
 
 
 
 
 
 
 
 
 
35
  /**
36
  * A list of user-defined inclusions to lazy load for "external" CSS background images.
37
  *
@@ -199,6 +207,18 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
199
  if ( empty( $uri ) ) {
200
  $uri = $this->request_uri;
201
  }
 
 
 
 
 
 
 
 
 
 
 
 
202
  if ( false !== strpos( $uri, 'bricks=run' ) ) {
203
  return false;
204
  }
@@ -261,6 +281,9 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
261
  if ( ! did_action( 'parse_query' ) ) {
262
  return $should_process;
263
  }
 
 
 
264
  if ( $this->is_amp() ) {
265
  return false;
266
  }
@@ -860,6 +883,11 @@ if ( ! class_exists( 'EIO_Lazy_Load' ) ) {
860
  if ( ! is_string( $exclusion ) ) {
861
  continue;
862
  }
 
 
 
 
 
863
  if (
864
  'a' === $exclusion ||
865
  'div' === $exclusion ||
32
  */
33
  protected $user_element_exclusions = array();
34
 
35
+ /**
36
+ * A list of user-defined page/URL exclusions, populated by validate_user_exclusions().
37
+ *
38
+ * @access protected
39
+ * @var array $user_page_exclusions
40
+ */
41
+ protected $user_page_exclusions = array();
42
+
43
  /**
44
  * A list of user-defined inclusions to lazy load for "external" CSS background images.
45
  *
207
  if ( empty( $uri ) ) {
208
  $uri = $this->request_uri;
209
  }
210
+ if ( $this->is_iterable( $this->user_page_exclusions ) ) {
211
+ foreach ( $this->user_page_exclusions as $page_exclusion ) {
212
+ if ( '/' === $page_exclusion && '/' === $uri ) {
213
+ return false;
214
+ } elseif ( '/' === $page_exclusion ) {
215
+ continue;
216
+ }
217
+ if ( false !== strpos( $uri, $page_exclusion ) ) {
218
+ return false;
219
+ }
220
+ }
221
+ }
222
  if ( false !== strpos( $uri, 'bricks=run' ) ) {
223
  return false;
224
  }
281
  if ( ! did_action( 'parse_query' ) ) {
282
  return $should_process;
283
  }
284
+ if ( function_exists( 'affwp_is_affiliate_portal' ) && affwp_is_affiliate_portal() ) {
285
+ return false;
286
+ }
287
  if ( $this->is_amp() ) {
288
  return false;
289
  }
883
  if ( ! is_string( $exclusion ) ) {
884
  continue;
885
  }
886
+ $exclusion = trim( $exclusion );
887
+ if ( 0 === strpos( $exclusion, 'page:' ) ) {
888
+ $this->user_page_exclusions[] = str_replace( 'page:', '', $exclusion );
889
+ continue;
890
+ }
891
  if (
892
  'a' === $exclusion ||
893
  'div' === $exclusion ||
classes/class-eio-picture-webp.php CHANGED
@@ -31,6 +31,14 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
31
  */
32
  protected $user_element_exclusions = array();
33
 
 
 
 
 
 
 
 
 
34
  /**
35
  * Request URI.
36
  *
@@ -124,6 +132,18 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
124
  if ( empty( $uri ) ) {
125
  $uri = $this->request_uri;
126
  }
 
 
 
 
 
 
 
 
 
 
 
 
127
  if ( false !== strpos( $uri, 'bricks=run' ) ) {
128
  return false;
129
  }
@@ -401,6 +421,11 @@ class EIO_Picture_Webp extends EIO_Page_Parser {
401
  if ( ! is_string( $exclusion ) ) {
402
  continue;
403
  }
 
 
 
 
 
404
  if (
405
  'a' === $exclusion ||
406
  'div' === $exclusion ||
31
  */
32
  protected $user_element_exclusions = array();
33
 
34
+ /**
35
+ * A list of user-defined page/URL exclusions, populated by validate_user_exclusions().
36
+ *
37
+ * @access protected
38
+ * @var array $user_page_exclusions
39
+ */
40
+ protected $user_page_exclusions = array();
41
+
42
  /**
43
  * Request URI.
44
  *
132
  if ( empty( $uri ) ) {
133
  $uri = $this->request_uri;
134
  }
135
+ if ( $this->is_iterable( $this->user_page_exclusions ) ) {
136
+ foreach ( $this->user_page_exclusions as $page_exclusion ) {
137
+ if ( '/' === $page_exclusion && '/' === $uri ) {
138
+ return false;
139
+ } elseif ( '/' === $page_exclusion ) {
140
+ continue;
141
+ }
142
+ if ( false !== strpos( $uri, $page_exclusion ) ) {
143
+ return false;
144
+ }
145
+ }
146
+ }
147
  if ( false !== strpos( $uri, 'bricks=run' ) ) {
148
  return false;
149
  }
421
  if ( ! is_string( $exclusion ) ) {
422
  continue;
423
  }
424
+ $exclusion = trim( $exclusion );
425
+ if ( 0 === strpos( $exclusion, 'page:' ) ) {
426
+ $this->user_page_exclusions[] = str_replace( 'page:', '', $exclusion );
427
+ continue;
428
+ }
429
  if (
430
  'a' === $exclusion ||
431
  'div' === $exclusion ||
classes/class-ewww-flag.php CHANGED
@@ -42,7 +42,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
42
  // To prevent webview from being prematurely optimized.
43
  add_action( 'flag_thumbnail_created', array( $this, 'ewww_remove_image_editor' ) );
44
  add_action( 'wp_ajax_ewww_flag_manual', array( $this, 'ewww_flag_manual' ) );
45
- add_action( 'wp_ajax_ewww_flag_cloud_restore', array( $this, 'ewww_flag_cloud_restore' ) );
46
  add_action( 'admin_action_ewww_flag_manual', array( $this, 'ewww_flag_manual' ) );
47
  add_action( 'admin_menu', array( $this, 'ewww_flag_bulk_menu' ) );
48
  add_action( 'admin_enqueue_scripts', array( $this, 'ewww_flag_bulk_script' ), PHP_INT_MAX );
@@ -114,7 +114,9 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
114
  ewww_image_optimizer_cloud_verify( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) );
115
  echo '<a id="ewww-bulk-credits-available" target="_blank" class="page-title-action" style="float:right;" href="https://ewww.io/my-account/">' . esc_html__( 'Image credits available:', 'ewww-image-optimizer' ) . ' ' . esc_html( ewww_image_optimizer_cloud_quota() ) . '</a>';
116
  }
117
- echo '<div id="ewww-bulk-warning" class="ewww-bulk-info notice notice-warning"><p>' . esc_html__( 'Bulk Optimization will alter your original images and cannot be undone. Please be sure you have a backup of your images before proceeding.', 'ewww-image-optimizer' ) . '</p></div>';
 
 
118
  // Retrieve the value of the 'bulk resume' option and set the button text for the form to use.
119
  $resume = get_option( 'ewww_image_optimizer_bulk_flag_resume' );
120
  if ( empty( $resume ) ) {
@@ -329,9 +331,6 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
329
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
330
  $image_id = $image->pid;
331
  global $ewwwio_flag_background;
332
- if ( ! class_exists( 'WP_Background_Process' ) ) {
333
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
334
- }
335
  if ( ! is_object( $ewwwio_flag_background ) ) {
336
  $ewwwio_flag_background = new EWWWIO_Flag_Background_Process();
337
  }
@@ -481,7 +480,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
481
  /**
482
  * Restore an image from the API.
483
  */
484
- function ewww_flag_cloud_restore() {
485
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
486
  // Check permission of current user.
487
  $permissions = apply_filters( 'ewww_image_optimizer_manual_permissions', '' );
@@ -512,7 +511,8 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
512
  if ( ! class_exists( 'flagMeta' ) ) {
513
  require_once( FLAG_ABSPATH . 'lib/meta.php' );
514
  }
515
- ewww_image_optimizer_cloud_restore_from_meta_data( $id, 'flag' );
 
516
  $success = $this->ewww_manage_image_custom_column_capture( $id );
517
  ewwwio_ob_clean();
518
  wp_die( wp_json_encode( array( 'success' => $success ) ) );
@@ -802,7 +802,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
802
  }
803
  $backup_available = false;
804
  global $wpdb;
805
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT image_size,orig_size,resize,converted,level,backup,updated FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'flag' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
806
  $ewww_manual_nonce = wp_create_nonce( 'ewww-manual-' . $id );
807
  if ( ! empty( $optimized_images ) ) {
808
  list( $detail_output, $converted, $backup_available ) = ewww_image_optimizer_custom_column_results( $id, $optimized_images );
@@ -816,7 +816,7 @@ if ( ! class_exists( 'EWWW_Flag' ) ) {
816
  );
817
  if ( $backup_available ) {
818
  printf(
819
- '<br><a class="ewww-manual-cloud-restore" data-id="%1$d" data-nonce="%2$s" href="' . esc_url( admin_url( 'admin.php?action=ewww_flag_cloud_restore' ) ) . '&amp;ewww_manual_nonce=%2$s&amp;ewww_attachment_ID=%1$d">%3$s</a>',
820
  (int) $id,
821
  esc_attr( $ewww_manual_nonce ),
822
  esc_html__( 'Restore original', 'ewww-image-optimizer' )
42
  // To prevent webview from being prematurely optimized.
43
  add_action( 'flag_thumbnail_created', array( $this, 'ewww_remove_image_editor' ) );
44
  add_action( 'wp_ajax_ewww_flag_manual', array( $this, 'ewww_flag_manual' ) );
45
+ add_action( 'wp_ajax_ewww_flag_image_restore', array( $this, 'ewww_flag_image_restore' ) );
46
  add_action( 'admin_action_ewww_flag_manual', array( $this, 'ewww_flag_manual' ) );
47
  add_action( 'admin_menu', array( $this, 'ewww_flag_bulk_menu' ) );
48
  add_action( 'admin_enqueue_scripts', array( $this, 'ewww_flag_bulk_script' ), PHP_INT_MAX );
114
  ewww_image_optimizer_cloud_verify( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) );
115
  echo '<a id="ewww-bulk-credits-available" target="_blank" class="page-title-action" style="float:right;" href="https://ewww.io/my-account/">' . esc_html__( 'Image credits available:', 'ewww-image-optimizer' ) . ' ' . esc_html( ewww_image_optimizer_cloud_quota() ) . '</a>';
116
  }
117
+ if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
118
+ echo '<div id="ewww-bulk-warning" class="ewww-bulk-info notice notice-warning"><p>' . esc_html__( 'Bulk Optimization will alter your original images and cannot be undone. Please be sure you have a backup of your images before proceeding.', 'ewww-image-optimizer' ) . '</p></div>';
119
+ }
120
  // Retrieve the value of the 'bulk resume' option and set the button text for the form to use.
121
  $resume = get_option( 'ewww_image_optimizer_bulk_flag_resume' );
122
  if ( empty( $resume ) ) {
331
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
332
  $image_id = $image->pid;
333
  global $ewwwio_flag_background;
 
 
 
334
  if ( ! is_object( $ewwwio_flag_background ) ) {
335
  $ewwwio_flag_background = new EWWWIO_Flag_Background_Process();
336
  }
480
  /**
481
  * Restore an image from the API.
482
  */
483
+ function ewww_flag_image_restore() {
484
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
485
  // Check permission of current user.
486
  $permissions = apply_filters( 'ewww_image_optimizer_manual_permissions', '' );
511
  if ( ! class_exists( 'flagMeta' ) ) {
512
  require_once( FLAG_ABSPATH . 'lib/meta.php' );
513
  }
514
+ global $eio_backup;
515
+ $eio_backup->restore_backup_from_meta_data( $id, 'flag' );
516
  $success = $this->ewww_manage_image_custom_column_capture( $id );
517
  ewwwio_ob_clean();
518
  wp_die( wp_json_encode( array( 'success' => $success ) ) );
802
  }
803
  $backup_available = false;
804
  global $wpdb;
805
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'flag' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
806
  $ewww_manual_nonce = wp_create_nonce( 'ewww-manual-' . $id );
807
  if ( ! empty( $optimized_images ) ) {
808
  list( $detail_output, $converted, $backup_available ) = ewww_image_optimizer_custom_column_results( $id, $optimized_images );
816
  );
817
  if ( $backup_available ) {
818
  printf(
819
+ '<br><a class="ewww-manual-image-restore" data-id="%1$d" data-nonce="%2$s" href="' . esc_url( admin_url( 'admin.php?action=ewww_flag_image_restore' ) ) . '&amp;ewww_manual_nonce=%2$s&amp;ewww_attachment_ID=%1$d">%3$s</a>',
820
  (int) $id,
821
  esc_attr( $ewww_manual_nonce ),
822
  esc_html__( 'Restore original', 'ewww-image-optimizer' )
classes/class-ewww-nextcellent.php CHANGED
@@ -57,9 +57,6 @@ if ( ! class_exists( 'EWWW_Nextcellent' ) ) {
57
  */
58
  function dispatch_new_images( $gallery, $images ) {
59
  global $ewwwio_ngg_background;
60
- if ( ! class_exists( 'WP_Background_Process' ) ) {
61
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
62
- }
63
  if ( ! is_object( $ewwwio_ngg_background ) ) {
64
  $ewwwio_ngg_background = new EWWWIO_Ngg_Background_Process();
65
  }
@@ -350,7 +347,7 @@ if ( ! class_exists( 'EWWW_Nextcellent' ) ) {
350
  }
351
  $backup_available = false;
352
  global $wpdb;
353
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT image_size,orig_size,resize,converted,level,backup,updated FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'nextcell' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
354
  $ewww_manual_nonce = wp_create_nonce( 'ewww-manual-' . $id );
355
  // If we have a valid status, display it, the image size, and give a re-optimize link.
356
  if ( ! empty( $optimized_images ) ) {
57
  */
58
  function dispatch_new_images( $gallery, $images ) {
59
  global $ewwwio_ngg_background;
 
 
 
60
  if ( ! is_object( $ewwwio_ngg_background ) ) {
61
  $ewwwio_ngg_background = new EWWWIO_Ngg_Background_Process();
62
  }
347
  }
348
  $backup_available = false;
349
  global $wpdb;
350
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'nextcell' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
351
  $ewww_manual_nonce = wp_create_nonce( 'ewww-manual-' . $id );
352
  // If we have a valid status, display it, the image size, and give a re-optimize link.
353
  if ( ! empty( $optimized_images ) ) {
classes/class-ewww-nextgen.php CHANGED
@@ -41,7 +41,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
41
  ewwwio_debug_message( 'background mode NOT enabled for nextgen' );
42
  }
43
  add_action( 'wp_ajax_ewww_ngg_manual', array( $this, 'ewww_ngg_manual' ) );
44
- add_action( 'wp_ajax_ewww_ngg_cloud_restore', array( $this, 'ewww_ngg_cloud_restore' ) );
45
  add_action( 'admin_action_ewww_ngg_manual', array( $this, 'ewww_ngg_manual' ) );
46
  add_action( 'admin_enqueue_scripts', array( $this, 'ewww_ngg_manual_actions_script' ) );
47
  add_action( 'admin_menu', array( $this, 'ewww_ngg_bulk_menu' ) );
@@ -153,9 +153,6 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
153
  $image_id = $storage->object->_get_image_id( $image );
154
  }
155
  global $ewwwio_ngg2_background;
156
- if ( ! class_exists( 'WP_Background_Process' ) ) {
157
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
158
- }
159
  if ( ! is_object( $ewwwio_ngg2_background ) ) {
160
  $ewwwio_ngg2_background = new EWWWIO_Ngg2_Background_Process();
161
  }
@@ -320,7 +317,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
320
  /**
321
  * Restore an image from the NextGEN Gallery.
322
  */
323
- function ewww_ngg_cloud_restore() {
324
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
325
  // Check permission of current user.
326
  $permissions = apply_filters( 'ewww_image_optimizer_manual_permissions', '' );
@@ -354,7 +351,8 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
354
  $storage = $registry->get_utility( 'I_Gallery_Storage' );
355
  // Get an image object.
356
  $image = $storage->object->_image_mapper->find( $id );
357
- ewww_image_optimizer_cloud_restore_from_meta_data( $image->pid, 'nextgen' );
 
358
  $success = $this->ewww_manage_image_custom_column( '', $image );
359
  ewwwio_ob_clean();
360
  wp_die( wp_json_encode( array( 'success' => $success ) ) );
@@ -528,7 +526,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
528
  }
529
  $backup_available = false;
530
  global $wpdb;
531
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT image_size,orig_size,resize,converted,level,backup,updated FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'nextgen' AND image_size <> 0 ORDER BY orig_size DESC", $image->pid ), ARRAY_A );
532
  if ( ! empty( $optimized_images ) ) {
533
  list( $detail_output, $converted, $backup_available ) = ewww_image_optimizer_custom_column_results( $image->pid, $optimized_images );
534
  echo wp_kses_post( $detail_output );
@@ -569,7 +567,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
569
  if ( 'optimize' === $id && is_object( $image ) && ! empty( $image->pid ) ) {
570
  $id = $image->pid;
571
  global $wpdb;
572
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT image_size,orig_size,resize,converted,level,backup,updated FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'nextgen' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
573
  if ( ! empty( $optimized_images ) ) {
574
  $optimized = true;
575
  }
@@ -584,7 +582,7 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
584
  );
585
  if ( $restorable ) {
586
  printf(
587
- '<br><a class="ewww-manual-cloud-restore" data-id="%1$d" data-nonce="%2$s" href="' . esc_url( admin_url( 'admin.php?action=ewww_ngg_cloud_restore' ) ) . '&amp;ewww_manual_nonce=%2$s&amp;ewww_attachment_ID=%1$d">%3$s</a>',
588
  (int) $id,
589
  esc_attr( $ewww_manual_nonce ),
590
  esc_html__( 'Restore original', 'ewww-image-optimizer' )
@@ -665,7 +663,9 @@ if ( ! class_exists( 'EWWW_Nextgen' ) ) {
665
  ewww_image_optimizer_cloud_verify( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) );
666
  echo '<span id="ewww-bulk-credits-available">' . esc_html__( 'Image credits available:', 'ewww-image-optimizer' ) . ' ' . wp_kses_post( ewww_image_optimizer_cloud_quota() ) . '</span>';
667
  }
668
- echo '<div id="ewww-bulk-warning" class="ewww-bulk-info notice notice-warning"><p>' . esc_html__( 'Bulk Optimization will alter your original images and cannot be undone. Please be sure you have a backup of your images before proceeding.', 'ewww-image-optimizer' ) . '</p></div>';
 
 
669
  // Retrieve the value of the 'bulk resume' option and set the button text for the form to use.
670
  $resume = get_option( 'ewww_image_optimizer_bulk_ngg_resume' );
671
  if ( empty( $resume ) ) {
41
  ewwwio_debug_message( 'background mode NOT enabled for nextgen' );
42
  }
43
  add_action( 'wp_ajax_ewww_ngg_manual', array( $this, 'ewww_ngg_manual' ) );
44
+ add_action( 'wp_ajax_ewww_ngg_image_restore', array( $this, 'ewww_ngg_image_restore' ) );
45
  add_action( 'admin_action_ewww_ngg_manual', array( $this, 'ewww_ngg_manual' ) );
46
  add_action( 'admin_enqueue_scripts', array( $this, 'ewww_ngg_manual_actions_script' ) );
47
  add_action( 'admin_menu', array( $this, 'ewww_ngg_bulk_menu' ) );
153
  $image_id = $storage->object->_get_image_id( $image );
154
  }
155
  global $ewwwio_ngg2_background;
 
 
 
156
  if ( ! is_object( $ewwwio_ngg2_background ) ) {
157
  $ewwwio_ngg2_background = new EWWWIO_Ngg2_Background_Process();
158
  }
317
  /**
318
  * Restore an image from the NextGEN Gallery.
319
  */
320
+ function ewww_ngg_image_restore() {
321
  ewwwio_debug_message( '<b>' . __METHOD__ . '()</b>' );
322
  // Check permission of current user.
323
  $permissions = apply_filters( 'ewww_image_optimizer_manual_permissions', '' );
351
  $storage = $registry->get_utility( 'I_Gallery_Storage' );
352
  // Get an image object.
353
  $image = $storage->object->_image_mapper->find( $id );
354
+ global $eio_backup;
355
+ $eio_backup->restore_backup_from_meta_data( $image->pid, 'nextgen' );
356
  $success = $this->ewww_manage_image_custom_column( '', $image );
357
  ewwwio_ob_clean();
358
  wp_die( wp_json_encode( array( 'success' => $success ) ) );
526
  }
527
  $backup_available = false;
528
  global $wpdb;
529
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'nextgen' AND image_size <> 0 ORDER BY orig_size DESC", $image->pid ), ARRAY_A );
530
  if ( ! empty( $optimized_images ) ) {
531
  list( $detail_output, $converted, $backup_available ) = ewww_image_optimizer_custom_column_results( $image->pid, $optimized_images );
532
  echo wp_kses_post( $detail_output );
567
  if ( 'optimize' === $id && is_object( $image ) && ! empty( $image->pid ) ) {
568
  $id = $image->pid;
569
  global $wpdb;
570
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'nextgen' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
571
  if ( ! empty( $optimized_images ) ) {
572
  $optimized = true;
573
  }
582
  );
583
  if ( $restorable ) {
584
  printf(
585
+ '<br><a class="ewww-manual-image-restore" data-id="%1$d" data-nonce="%2$s" href="' . esc_url( admin_url( 'admin.php?action=ewww_ngg_image_restore' ) ) . '&amp;ewww_manual_nonce=%2$s&amp;ewww_attachment_ID=%1$d">%3$s</a>',
586
  (int) $id,
587
  esc_attr( $ewww_manual_nonce ),
588
  esc_html__( 'Restore original', 'ewww-image-optimizer' )
663
  ewww_image_optimizer_cloud_verify( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) );
664
  echo '<span id="ewww-bulk-credits-available">' . esc_html__( 'Image credits available:', 'ewww-image-optimizer' ) . ' ' . wp_kses_post( ewww_image_optimizer_cloud_quota() ) . '</span>';
665
  }
666
+ if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
667
+ echo '<div id="ewww-bulk-warning" class="ewww-bulk-info notice notice-warning"><p>' . esc_html__( 'Bulk Optimization will alter your original images and cannot be undone. Please be sure you have a backup of your images before proceeding.', 'ewww-image-optimizer' ) . '</p></div>';
668
+ }
669
  // Retrieve the value of the 'bulk resume' option and set the button text for the form to use.
670
  $resume = get_option( 'ewww_image_optimizer_bulk_ngg_resume' );
671
  if ( empty( $resume ) ) {
classes/class-ewwwio-cli.php CHANGED
@@ -226,6 +226,353 @@ class EWWWIO_CLI extends WP_CLI_Command {
226
  }
227
  } // End switch().
228
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  }
230
 
231
  WP_CLI::add_command( 'ewwwio', 'EWWWIO_CLI' );
226
  }
227
  } // End switch().
228
  }
229
+
230
+ /**
231
+ * Restore images from cloud/local backups.
232
+ *
233
+ * ## OPTIONS
234
+ *
235
+ * <reset>
236
+ * : optional, start the process over instead of resuming from last position
237
+ *
238
+ * ## EXAMPLES
239
+ *
240
+ * wp-cli ewwwio restore --reset
241
+ *
242
+ * @synopsis [--reset]
243
+ *
244
+ * @param array $args A numeric array of required arguments.
245
+ * @param array $assoc_args An associative array of optional arguments.
246
+ */
247
+ function restore( $args, $assoc_args ) {
248
+ if ( ! empty( $assoc_args['reset'] ) ) {
249
+ delete_option( 'ewww_image_optimizer_bulk_restore_position' );
250
+ }
251
+ global $eio_backup;
252
+ global $wpdb;
253
+ if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
254
+ ewww_image_optimizer_db_init();
255
+ global $ewwwdb;
256
+ } else {
257
+ $ewwwdb = $wpdb;
258
+ }
259
+
260
+ $completed = 0;
261
+ $position = (int) get_option( 'ewww_image_optimizer_bulk_restore_position' );
262
+ $per_page = 200;
263
+
264
+ ewwwio_debug_message( "searching for $per_page records starting at $position" );
265
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE id > %d AND pending = 0 AND image_size > 0 AND updates > 0 ORDER BY id LIMIT %d", $position, $per_page ), ARRAY_A );
266
+
267
+ $restorable_images = (int) $wpdb->get_var( $wpdb->prepare( "SELECT count(id) FROM $wpdb->ewwwio_images WHERE id > %d AND pending = 0 AND image_size > 0 AND updates > 0", $position ) );
268
+
269
+ /* translators: %d: number of images */
270
+ WP_CLI::line( sprintf( __( 'There are %d images that may be restored.', 'ewww-image-optimizer' ), $restorable_images ) );
271
+ WP_CLI::confirm( __( 'You should take a site backup before performing a bulk action on your images. Do you wish to continue?', 'ewww-image-optimizer' ) );
272
+
273
+ // Because some plugins might have loose filters (looking at you WPML).
274
+ remove_all_filters( 'wp_delete_file' );
275
+
276
+ while ( ewww_image_optimizer_iterable( $optimized_images ) ) {
277
+ foreach ( $optimized_images as $optimized_image ) {
278
+ $completed++;
279
+ ewwwio_debug_message( "submitting {$optimized_image['id']} to be restored" );
280
+ $optimized_image['path'] = \ewww_image_optimizer_absolutize_path( $optimized_image['path'] );
281
+ $eio_backup->restore_file( $optimized_image );
282
+ $error_message = $eio_backup->get_error();
283
+ if ( $error_message ) {
284
+ WP_CLI::warning( "$completed/$restorable_images: $error_message" );
285
+ } else {
286
+ WP_CLI::success( "$completed/$restorable_images: {$optimized_image['path']}" );
287
+ }
288
+ update_option( 'ewww_image_optimizer_bulk_restore_position', $optimized_image['id'], false );
289
+ } // End foreach().
290
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE id > %d AND pending = 0 AND image_size > 0 AND updates > 0 ORDER BY id LIMIT %d", $optimized_image['id'], $per_page ), ARRAY_A );
291
+ }
292
+
293
+ delete_option( 'ewww_image_optimizer_bulk_restore_position' );
294
+ }
295
+
296
+ /**
297
+ * Remove pre-scaled original size versions of image uploads.
298
+ *
299
+ * ## OPTIONS
300
+ *
301
+ * <reset>
302
+ * : optional, start the process back at the beginning instead of resuming from last position
303
+ *
304
+ * ## EXAMPLES
305
+ *
306
+ * wp-cli ewwwio remove_originals --reset
307
+ *
308
+ * @synopsis [--reset]
309
+ *
310
+ * @param array $args A numeric array of required arguments.
311
+ * @param array $assoc_args An associative array of optional arguments.
312
+ */
313
+ function remove_originals( $args, $assoc_args ) {
314
+ if ( ! empty( $assoc_args['reset'] ) ) {
315
+ delete_option( 'ewww_image_optimizer_delete_originals_resume' );
316
+ }
317
+ global $wpdb;
318
+
319
+ $per_page = 200;
320
+ $position = (int) get_option( 'ewww_image_optimizer_delete_originals_resume' );
321
+
322
+ $cleanable_uploads = (int) $wpdb->get_var(
323
+ $wpdb->prepare(
324
+ "SELECT count(ID) FROM $wpdb->posts WHERE ID > %d AND (post_type = 'attachment' OR post_type = 'ims_image') AND post_mime_type LIKE %s",
325
+ (int) $position,
326
+ '%image%',
327
+ )
328
+ );
329
+
330
+ /* translators: %d: number of image uploads */
331
+ WP_CLI::line( sprintf( __( 'This process removes the originals that WordPress preserves for thumbnail generation. %d media uploads will checked for originals to remove.', 'ewww-image-optimizer' ), $cleanable_uploads ) );
332
+ WP_CLI::confirm( __( 'You should take a site backup before performing a bulk action on your images. Do you wish to continue?', 'ewww-image-optimizer' ) );
333
+
334
+ /**
335
+ * Require the files that contain functions for the images table and bulk processing images outside the library.
336
+ */
337
+ require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'aux-optimize.php' );
338
+
339
+ \ewwwio_debug_message( "searching for $per_page records starting at $position" );
340
+
341
+ $attachments = $wpdb->get_col(
342
+ $wpdb->prepare(
343
+ "SELECT ID FROM $wpdb->posts WHERE ID > %d AND (post_type = 'attachment' OR post_type = 'ims_image') AND post_mime_type LIKE %s ORDER BY ID LIMIT %d",
344
+ (int) $position,
345
+ '%image%',
346
+ (int) $per_page
347
+ )
348
+ );
349
+
350
+ $progress = \WP_CLI\Utils\make_progress_bar( __( 'Deleting originals', 'ewww-image-optimizer' ), $cleanable_uploads );
351
+
352
+ // Because some plugins might have loose filters (looking at you WPML).
353
+ \remove_all_filters( 'wp_delete_file' );
354
+
355
+ while ( \ewww_image_optimizer_iterable( $attachments ) ) {
356
+ foreach ( $attachments as $id ) {
357
+ $new_meta = \ewwwio_remove_original_image( $id );
358
+ if ( \ewww_image_optimizer_iterable( $new_meta ) ) {
359
+ \wp_update_attachment_metadata( $id, $new_meta );
360
+ }
361
+ \update_option( 'ewww_image_optimizer_delete_originals_resume', $id, false );
362
+ $progress->tick();
363
+ }
364
+ $attachments = $wpdb->get_col(
365
+ $wpdb->prepare(
366
+ "SELECT ID FROM $wpdb->posts WHERE ID > %d AND (post_type = 'attachment' OR post_type = 'ims_image') AND post_mime_type LIKE %s ORDER BY ID LIMIT %d",
367
+ (int) $id,
368
+ '%image%',
369
+ (int) $per_page
370
+ )
371
+ );
372
+ }
373
+ $progress->finish();
374
+
375
+ WP_CLI::success( __( 'Finished', 'ewww-image-optimizer' ) );
376
+
377
+ \delete_option( 'ewww_image_optimizer_delete_originals_resume' );
378
+ }
379
+
380
+ /**
381
+ * Remove the original version of converted images.
382
+ *
383
+ * @param array $args A numeric array of required arguments.
384
+ * @param array $assoc_args An associative array of optional arguments.
385
+ */
386
+ function remove_converted_originals( $args, $assoc_args ) {
387
+ if ( ! empty( $assoc_args['reset'] ) ) {
388
+ delete_option( 'ewww_image_optimizer_delete_originals_resume' );
389
+ }
390
+ global $wpdb;
391
+ if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
392
+ ewww_image_optimizer_db_init();
393
+ global $ewwwdb;
394
+ } else {
395
+ $ewwwdb = $wpdb;
396
+ }
397
+
398
+ $per_page = 200;
399
+
400
+ $converted_count = (int) $wpdb->get_var( "SELECT count(id) FROM $wpdb->ewwwio_images WHERE converted != ''" );
401
+
402
+ /* translators: %d: number of converted images */
403
+ WP_CLI::line( sprintf( __( 'This process will remove the originals after you have converted images (PNG to JPG and friends). %d images will checked for originals to remove.', 'ewww-image-optimizer' ), $converted_count ) );
404
+ WP_CLI::confirm( __( 'You should take a site backup before performing a bulk action on your images. Do you wish to continue?', 'ewww-image-optimizer' ) );
405
+
406
+ $converted_images = $wpdb->get_results( $wpdb->prepare( "SELECT path,converted,id FROM $wpdb->ewwwio_images WHERE converted != '' ORDER BY id DESC LIMIT %d", $per_page ), ARRAY_A );
407
+
408
+ $progress = \WP_CLI\Utils\make_progress_bar( __( 'Deleting converted images', 'ewww-image-optimizer' ), $converted_count );
409
+
410
+ // Because some plugins might have loose filters (looking at you WPML).
411
+ \remove_all_filters( 'wp_delete_file' );
412
+
413
+ while ( \ewww_image_optimizer_iterable( $converted_images ) ) {
414
+ foreach ( $converted_images as $optimized_image ) {
415
+ $file = \ewww_image_optimizer_absolutize_path( $optimized_image['converted'] );
416
+ \ewwwio_debug_message( "$file was converted, checking if it still exists" );
417
+ if ( ! \ewww_image_optimizer_stream_wrapped( $file ) && \ewwwio_is_file( $file ) ) {
418
+ \ewwwio_debug_message( "removing original: $file" );
419
+ if ( \ewwwio_delete_file( $file ) ) {
420
+ \ewwwio_debug_message( "removed $file" );
421
+ } else {
422
+ /* translators: %s: file name */
423
+ WP_CLI::warning( sprintf( __( 'Could not delete %s, please remove manually or fix permissions and try again.', 'ewww-image-optimizer' ), $file ) );
424
+ }
425
+ }
426
+ $wpdb->update(
427
+ $wpdb->ewwwio_images,
428
+ array(
429
+ 'converted' => '',
430
+ ),
431
+ array(
432
+ 'id' => $optimized_image['id'],
433
+ )
434
+ );
435
+ $progress->tick();
436
+ } // End foreach().
437
+ $converted_images = $wpdb->get_results( $wpdb->prepare( "SELECT path,converted,id FROM $wpdb->ewwwio_images WHERE converted != '' ORDER BY id DESC LIMIT %d", $per_page ), ARRAY_A );
438
+ }
439
+ $progress->finish();
440
+
441
+ WP_CLI::success( __( 'Finished', 'ewww-image-optimizer' ) );
442
+
443
+ \delete_option( 'ewww_image_optimizer_delete_originals_resume' );
444
+ }
445
+
446
+ /**
447
+ * Remove all WebP images.
448
+ *
449
+ * ## OPTIONS
450
+ *
451
+ * <reset>
452
+ * : optional, start the process back at the beginning instead of resuming from last position
453
+ *
454
+ * ## EXAMPLES
455
+ *
456
+ * wp-cli ewwwio remove_webp --reset
457
+ *
458
+ * @synopsis [--reset]
459
+ *
460
+ * @param array $args A numeric array of required arguments.
461
+ * @param array $assoc_args An associative array of optional arguments.
462
+ */
463
+ function remove_webp( $args, $assoc_args ) {
464
+ if ( ! empty( $assoc_args['reset'] ) ) {
465
+ delete_option( 'ewww_image_optimizer_webp_clean_position' );
466
+ }
467
+ global $wpdb;
468
+ if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
469
+ ewww_image_optimizer_db_init();
470
+ global $ewwwdb;
471
+ } else {
472
+ $ewwwdb = $wpdb;
473
+ }
474
+
475
+ $completed = 0;
476
+ $per_page = 200;
477
+
478
+ $resume = get_option( 'ewww_image_optimizer_webp_clean_position' );
479
+ $position1 = is_array( $resume ) && ! empty( $resume['stage1'] ) ? (int) $resume['stage1'] : 0;
480
+ $position2 = is_array( $resume ) && ! empty( $resume['stage2'] ) ? (int) $resume['stage2'] : 0;
481
+
482
+ $cleanable_uploads = (int) $wpdb->get_var(
483
+ $wpdb->prepare(
484
+ "SELECT count(ID) FROM $wpdb->posts WHERE ID > %d AND (post_type = 'attachment' OR post_type = 'ims_image') AND (post_mime_type LIKE %s OR post_mime_type LIKE %s)",
485
+ (int) $position1,
486
+ '%image%',
487
+ '%pdf%'
488
+ )
489
+ );
490
+ $cleanable_records = (int) $wpdb->get_var(
491
+ $wpdb->prepare(
492
+ "SELECT count(id) FROM $wpdb->ewwwio_images WHERE id > %d AND pending = 0 AND image_size > 0 AND updates > 0",
493
+ $position2
494
+ )
495
+ );
496
+
497
+ /* translators: 1: number of image uploads, 2: number of database records */
498
+ WP_CLI::line( sprintf( __( 'WebP copies of %1$d media uploads will be removed first, then %2$d records in the optimization history will be checked to remove any remaining WebP images.', 'ewww-image-optimizer' ), $cleanable_uploads, $cleanable_records ) );
499
+ WP_CLI::confirm( __( 'You should take a site backup before performing a bulk action on your images. Do you wish to continue?', 'ewww-image-optimizer' ) );
500
+
501
+ /**
502
+ * Require the files that contain functions for the images table and bulk processing images outside the library.
503
+ */
504
+ require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'aux-optimize.php' );
505
+
506
+ ewwwio_debug_message( "searching for $per_page records starting at $position1" );
507
+
508
+ $attachment_ids = $wpdb->get_col(
509
+ $wpdb->prepare(
510
+ "SELECT ID FROM $wpdb->posts WHERE ID > %d AND (post_type = 'attachment' OR post_type = 'ims_image') AND (post_mime_type LIKE %s OR post_mime_type LIKE %s) ORDER BY ID LIMIT %d",
511
+ (int) $position1,
512
+ '%image%',
513
+ '%pdf%',
514
+ (int) $per_page
515
+ )
516
+ );
517
+
518
+ $progress1 = \WP_CLI\Utils\make_progress_bar( __( 'Stage 1:', 'ewww-image-optimizer' ), $cleanable_uploads );
519
+
520
+ // Because some plugins might have loose filters (looking at you WPML).
521
+ \remove_all_filters( 'wp_delete_file' );
522
+
523
+ while ( \ewww_image_optimizer_iterable( $attachment_ids ) ) {
524
+ foreach ( $attachment_ids as $id ) {
525
+ \ewww_image_optimizer_delete_webp( $id );
526
+ $resume['stage1'] = (int) $id;
527
+ \update_option( 'ewww_image_optimizer_webp_clean_position', $resume, false );
528
+ $progress1->tick();
529
+ }
530
+ $attachment_ids = $wpdb->get_col(
531
+ $wpdb->prepare(
532
+ "SELECT ID FROM $wpdb->posts WHERE ID > %d AND (post_type = 'attachment' OR post_type = 'ims_image') AND (post_mime_type LIKE %s OR post_mime_type LIKE %s) ORDER BY ID LIMIT %d",
533
+ (int) $id,
534
+ '%image%',
535
+ '%pdf%',
536
+ (int) $per_page
537
+ )
538
+ );
539
+ }
540
+ $progress1->finish();
541
+
542
+ \ewwwio_debug_message( "searching for $per_page records starting at $position2" );
543
+
544
+ $optimized_images = $wpdb->get_results(
545
+ $wpdb->prepare(
546
+ "SELECT * FROM $wpdb->ewwwio_images WHERE id > %d AND pending = 0 AND image_size > 0 AND updates > 0 ORDER BY id LIMIT %d",
547
+ (int) $position2,
548
+ (int) $per_page
549
+ ),
550
+ ARRAY_A
551
+ );
552
+
553
+ $progress2 = \WP_CLI\Utils\make_progress_bar( __( 'Stage 2:', 'ewww-image-optimizer' ), $cleanable_records );
554
+
555
+ while ( \ewww_image_optimizer_iterable( $optimized_images ) ) {
556
+ foreach ( $optimized_images as $optimized_image ) {
557
+ \ewww_image_optimizer_aux_images_webp_clean( $optimized_image );
558
+ $resume['stage2'] = $optimized_image['id'];
559
+ \update_option( 'ewww_image_optimizer_webp_clean_position', $resume, false );
560
+ $progress2->tick();
561
+ }
562
+ $optimized_images = $wpdb->get_results(
563
+ $wpdb->prepare(
564
+ "SELECT * FROM $wpdb->ewwwio_images WHERE id > %d AND pending = 0 AND image_size > 0 AND updates > 0 ORDER BY id LIMIT %d",
565
+ (int) $optimized_image['id'],
566
+ (int) $per_page
567
+ ),
568
+ ARRAY_A
569
+ );
570
+ }
571
+ $progress2->finish();
572
+ WP_CLI::success( __( 'Finished', 'ewww-image-optimizer' ) );
573
+
574
+ \delete_option( 'ewww_image_optimizer_webp_clean_position' );
575
+ }
576
  }
577
 
578
  WP_CLI::add_command( 'ewwwio', 'EWWWIO_CLI' );
classes/class-ewwwio-gmagick-editor.php CHANGED
@@ -57,27 +57,10 @@ if ( class_exists( 'WP_Image_Editor_Gmagick' ) ) {
57
  $filename = $saved['path'];
58
  }
59
  if ( file_exists( $filename ) ) {
60
- /* if ( ! ewww_image_optimizer_test_background_opt() ) { */
61
- ewww_image_optimizer( $filename );
62
- ewwwio_debug_message( "image editor (gmagick) saved: $filename" );
63
- $image_size = ewww_image_optimizer_filesize( $filename );
64
- ewwwio_debug_message( "image editor size: $image_size" );
65
-
66
- /*
67
- } else {
68
- add_filter( 'http_headers_useragent', 'ewww_image_optimizer_cloud_useragent', PHP_INT_MAX );
69
- global $ewwwio_image_background;
70
- if ( ! class_exists( 'WP_Background_Process' ) ) {
71
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
72
- }
73
- if ( ! is_object( $ewwwio_image_background ) ) {
74
- $ewwwio_image_background = new EWWWIO_Image_Background_Process();
75
- }
76
- $ewwwio_image_background->push_to_queue( $filename );
77
- $ewwwio_image_background->save()->dispatch();
78
- ewwwio_debug_message( "image editor (gmagick) queued: $filename" );
79
- }
80
- */
81
  }
82
  }
83
  ewwwio_memory( __FUNCTION__ );
57
  $filename = $saved['path'];
58
  }
59
  if ( file_exists( $filename ) ) {
60
+ ewww_image_optimizer( $filename );
61
+ ewwwio_debug_message( "image editor (gmagick) saved: $filename" );
62
+ $image_size = ewww_image_optimizer_filesize( $filename );
63
+ ewwwio_debug_message( "image editor size: $image_size" );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
  }
66
  ewwwio_memory( __FUNCTION__ );
classes/class-exactdn.php CHANGED
@@ -24,6 +24,14 @@ if ( ! class_exists( 'ExactDN' ) ) {
24
  */
25
  protected $user_exclusions = array();
26
 
 
 
 
 
 
 
 
 
27
  /**
28
  * A list of image sizes registered for attachments.
29
  *
@@ -230,6 +238,7 @@ if ( ! class_exists( 'ExactDN' ) ) {
230
  // Overrides for admin-ajax images.
231
  add_filter( 'exactdn_admin_allow_image_downsize', array( $this, 'allow_admin_image_downsize' ), 10, 2 );
232
  add_filter( 'exactdn_admin_allow_image_srcset', array( $this, 'allow_admin_image_downsize' ), 10, 2 );
 
233
  // Overrides for "pass through" images.
234
  add_filter( 'exactdn_pre_args', array( $this, 'exactdn_remove_args' ), 10, 3 );
235
  // Overrides for user exclusions.
@@ -823,6 +832,11 @@ if ( ! class_exists( 'ExactDN' ) ) {
823
  if ( ! is_string( $exclusion ) ) {
824
  continue;
825
  }
 
 
 
 
 
826
  if ( $this->content_path && false !== strpos( $exclusion, $this->content_path ) ) {
827
  $exclusion = preg_replace( '#([^"\'?>]+?)?' . $this->content_path . '/#i', '', $exclusion );
828
  }
@@ -3127,6 +3141,18 @@ if ( ! class_exists( 'ExactDN' ) ) {
3127
  * @return boolean True to skip the page, unchanged otherwise.
3128
  */
3129
  function skip_page( $skip = false, $uri = '' ) {
 
 
 
 
 
 
 
 
 
 
 
 
3130
  if ( false !== strpos( $uri, 'bricks=run' ) ) {
3131
  return true;
3132
  }
@@ -3197,6 +3223,9 @@ if ( ! class_exists( 'ExactDN' ) ) {
3197
  if ( is_admin() ) {
3198
  return $url;
3199
  }
 
 
 
3200
  if ( apply_filters( 'exactdn_skip_page', false, $this->request_uri ) ) {
3201
  return $url;
3202
  }
24
  */
25
  protected $user_exclusions = array();
26
 
27
+ /**
28
+ * A list of user-defined page/URL exclusions, populated by validate_user_exclusions().
29
+ *
30
+ * @access protected
31
+ * @var array $user_page_exclusions
32
+ */
33
+ protected $user_page_exclusions = array();
34
+
35
  /**
36
  * A list of image sizes registered for attachments.
37
  *
238
  // Overrides for admin-ajax images.
239
  add_filter( 'exactdn_admin_allow_image_downsize', array( $this, 'allow_admin_image_downsize' ), 10, 2 );
240
  add_filter( 'exactdn_admin_allow_image_srcset', array( $this, 'allow_admin_image_downsize' ), 10, 2 );
241
+ add_filter( 'exactdn_admin_allow_plugin_url', array( $this, 'allow_admin_image_downsize' ), 10, 2 );
242
  // Overrides for "pass through" images.
243
  add_filter( 'exactdn_pre_args', array( $this, 'exactdn_remove_args' ), 10, 3 );
244
  // Overrides for user exclusions.
832
  if ( ! is_string( $exclusion ) ) {
833
  continue;
834
  }
835
+ $exclusion = trim( $exclusion );
836
+ if ( 0 === strpos( $exclusion, 'page:' ) ) {
837
+ $this->user_page_exclusions[] = str_replace( 'page:', '', $exclusion );
838
+ continue;
839
+ }
840
  if ( $this->content_path && false !== strpos( $exclusion, $this->content_path ) ) {
841
  $exclusion = preg_replace( '#([^"\'?>]+?)?' . $this->content_path . '/#i', '', $exclusion );
842
  }
3141
  * @return boolean True to skip the page, unchanged otherwise.
3142
  */
3143
  function skip_page( $skip = false, $uri = '' ) {
3144
+ if ( $this->is_iterable( $this->user_page_exclusions ) ) {
3145
+ foreach ( $this->user_page_exclusions as $page_exclusion ) {
3146
+ if ( '/' === $page_exclusion && '/' === $uri ) {
3147
+ return true;
3148
+ } elseif ( '/' === $page_exclusion ) {
3149
+ continue;
3150
+ }
3151
+ if ( false !== strpos( $uri, $page_exclusion ) ) {
3152
+ return true;
3153
+ }
3154
+ }
3155
+ }
3156
  if ( false !== strpos( $uri, 'bricks=run' ) ) {
3157
  return true;
3158
  }
3223
  if ( is_admin() ) {
3224
  return $url;
3225
  }
3226
+ if ( function_exists( 'affwp_is_affiliate_portal' ) && affwp_is_affiliate_portal() ) {
3227
+ return $url;
3228
+ }
3229
  if ( apply_filters( 'exactdn_skip_page', false, $this->request_uri ) ) {
3230
  return $url;
3231
  }
common.php CHANGED
@@ -2,9 +2,8 @@
2
  /**
3
  * Common functions for Standard and Cloud plugins
4
  *
5
- * This file contains functions that are shared by both the regular EWWW IO plugin, and the
6
- * Cloud version. Functions that differ between the two are stored in the main
7
- * ewww-image-optimizer(-cloud).php file.
8
  *
9
  * @link https://ewww.io
10
  * @package EWWW_Image_Optimizer
@@ -14,7 +13,7 @@ if ( ! defined( 'ABSPATH' ) ) {
14
  exit;
15
  }
16
 
17
- define( 'EWWW_IMAGE_OPTIMIZER_VERSION', 670 );
18
 
19
  // Initialize a couple globals.
20
  $eio_debug = '';
@@ -88,7 +87,10 @@ if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_noauto' ) ) {
88
  add_filter( 'crop_thumbnails_before_update_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15, 2 );
89
  // Process BuddyPress uploads from Vikinger theme.
90
  add_action( 'vikinger_file_uploaded', 'ewww_image_optimizer' );
 
 
91
  }
 
92
  // Ensures we update the filesize data in the meta.
93
  // add_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_update_filesize_metadata', 9, 2 );
94
  // Skips resizing for images with 'noresize' in the filename.
@@ -110,6 +112,8 @@ add_filter( 'plugin_action_links_' . EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE_REL, 'ewww
110
  add_filter( 'intermediate_image_sizes_advanced', 'ewww_image_optimizer_image_sizes_advanced' );
111
  // Ditto for PDF files (or anything non-image).
112
  add_filter( 'fallback_intermediate_image_sizes', 'ewww_image_optimizer_fallback_sizes' );
 
 
113
  // Processes screenshots imported with MyArcadePlugin.
114
  add_filter( 'myarcade_filter_screenshot', 'ewww_image_optimizer_myarcade_thumbnail' );
115
  // Processes thumbnails created by MyArcadePlugin.
@@ -139,7 +143,7 @@ add_action( 'admin_action_ewww_image_optimizer_manual_optimize', 'ewww_image_opt
139
  // Legacy (non-AJAX) action hook for manually restoring a converted image.
140
  add_action( 'admin_action_ewww_image_optimizer_manual_restore', 'ewww_image_optimizer_manual' );
141
  // Legacy (non-AJAX) action hook for manually restoring a backup from the API.
142
- add_action( 'admin_action_ewww_image_optimizer_manual_cloud_restore', 'ewww_image_optimizer_manual' );
143
  // Cleanup routine when an attachment is deleted.
144
  add_action( 'delete_attachment', 'ewww_image_optimizer_delete' );
145
  // Cleanup db records when Enable Media Replace replaces a file.
@@ -180,10 +184,8 @@ add_action( 'wp_ajax_ewww_webp_unwrite', 'ewww_image_optimizer_webp_unwrite' );
180
  add_action( 'wp_ajax_ewww_manual_optimize', 'ewww_image_optimizer_manual' );
181
  // AJAX action hook for manually restoring a converted image.
182
  add_action( 'wp_ajax_ewww_manual_restore', 'ewww_image_optimizer_manual' );
183
- // AJAX action hook for manually restoring an attachment from backups on the API.
184
- add_action( 'wp_ajax_ewww_manual_cloud_restore', 'ewww_image_optimizer_manual' );
185
- // AJAX action hook for manually restoring a single image backup from the API.
186
- add_action( 'wp_ajax_ewww_manual_cloud_restore_single', 'ewww_image_optimizer_cloud_restore_single_image_handler' );
187
  // AJAX action hook to dismiss the WooCommerce regen notice.
188
  add_action( 'wp_ajax_ewww_dismiss_wc_regen', 'ewww_image_optimizer_dismiss_wc_regen' );
189
  // AJAX action hook to dismiss the WP/LR Sync regen notice.
@@ -237,9 +239,6 @@ if ( defined( 'WP_CLI' ) && WP_CLI ) {
237
  if ( 'done' !== get_option( 'ewww_image_optimizer_relative_migration_status' ) ) {
238
  require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-relative-migration.php' );
239
  }
240
- if ( defined( 'EWWW_IMAGE_OPTIMIZER_ALT_WEBP' ) && EWWW_IMAGE_OPTIMIZER_ALT_WEBP ) {
241
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-eio-alt-webp-weglot-alt.php' );
242
- }
243
 
244
  /**
245
  * Setup page parsing classes after theme functions.php is loaded and plugins have run init routines.
@@ -291,17 +290,10 @@ function ewww_image_optimizer_parser_init() {
291
  * Page Parsing class for working with HTML content.
292
  */
293
  require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-eio-page-parser.php' );
294
- if ( defined( 'EWWW_IMAGE_OPTIMIZER_ALT_WEBP' ) && EWWW_IMAGE_OPTIMIZER_ALT_WEBP ) {
295
- /**
296
- * Alt WebP class for parsing image urls and rewriting them for WebP support.
297
- */
298
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-eio-alt-webp.php' );
299
- } else {
300
- /**
301
- * JS WebP class for parsing image urls and rewriting them for WebP support.
302
- */
303
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-eio-js-webp.php' );
304
- }
305
  }
306
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_picture_webp' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) {
307
  $buffer_start = true;
@@ -697,7 +689,7 @@ function ewww_image_optimizer_save_network_settings() {
697
  update_site_option( 'ewww_image_optimizer_avif_quality', ewww_image_optimizer_avif_quality( $ewww_image_optimizer_avif_quality ) );
698
  $ewww_image_optimizer_disable_convert_links = ( empty( $_POST['ewww_image_optimizer_disable_convert_links'] ) ? false : true );
699
  update_site_option( 'ewww_image_optimizer_disable_convert_links', $ewww_image_optimizer_disable_convert_links );
700
- $ewww_image_optimizer_backup_files = ( empty( $_POST['ewww_image_optimizer_backup_files'] ) ? false : true );
701
  update_site_option( 'ewww_image_optimizer_backup_files', $ewww_image_optimizer_backup_files );
702
  $ewww_image_optimizer_auto = ( empty( $_POST['ewww_image_optimizer_auto'] ) ? false : true );
703
  update_site_option( 'ewww_image_optimizer_auto', $ewww_image_optimizer_auto );
@@ -800,6 +792,10 @@ function ewww_image_optimizer_save_network_settings() {
800
  */
801
  function ewww_image_optimizer_init() {
802
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
 
 
 
 
803
 
804
  // Check to see if this is the settings page and enable debugging temporarily if it is.
805
  global $ewwwio_temp_debug;
@@ -956,6 +952,15 @@ function ewww_image_optimizer_upgrade() {
956
  ) {
957
  ewww_image_optimizer_set_option( 'exactdn_lossy', true );
958
  }
 
 
 
 
 
 
 
 
 
959
  if ( get_option( 'ewww_image_optimizer_version' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_review_time' ) ) {
960
  $review_time = rand( time(), time() + 51 * DAY_IN_SECONDS );
961
  add_option( 'ewww_image_optimizer_review_time', $review_time, '', false );
@@ -969,15 +974,6 @@ function ewww_image_optimizer_upgrade() {
969
  add_option( 'ewww_image_optimizer_wizard_complete', true, '', false );
970
  add_site_option( 'ewww_image_optimizer_wizard_complete', true );
971
  }
972
- if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) {
973
- if ( 'external' === get_option( 'elementor_css_print_method' ) ) {
974
- update_option( 'elementor_css_print_method', 'internal' );
975
- }
976
- if ( function_exists( 'et_get_option' ) && function_exists( 'et_update_option' ) && 'on' === et_get_option( 'et_pb_static_css_file', 'on' ) ) {
977
- et_update_option( 'et_pb_static_css_file', 'off' );
978
- et_update_option( 'et_pb_css_in_footer', 'off' );
979
- }
980
- }
981
  ewww_image_optimizer_remove_obsolete_settings();
982
  update_option( 'ewww_image_optimizer_version', EWWW_IMAGE_OPTIMIZER_VERSION );
983
  }
@@ -997,9 +993,6 @@ function ewww_image_optimizer_enable_background_optimization() {
997
  return;
998
  }
999
  global $ewwwio_test_async;
1000
- if ( ! class_exists( 'WP_Background_Process' ) ) {
1001
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
1002
- }
1003
  if ( ! is_object( $ewwwio_test_async ) ) {
1004
  $ewwwio_test_async = new EWWWIO_Test_Async_Handler();
1005
  }
@@ -1079,7 +1072,7 @@ function ewww_image_optimizer_admin_init() {
1079
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_gif_level', 'intval' );
1080
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_pdf_level', 'intval' );
1081
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_svg_level', 'intval' );
1082
- register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_backup_files', 'boolval' );
1083
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_enable_cloudinary', 'boolval' );
1084
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_sharpen', 'boolval' );
1085
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_jpg_quality', 'ewww_image_optimizer_jpg_quality' );
@@ -1940,9 +1933,6 @@ function ewww_image_optimizer_remove_obsolete_settings() {
1940
  function ewww_image_optimizer_migrate_option_queue_to_table() {
1941
  global $wpdb;
1942
  global $ewwwio_media_background;
1943
- if ( ! class_exists( 'WP_Background_Process' ) ) {
1944
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
1945
- }
1946
  if ( ! is_object( $ewwwio_media_background ) ) {
1947
  $ewwwio_media_background = new EWWWIO_Media_Background_Process();
1948
  }
@@ -2000,9 +1990,6 @@ function ewww_image_optimizer_webp_maybe_enabled( $old_value, $new_value ) {
2000
  function ewww_image_optimizer_scheduled_optimization_changed( $old_value, $new_value ) {
2001
  if ( empty( $new_value ) && (bool) $new_value !== (bool) $old_value ) {
2002
  global $ewwwio_image_background;
2003
- if ( ! class_exists( 'WP_Background_Process' ) ) {
2004
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
2005
- }
2006
  $ewwwio_image_background->cancel_process();
2007
  update_option( 'ewwwio_stop_scheduled_scan', true, false );
2008
  }
@@ -3019,9 +3006,6 @@ function ewww_image_optimizer_auto() {
3019
  ewwwio_debug_message( 'detected bulk operation in progress, bailing' );
3020
  return;
3021
  }
3022
- if ( ! class_exists( 'WP_Background_Process' ) ) {
3023
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
3024
- }
3025
  global $ewww_defer;
3026
  $ewww_defer = false;
3027
  require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'bulk.php' );
@@ -4062,6 +4046,7 @@ function ewwwio_is_readable( $file ) {
4062
  ewwwio_get_filesystem();
4063
  return $eio_filesystem->is_readable( $file );
4064
  }
 
4065
  /**
4066
  * Check if directory exists, and that it is local rather than using a protocol like http:// or phar://
4067
  *
@@ -4309,8 +4294,9 @@ function ewww_image_optimizer_manual() {
4309
  $new_meta = ewww_image_optimizer_resize_from_meta_data( $original_meta, $attachment_id );
4310
  } elseif ( 'ewww_image_optimizer_manual_restore' === $_REQUEST['action'] || 'ewww_manual_restore' === $_REQUEST['action'] ) {
4311
  $new_meta = ewww_image_optimizer_restore_from_meta_data( $original_meta, $attachment_id );
4312
- } elseif ( 'ewww_image_optimizer_manual_cloud_restore' === $_REQUEST['action'] || 'ewww_manual_cloud_restore' === $_REQUEST['action'] ) {
4313
- $new_meta = ewww_image_optimizer_cloud_restore_from_meta_data( $attachment_id, 'media', $original_meta );
 
4314
  } else {
4315
  if ( ! wp_doing_ajax() ) {
4316
  wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) );
@@ -4489,11 +4475,12 @@ function ewww_image_optimizer_cloud_restore_single_image_handler() {
4489
  * @global object $wpdb
4490
  * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity.
4491
  *
4492
- * @param string $image The filename of the image to restore.
4493
  * @return bool True if the image was restored successfully.
4494
  */
4495
  function ewww_image_optimizer_cloud_restore_single_image( $image ) {
4496
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
 
4497
  global $wpdb;
4498
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
4499
  ewww_image_optimizer_db_init();
@@ -4530,6 +4517,8 @@ function ewww_image_optimizer_cloud_restore_single_image( $image ) {
4530
  $error_message = $result->get_error_message();
4531
  ewwwio_debug_message( "restore request failed: $error_message" );
4532
  ewwwio_memory( __FUNCTION__ );
 
 
4533
  return false;
4534
  } elseif ( ! empty( $result['body'] ) && strpos( $result['body'], 'missing' ) === false ) {
4535
  $enabled_types = array( 'image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'image/svg+xml' );
@@ -4543,10 +4532,13 @@ function ewww_image_optimizer_cloud_restore_single_image( $image ) {
4543
  $old_type = ewww_image_optimizer_mimetype( $image['path'], 'i' );
4544
  }
4545
  if ( ! in_array( $new_type, $enabled_types, true ) ) {
 
 
4546
  return false;
4547
  }
4548
  if ( empty( $old_type ) || $old_type === $new_type ) {
4549
  if ( ewwwio_rename( $image['path'] . '.tmp', $image['path'] ) ) {
 
4550
  if ( ewwwio_is_file( $image['path'] . '.webp' ) && is_writable( $image['path'] . '.webp' ) ) {
4551
  unlink( $image['path'] . '.webp' );
4552
  }
@@ -4556,6 +4548,8 @@ function ewww_image_optimizer_cloud_restore_single_image( $image ) {
4556
  }
4557
  }
4558
  }
 
 
4559
  return false;
4560
  }
4561
 
@@ -4571,6 +4565,7 @@ function ewww_image_optimizer_cloud_restore_single_image( $image ) {
4571
  */
4572
  function ewww_image_optimizer_delete( $id ) {
4573
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
 
4574
  global $wpdb;
4575
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
4576
  ewww_image_optimizer_db_init();
@@ -4601,9 +4596,11 @@ function ewww_image_optimizer_delete( $id ) {
4601
  ewwwio_debug_message( 'removing: ' . $webpfileold );
4602
  ewwwio_delete_file( $webpfileold );
4603
  }
 
4604
  }
4605
  if ( ! empty( $image['converted'] ) ) {
4606
  $image['converted'] = ewww_image_optimizer_absolutize_path( $image['converted'] );
 
4607
  }
4608
  if ( ! empty( $image['converted'] ) && ewwwio_is_file( $image['converted'] ) ) {
4609
  ewwwio_debug_message( 'removing: ' . $image['converted'] );
@@ -4653,6 +4650,7 @@ function ewww_image_optimizer_delete( $id ) {
4653
  if ( ewwwio_is_file( $file_path ) && empty( $rows ) ) {
4654
  ewwwio_debug_message( 'removing: ' . $file_path );
4655
  ewwwio_delete_file( $file_path );
 
4656
  $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $file_path ) ) );
4657
  }
4658
  }
@@ -4673,6 +4671,7 @@ function ewww_image_optimizer_delete( $id ) {
4673
  ewwwio_debug_message( 'removing: ' . $s3_dir . wp_basename( $meta['original_image'] ) . '.webp' );
4674
  unlink( $s3_dir . wp_basename( $meta['original_image'] ) . '.webp' );
4675
  }
 
4676
  $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $orig_path ) ) );
4677
  }
4678
  // Remove the regular image from the ewwwio_images tables.
@@ -4697,6 +4696,7 @@ function ewww_image_optimizer_delete( $id ) {
4697
  ewwwio_debug_message( 'removing: ' . $s3_dir . wp_basename( $data['file'] ) . '.webp' );
4698
  unlink( $s3_dir . wp_basename( $data['file'] ) . '.webp' );
4699
  }
 
4700
  $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $base_dir . $data['file'] ) ) );
4701
  // If the original resize is set, and still exists.
4702
  if ( ! empty( $data['orig_file'] ) && ewwwio_is_file( $base_dir . $data['orig_file'] ) ) {
@@ -4710,6 +4710,7 @@ function ewww_image_optimizer_delete( $id ) {
4710
  if ( empty( $srows ) ) {
4711
  ewwwio_debug_message( 'removing: ' . $base_dir . $data['orig_file'] );
4712
  ewwwio_delete_file( $base_dir . $data['orig_file'] );
 
4713
  $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $base_dir . $data['orig_file'] ) ) );
4714
  }
4715
  }
@@ -4724,6 +4725,7 @@ function ewww_image_optimizer_delete( $id ) {
4724
  ewwwio_debug_message( 'removing: ' . $webpfileold );
4725
  ewwwio_delete_file( $webpfileold );
4726
  }
 
4727
  }
4728
 
4729
  /**
@@ -4739,6 +4741,7 @@ function ewww_image_optimizer_delete( $id ) {
4739
  */
4740
  function ewww_image_optimizer_file_deleted( $id, $file ) {
4741
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
 
4742
  global $wpdb;
4743
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
4744
  ewww_image_optimizer_db_init();
@@ -4768,12 +4771,14 @@ function ewww_image_optimizer_file_deleted( $id, $file ) {
4768
  ewwwio_delete_file( $image['converted'] . '.webp' );
4769
  }
4770
  }
 
4771
  $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'id' => $image['id'] ) );
4772
  }
4773
  }
4774
  if ( ewwwio_is_file( $file . '.webp' ) ) {
4775
  ewwwio_delete_file( $file . '.webp' );
4776
  }
 
4777
  }
4778
 
4779
  /**
@@ -5440,7 +5445,9 @@ function ewww_image_optimizer_cloud_enable() {
5440
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_gif_level', 10 );
5441
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_pdf_level', 10 );
5442
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_svg_level', 10 );
5443
- ewww_image_optimizer_set_option( 'ewww_image_optimizer_backup_files', 1 );
 
 
5444
  }
5445
 
5446
  /**
@@ -5481,8 +5488,10 @@ function ewww_image_optimizer_cloud_verify( $api_key, $cache = true ) {
5481
  update_site_option( 'ewww_image_optimizer_pdf_level', 0 );
5482
  update_option( 'ewww_image_optimizer_pdf_level', 0 );
5483
  }
5484
- update_site_option( 'ewww_image_optimizer_backup_files', '' );
5485
- update_option( 'ewww_image_optimizer_backup_files', '' );
 
 
5486
  return false;
5487
  }
5488
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_exceeded' ) > time() ) {
@@ -5494,9 +5503,6 @@ function ewww_image_optimizer_cloud_verify( $api_key, $cache = true ) {
5494
  if ( ! ewww_image_optimizer_detect_wpsf_location_lock() && $cache && preg_match( '/great/', $ewww_cloud_status ) ) {
5495
  ewwwio_debug_message( 'using cached verification' );
5496
  global $ewwwio_async_key_verification;
5497
- if ( ! class_exists( 'WP_Background_Process' ) ) {
5498
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
5499
- }
5500
  if ( ! is_object( $ewwwio_async_key_verification ) ) {
5501
  $ewwwio_async_key_verification = new EWWWIO_Async_Key_Verification();
5502
  }
@@ -5787,14 +5793,23 @@ function ewww_image_optimizer_cloud_optimizer( $file, $type, $convert = false, $
5787
  if ( 'image/png' === $type && 30 === (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_level' ) ) {
5788
  $png_compress = 1;
5789
  }
5790
- if ( ! $webp && ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' )
5791
- && strpos( $file, '/wp-admin/' ) === false
5792
- && strpos( $file, '/wp-includes/' ) === false
5793
- && strpos( $file, '/wp-content/themes/' ) === false
5794
- && strpos( $file, '/wp-content/plugins/' ) === false
5795
- && strpos( $file, '/cache/' ) === false
5796
- && strpos( $file, '/dynamic/' ) === false // Nextgen dynamic images.
5797
- ) {
 
 
 
 
 
 
 
 
 
5798
  global $ewww_image;
5799
  if ( is_object( $ewww_image ) && $ewww_image->file === $file && ! empty( $ewww_image->backup ) ) {
5800
  $hash = $ewww_image->backup;
@@ -6080,7 +6095,7 @@ function ewww_image_optimizer_cloud_backup( $file ) {
6080
  if ( empty( $api_key ) ) {
6081
  return false;
6082
  }
6083
- if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
6084
  return false;
6085
  }
6086
  if ( ! ewwwio_is_file( $file ) || ! ewwwio_is_readable( $file ) ) {
@@ -7998,8 +8013,10 @@ function ewww_image_optimizer_resize_upload( $file ) {
7998
  }
7999
  $new_jpeg->saveFile( $new_file );
8000
  }
8001
- // backup the file to the API, right before we replace the original.
8002
- ewww_image_optimizer_cloud_backup( $file );
 
 
8003
  $new_type = (string) ewww_image_optimizer_mimetype( $new_file, 'i' );
8004
  if ( $type === $new_type ) {
8005
  ewwwio_rename( $new_file, $file );
@@ -8136,7 +8153,7 @@ function ewww_image_optimizer_attachment_check_variant_level( $id, $type, $meta
8136
  if ( empty( $ewww_force ) ) {
8137
  return $meta;
8138
  }
8139
- if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) || ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
8140
  return $meta;
8141
  }
8142
  if ( 'image/jpeg' === $type && (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_level' ) > 20 ) {
@@ -8151,12 +8168,12 @@ function ewww_image_optimizer_attachment_check_variant_level( $id, $type, $meta
8151
  $compression_level = ewww_image_optimizer_get_level( $type );
8152
  // Retrieve any records for this image.
8153
  global $wpdb;
8154
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT image_size,orig_size,resize,level,backup,updated FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
8155
  foreach ( $optimized_images as $optimized_image ) {
8156
  if ( 'full' === $optimized_image['resize'] && $compression_level < $optimized_image['level'] ) {
8157
- $updated_time = strtotime( $optimized_image['updated'] );
8158
- if ( DAY_IN_SECONDS * 30 + $updated_time > time() ) {
8159
- return ewww_image_optimizer_cloud_restore_from_meta_data( $id, 'media', $meta );
8160
  }
8161
  }
8162
  }
@@ -8570,9 +8587,6 @@ function ewww_image_optimizer_resize_from_meta_data( $meta, $id = null, $log = t
8570
  add_filter( 'as3cf_pre_update_attachment_metadata', '__return_true' );
8571
  }
8572
  global $ewwwio_media_background;
8573
- if ( ! class_exists( 'WP_Background_Process' ) ) {
8574
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
8575
- }
8576
  if ( ! is_object( $ewwwio_media_background ) ) {
8577
  $ewwwio_media_background = new EWWWIO_Media_Background_Process();
8578
  }
@@ -8619,9 +8633,6 @@ function ewww_image_optimizer_resize_from_meta_data( $meta, $id = null, $log = t
8619
  add_filter( 'http_headers_useragent', 'ewww_image_optimizer_cloud_useragent', PHP_INT_MAX );
8620
  $parallel_sizes['full'] = $file_path;
8621
  global $ewwwio_async_optimize_media;
8622
- if ( ! class_exists( 'WP_Background_Process' ) ) {
8623
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
8624
- }
8625
  if ( ! is_object( $ewwwio_async_optimize_media ) ) {
8626
  $ewwwio_async_optimize_media = new EWWWIO_Async_Request();
8627
  }
@@ -8833,9 +8844,6 @@ function ewww_image_optimizer_resize_from_meta_data( $meta, $id = null, $log = t
8833
  $timer_max = (int) apply_filters( 'ewww_image_optimizer_background_timer_max', 20 );
8834
  $processing_sizes = array();
8835
  global $ewwwio_async_optimize_media;
8836
- if ( ! class_exists( 'WP_Background_Process' ) ) {
8837
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
8838
- }
8839
  if ( ! is_object( $ewwwio_async_optimize_media ) ) {
8840
  $ewwwio_async_optimize_media = new EWWWIO_Async_Request();
8841
  }
@@ -8986,6 +8994,27 @@ function ewww_image_optimizer_resize_from_meta_data( $meta, $id = null, $log = t
8986
  return $meta;
8987
  }
8988
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8989
  /**
8990
  * Only runs during WP/LR Sync to check if an attachment has been updated.
8991
  *
@@ -9025,7 +9054,7 @@ function ewww_image_optimizer_lr_sync_update( $id ) {
9025
 
9026
  // Get a list of all the image files optimized for this attachment.
9027
  global $wpdb;
9028
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT id,path,image_size FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
9029
  if ( ewww_image_optimizer_iterable( $optimized_images ) ) {
9030
  foreach ( $optimized_images as $optimized_image ) {
9031
  $image_path = ewww_image_optimizer_absolutize_path( $optimized_image['path'] );
@@ -10012,13 +10041,13 @@ function ewww_image_optimizer_custom_column( $column_name, $id, $meta = null ) {
10012
  $in_progress = true;
10013
  }
10014
  if ( ! $in_progress ) {
10015
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT image_size,orig_size,resize,converted,level,backup,updated FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
10016
  if ( ! $optimized_images ) {
10017
  // Attempt migration, but only if the original image is in the db, $migrated will be metadata on success, false on failure.
10018
  $migrated = ewww_image_optimizer_migrate_meta_to_db( $id, $meta, true );
10019
  }
10020
  if ( $migrated ) {
10021
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT image_size,orig_size,resize,converted,level,backup,updated FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
10022
  }
10023
  if ( ! $optimized_images ) {
10024
  list( $possible_action_id, $optimized_images ) = ewww_image_optimizer_get_wpml_results( $id );
@@ -10046,10 +10075,10 @@ function ewww_image_optimizer_custom_column( $column_name, $id, $meta = null ) {
10046
  }
10047
  if ( $backup_available && current_user_can( apply_filters( 'ewww_image_optimizer_manual_permissions', '' ) ) ) {
10048
  echo '<div>' . sprintf(
10049
- '<a class="ewww-manual-cloud-restore" data-id="%1$d" data-nonce="%2$s" href="%3$s">%4$s</a>',
10050
  (int) $action_id,
10051
  esc_attr( $ewww_manual_nonce ),
10052
- esc_url( admin_url( "admin.php?action=ewww_image_optimizer_manual_cloud_restore&ewww_manual_nonce=$ewww_manual_nonce&ewww_attachment_ID=$action_id" ) ),
10053
  esc_html__( 'Restore original', 'ewww-image-optimizer' )
10054
  ) . '</div>';
10055
  }
@@ -10090,13 +10119,13 @@ function ewww_image_optimizer_custom_column( $column_name, $id, $meta = null ) {
10090
  $in_progress = true;
10091
  }
10092
  if ( ! $in_progress ) {
10093
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT image_size,orig_size,resize,converted,level,backup,updated FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
10094
  if ( ! $optimized_images ) {
10095
  // Attempt migration, but only if the original image is in the db, $migrated will be metadata on success, false on failure.
10096
  $migrated = ewww_image_optimizer_migrate_meta_to_db( $id, $meta, true );
10097
  }
10098
  if ( $migrated ) {
10099
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT image_size,orig_size,resize,converted,level,backup,updated FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
10100
  }
10101
  if ( ! $optimized_images ) {
10102
  list( $possible_action_id, $optimized_images ) = ewww_image_optimizer_get_wpml_results( $id );
@@ -10162,10 +10191,10 @@ function ewww_image_optimizer_custom_column( $column_name, $id, $meta = null ) {
10162
  ) . '</div>';
10163
  } elseif ( $backup_available && current_user_can( apply_filters( 'ewww_image_optimizer_manual_permissions', '' ) ) ) {
10164
  echo '<div>' . sprintf(
10165
- '<a class="ewww-manual-cloud-restore" data-id="%1$d" data-nonce="%2$s" href="%3$s">%4$s</a>',
10166
  (int) $action_id,
10167
  esc_attr( $ewww_manual_nonce ),
10168
- esc_url( admin_url( "admin.php?action=ewww_image_optimizer_manual_cloud_restore&ewww_manual_nonce=$ewww_manual_nonce&ewww_attachment_ID=$action_id" ) ),
10169
  esc_html__( 'Restore original', 'ewww-image-optimizer' )
10170
  ) . '</div>';
10171
  }
@@ -10241,7 +10270,7 @@ function ewww_image_optimizer_restore_possible( $optimized_images, $compression_
10241
  if ( empty( $compression_level ) ) {
10242
  return '';
10243
  }
10244
- if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) ) {
10245
  return '';
10246
  }
10247
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
@@ -10249,10 +10278,8 @@ function ewww_image_optimizer_restore_possible( $optimized_images, $compression_
10249
  if ( 'full' === $optimized_image['resize'] ) {
10250
  ewwwio_debug_message( "comparing $compression_level (current) vs. {$optimized_image['level']} (previous)" );
10251
  if ( $compression_level < 30 && $compression_level < $optimized_image['level'] && $optimized_image['level'] > 20 ) {
10252
- $updated_time = strtotime( $optimized_image['updated'] );
10253
- if ( DAY_IN_SECONDS * 30 + $updated_time > time() ) {
10254
- return true;
10255
- }
10256
  }
10257
  }
10258
  }
@@ -10362,11 +10389,8 @@ function ewww_image_optimizer_custom_column_results( $id, $optimized_images ) {
10362
  $opt_size += $optimized_image['image_size'];
10363
  if ( 'full' === $optimized_image['resize'] ) {
10364
  $updated_time = strtotime( $optimized_image['updated'] );
10365
- if ( DAY_IN_SECONDS * 30 + $updated_time > time() ) {
10366
- $backup_available = $optimized_image['backup'];
10367
- } else {
10368
- $backup_available = '';
10369
- }
10370
  }
10371
  if ( ! empty( $optimized_image['converted'] ) ) {
10372
  $converted = ewww_image_optimizer_absolutize_path( $optimized_image['converted'] );
@@ -10459,7 +10483,7 @@ function ewww_image_optimizer_get_wpml_results( $id ) {
10459
  continue;
10460
  }
10461
  ewwwio_debug_message( "checking {$translation->element_id} for results with WPML" );
10462
- $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT image_size,orig_size,resize,converted,level,backup,updated FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $translation->element_id ), ARRAY_A );
10463
  if ( ! empty( $optimized_images ) ) {
10464
  return array( (int) $translation->element_id, $optimized_images );
10465
  }
@@ -11596,7 +11620,7 @@ function ewwwio_debug_info() {
11596
  ewwwio_debug_message( 'pdf level: ' . ewww_image_optimizer_get_option( 'ewww_image_optimizer_pdf_level' ) );
11597
  ewwwio_debug_message( 'svg level: ' . ewww_image_optimizer_get_option( 'ewww_image_optimizer_svg_level' ) );
11598
  ewwwio_debug_message( 'bulk delay: ' . ewww_image_optimizer_get_option( 'ewww_image_optimizer_delay' ) );
11599
- ewwwio_debug_message( 'backup mode: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ? 'on' : 'off' ) );
11600
  ewwwio_debug_message( 'cloudinary upload: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_cloudinary' ) ? 'on' : 'off' ) );
11601
  ewwwio_debug_message( 'ExactDN enabled: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ? 'on' : 'off' ) );
11602
  ewwwio_debug_message( 'ExactDN all the things: ' . ( ewww_image_optimizer_get_option( 'exactdn_all_the_things' ) ? 'on' : 'off' ) );
@@ -11777,6 +11801,7 @@ function ewww_image_optimizer_intro_wizard() {
11777
  $webp_available = ewww_image_optimizer_webp_available();
11778
  $bulk_available = false;
11779
  $tools_available = true;
 
11780
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_NOEXEC' ) ) {
11781
  if ( defined( 'EWWW_IMAGE_OPTIMIZER_CLOUD' ) && EWWW_IMAGE_OPTIMIZER_CLOUD ) {
11782
  ewww_image_optimizer_disable_tools();
@@ -11845,15 +11870,21 @@ function ewww_image_optimizer_intro_wizard() {
11845
  if ( ! empty( $_POST['ewwwio_wizard_step'] ) ) {
11846
  $wizard_step = (int) $_POST['ewwwio_wizard_step'];
11847
  }
11848
- if ( ! empty( $_POST['ewww_image_optimizer_goal_save_space'] ) ) {
11849
- update_option( 'ewww_image_optimizer_goal_save_space', true, false );
11850
- } else {
11851
- update_option( 'ewww_image_optimizer_goal_save_space', false, false );
11852
- }
11853
- if ( ! empty( $_POST['ewww_image_optimizer_goal_site_speed'] ) ) {
11854
- update_option( 'ewww_image_optimizer_goal_site_speed', true, false );
11855
- } else {
11856
- update_option( 'ewww_image_optimizer_goal_site_speed', false, false );
 
 
 
 
 
 
11857
  }
11858
  if ( ! empty( $_POST['ewww_image_optimizer_budget'] ) && 'free' === $_POST['ewww_image_optimizer_budget'] ) {
11859
  if ( $display_exec_notice ) {
@@ -11884,6 +11915,11 @@ function ewww_image_optimizer_intro_wizard() {
11884
  }
11885
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_enable_help', ! empty( $_POST['ewww_image_optimizer_enable_help'] ) );
11886
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_allow_tracking', ! empty( $_POST['ewww_image_optimizer_allow_tracking'] ) );
 
 
 
 
 
11887
  update_option( 'ewww_image_optimizer_wizard_complete', true, false );
11888
  global $eio_debug;
11889
  $debug_info = '';
@@ -11898,6 +11934,16 @@ function ewww_image_optimizer_intro_wizard() {
11898
  );
11899
  }
11900
  $cloud_key = ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' );
 
 
 
 
 
 
 
 
 
 
11901
  ?>
11902
  <div id='ewww-settings-wrap' class='wrap'>
11903
  <div id='ewwwio-wizard'>
@@ -12091,6 +12137,20 @@ function ewww_image_optimizer_intro_wizard() {
12091
  <span class='description'><?php esc_html_e( 'Resize uploaded images to these dimensions (in pixels).', 'ewww-image-optimizer' ); ?></span>
12092
  </p>
12093
  <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12094
  <p>
12095
  <input type='checkbox' id='ewww_image_optimizer_enable_help' name='ewww_image_optimizer_enable_help' value='true' />
12096
  <label for='ewww_image_optimizer_enable_help'><?php esc_html_e( 'Embedded Help', 'ewww-image-optimizer' ); ?></label><br>
@@ -13246,6 +13306,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
13246
  <textarea id='exactdn_exclude' name='exactdn_exclude' rows='3' cols='60'><?php echo esc_html( $eio_exclude_paths ); ?></textarea>
13247
  <p class='description'>
13248
  <?php esc_html_e( 'One exclusion per line, no wildcards (*) needed. Any pattern or path provided will not be routed through Easy IO.', 'ewww-image-optimizer' ); ?>
 
13249
  </p>
13250
  </td>
13251
  </tr>
@@ -13406,6 +13467,7 @@ function ewww_image_optimizer_options( $network = 'singlesite' ) {
13406
  <textarea id='ewww_image_optimizer_ll_exclude' name='ewww_image_optimizer_ll_exclude' rows='3' cols='60'><?php echo esc_html( $ll_exclude_paths ); ?></textarea>
13407
  <p class='description'>
13408
  <?php esc_html_e( 'One exclusion per line, no wildcards (*) needed. Use any string that matches the desired element(s) or exclude entire element types like "div", "span", etc. The class "skip-lazy" and attribute "data-skip-lazy" are excluded by default.', 'ewww-image-optimizer' ); ?>
 
13409
  </p>
13410
  </td>
13411
  </tr>
@@ -13636,7 +13698,10 @@ AddType image/webp .webp</pre>
13636
  <td>
13637
  <label for='ewww_image_optimizer_webp_rewrite_exclude'><strong><?php esc_html_e( 'JS WebP and Picture Web Exclusions', 'ewww-image-optimizer' ); ?></strong></label><br>
13638
  <textarea id='ewww_image_optimizer_webp_rewrite_exclude' name='ewww_image_optimizer_webp_rewrite_exclude' rows='3' cols='60'><?php echo esc_html( $webp_exclude_paths ); ?></textarea>
13639
- <p class='description'><?php esc_html_e( 'One exclusion per line, no wildcards (*) needed. Use any string that matches the desired element(s) or exclude entire element types like "div", "span", etc.', 'ewww-image-optimizer' ); ?></p>
 
 
 
13640
  </td>
13641
  </tr>
13642
  <?php if ( ! $easymode ) : ?>
@@ -13873,8 +13938,20 @@ AddType image/webp .webp</pre>
13873
  <?php ewwwio_help_link( 'https://docs.ewww.io/article/102-local-compression-options', '60c24b24a6d12c2cd643e9fb' ); ?>
13874
  </th>
13875
  <td>
13876
- <input type='checkbox' id='ewww_image_optimizer_backup_files' name='ewww_image_optimizer_backup_files' value='true' <?php checked( ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ); ?> <?php disabled( $disable_level ); ?>>
13877
- <?php esc_html_e( 'Store a copy of your original images on our secure server for 30 days. *Requires an active API key.', 'ewww-image-optimizer' ); ?>
 
 
 
 
 
 
 
 
 
 
 
 
13878
  </td>
13879
  </tr>
13880
  </table>
@@ -14517,7 +14594,9 @@ function ewww_image_optimizer_remove_cloud_key( $redirect = true ) {
14517
  }
14518
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_cloud_exceeded', 0 );
14519
  delete_transient( 'ewww_image_optimizer_cloud_status' );
14520
- ewww_image_optimizer_set_option( 'ewww_image_optimizer_backup_files', '' );
 
 
14521
  if ( 'none' !== $redirect ) {
14522
  wp_safe_redirect( wp_get_referer() );
14523
  exit;
2
  /**
3
  * Common functions for Standard and Cloud plugins
4
  *
5
+ * This file contains functions that are shared by both EWWW IO plugin(s), useful when we had a
6
+ * Cloud version. Functions that differed between the two are stored in unique.php.
 
7
  *
8
  * @link https://ewww.io
9
  * @package EWWW_Image_Optimizer
13
  exit;
14
  }
15
 
16
+ define( 'EWWW_IMAGE_OPTIMIZER_VERSION', 680 );
17
 
18
  // Initialize a couple globals.
19
  $eio_debug = '';
87
  add_filter( 'crop_thumbnails_before_update_metadata', 'ewww_image_optimizer_resize_from_meta_data', 15, 2 );
88
  // Process BuddyPress uploads from Vikinger theme.
89
  add_action( 'vikinger_file_uploaded', 'ewww_image_optimizer' );
90
+ // Process image after resize by Imsanity.
91
+ add_action( 'imsanity_post_process_attachment', 'ewww_image_optimizer_optimize_by_id', 10, 2 );
92
  }
93
+
94
  // Ensures we update the filesize data in the meta.
95
  // add_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_update_filesize_metadata', 9, 2 );
96
  // Skips resizing for images with 'noresize' in the filename.
112
  add_filter( 'intermediate_image_sizes_advanced', 'ewww_image_optimizer_image_sizes_advanced' );
113
  // Ditto for PDF files (or anything non-image).
114
  add_filter( 'fallback_intermediate_image_sizes', 'ewww_image_optimizer_fallback_sizes' );
115
+ // Disable core WebP generation since we already do that.
116
+ add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' );
117
  // Processes screenshots imported with MyArcadePlugin.
118
  add_filter( 'myarcade_filter_screenshot', 'ewww_image_optimizer_myarcade_thumbnail' );
119
  // Processes thumbnails created by MyArcadePlugin.
143
  // Legacy (non-AJAX) action hook for manually restoring a converted image.
144
  add_action( 'admin_action_ewww_image_optimizer_manual_restore', 'ewww_image_optimizer_manual' );
145
  // Legacy (non-AJAX) action hook for manually restoring a backup from the API.
146
+ add_action( 'admin_action_ewww_image_optimizer_manual_image_restore', 'ewww_image_optimizer_manual' );
147
  // Cleanup routine when an attachment is deleted.
148
  add_action( 'delete_attachment', 'ewww_image_optimizer_delete' );
149
  // Cleanup db records when Enable Media Replace replaces a file.
184
  add_action( 'wp_ajax_ewww_manual_optimize', 'ewww_image_optimizer_manual' );
185
  // AJAX action hook for manually restoring a converted image.
186
  add_action( 'wp_ajax_ewww_manual_restore', 'ewww_image_optimizer_manual' );
187
+ // AJAX action hook for manually restoring an attachment from local/cloud backups.
188
+ add_action( 'wp_ajax_ewww_manual_image_restore', 'ewww_image_optimizer_manual' );
 
 
189
  // AJAX action hook to dismiss the WooCommerce regen notice.
190
  add_action( 'wp_ajax_ewww_dismiss_wc_regen', 'ewww_image_optimizer_dismiss_wc_regen' );
191
  // AJAX action hook to dismiss the WP/LR Sync regen notice.
239
  if ( 'done' !== get_option( 'ewww_image_optimizer_relative_migration_status' ) ) {
240
  require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-relative-migration.php' );
241
  }
 
 
 
242
 
243
  /**
244
  * Setup page parsing classes after theme functions.php is loaded and plugins have run init routines.
290
  * Page Parsing class for working with HTML content.
291
  */
292
  require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-eio-page-parser.php' );
293
+ /**
294
+ * JS WebP class for parsing image urls and rewriting them for WebP support.
295
+ */
296
+ require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-eio-js-webp.php' );
 
 
 
 
 
 
 
297
  }
298
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_picture_webp' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) {
299
  $buffer_start = true;
689
  update_site_option( 'ewww_image_optimizer_avif_quality', ewww_image_optimizer_avif_quality( $ewww_image_optimizer_avif_quality ) );
690
  $ewww_image_optimizer_disable_convert_links = ( empty( $_POST['ewww_image_optimizer_disable_convert_links'] ) ? false : true );
691
  update_site_option( 'ewww_image_optimizer_disable_convert_links', $ewww_image_optimizer_disable_convert_links );
692
+ $ewww_image_optimizer_backup_files = ( empty( $_POST['ewww_image_optimizer_backup_files'] ) ? '' : sanitize_text_field( wp_unslash( $_POST['ewww_image_optimizer_backup_files'] ) ) );
693
  update_site_option( 'ewww_image_optimizer_backup_files', $ewww_image_optimizer_backup_files );
694
  $ewww_image_optimizer_auto = ( empty( $_POST['ewww_image_optimizer_auto'] ) ? false : true );
695
  update_site_option( 'ewww_image_optimizer_auto', $ewww_image_optimizer_auto );
792
  */
793
  function ewww_image_optimizer_init() {
794
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
795
+ /**
796
+ * EIO_Backup class for managing image backups.
797
+ */
798
+ require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-eio-backup.php' );
799
 
800
  // Check to see if this is the settings page and enable debugging temporarily if it is.
801
  global $ewwwio_temp_debug;
952
  ) {
953
  ewww_image_optimizer_set_option( 'exactdn_lossy', true );
954
  }
955
+ if (
956
+ get_option( 'ewww_image_optimizer_version' ) <= 670 &&
957
+ ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' )
958
+ ) {
959
+ $backup_mode = ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' );
960
+ if ( 'local' !== $backup_mode && 'cloud' !== $backup_mode ) {
961
+ ewww_image_optimizer_set_option( 'ewww_image_optimizer_backup_files', 'cloud' );
962
+ }
963
+ }
964
  if ( get_option( 'ewww_image_optimizer_version' ) && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_review_time' ) ) {
965
  $review_time = rand( time(), time() + 51 * DAY_IN_SECONDS );
966
  add_option( 'ewww_image_optimizer_review_time', $review_time, '', false );
974
  add_option( 'ewww_image_optimizer_wizard_complete', true, '', false );
975
  add_site_option( 'ewww_image_optimizer_wizard_complete', true );
976
  }
 
 
 
 
 
 
 
 
 
977
  ewww_image_optimizer_remove_obsolete_settings();
978
  update_option( 'ewww_image_optimizer_version', EWWW_IMAGE_OPTIMIZER_VERSION );
979
  }
993
  return;
994
  }
995
  global $ewwwio_test_async;
 
 
 
996
  if ( ! is_object( $ewwwio_test_async ) ) {
997
  $ewwwio_test_async = new EWWWIO_Test_Async_Handler();
998
  }
1072
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_gif_level', 'intval' );
1073
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_pdf_level', 'intval' );
1074
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_svg_level', 'intval' );
1075
+ register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_backup_files', 'sanitize_text_field' );
1076
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_enable_cloudinary', 'boolval' );
1077
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_sharpen', 'boolval' );
1078
  register_setting( 'ewww_image_optimizer_options', 'ewww_image_optimizer_jpg_quality', 'ewww_image_optimizer_jpg_quality' );
1933
  function ewww_image_optimizer_migrate_option_queue_to_table() {
1934
  global $wpdb;
1935
  global $ewwwio_media_background;
 
 
 
1936
  if ( ! is_object( $ewwwio_media_background ) ) {
1937
  $ewwwio_media_background = new EWWWIO_Media_Background_Process();
1938
  }
1990
  function ewww_image_optimizer_scheduled_optimization_changed( $old_value, $new_value ) {
1991
  if ( empty( $new_value ) && (bool) $new_value !== (bool) $old_value ) {
1992
  global $ewwwio_image_background;
 
 
 
1993
  $ewwwio_image_background->cancel_process();
1994
  update_option( 'ewwwio_stop_scheduled_scan', true, false );
1995
  }
3006
  ewwwio_debug_message( 'detected bulk operation in progress, bailing' );
3007
  return;
3008
  }
 
 
 
3009
  global $ewww_defer;
3010
  $ewww_defer = false;
3011
  require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'bulk.php' );
4046
  ewwwio_get_filesystem();
4047
  return $eio_filesystem->is_readable( $file );
4048
  }
4049
+
4050
  /**
4051
  * Check if directory exists, and that it is local rather than using a protocol like http:// or phar://
4052
  *
4294
  $new_meta = ewww_image_optimizer_resize_from_meta_data( $original_meta, $attachment_id );
4295
  } elseif ( 'ewww_image_optimizer_manual_restore' === $_REQUEST['action'] || 'ewww_manual_restore' === $_REQUEST['action'] ) {
4296
  $new_meta = ewww_image_optimizer_restore_from_meta_data( $original_meta, $attachment_id );
4297
+ } elseif ( 'ewww_image_optimizer_manual_image_restore' === $_REQUEST['action'] || 'ewww_manual_image_restore' === $_REQUEST['action'] ) {
4298
+ global $eio_backup;
4299
+ $new_meta = $eio_backup->restore_backup_from_meta_data( $attachment_id, 'media', $original_meta );
4300
  } else {
4301
  if ( ! wp_doing_ajax() ) {
4302
  wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) );
4475
  * @global object $wpdb
4476
  * @global object $ewwwdb A clone of $wpdb unless it is lacking utf8 connectivity.
4477
  *
4478
+ * @param int|array $image The db record/ID of the image to restore.
4479
  * @return bool True if the image was restored successfully.
4480
  */
4481
  function ewww_image_optimizer_cloud_restore_single_image( $image ) {
4482
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
4483
+ global $eio_backup;
4484
  global $wpdb;
4485
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
4486
  ewww_image_optimizer_db_init();
4517
  $error_message = $result->get_error_message();
4518
  ewwwio_debug_message( "restore request failed: $error_message" );
4519
  ewwwio_memory( __FUNCTION__ );
4520
+ /* translators: %s: An HTTP error message */
4521
+ $eio_backup->throw_error( sprintf( __( 'Restore failed with HTTP error: %s', 'ewww-image-optimizer' ), $error_message ) );
4522
  return false;
4523
  } elseif ( ! empty( $result['body'] ) && strpos( $result['body'], 'missing' ) === false ) {
4524
  $enabled_types = array( 'image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'image/svg+xml' );
4532
  $old_type = ewww_image_optimizer_mimetype( $image['path'], 'i' );
4533
  }
4534
  if ( ! in_array( $new_type, $enabled_types, true ) ) {
4535
+ /* translators: %s: An image filename */
4536
+ $eio_backup->throw_error( sprintf( __( 'Backup file for %s has the wrong mime type.', 'ewww-image-optimizer' ), $image['path'] ) );
4537
  return false;
4538
  }
4539
  if ( empty( $old_type ) || $old_type === $new_type ) {
4540
  if ( ewwwio_rename( $image['path'] . '.tmp', $image['path'] ) ) {
4541
+ ewwwio_debug_message( "{$image['path']} was restored, removing .webp version and resetting db record" );
4542
  if ( ewwwio_is_file( $image['path'] . '.webp' ) && is_writable( $image['path'] . '.webp' ) ) {
4543
  unlink( $image['path'] . '.webp' );
4544
  }
4548
  }
4549
  }
4550
  }
4551
+ /* translators: %s: An image filename */
4552
+ $eio_backup->throw_error( sprintf( __( 'Backup could not be retrieved for %s.', 'ewww-image-optimizer' ), $image['path'] ) );
4553
  return false;
4554
  }
4555
 
4565
  */
4566
  function ewww_image_optimizer_delete( $id ) {
4567
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
4568
+ global $eio_backup;
4569
  global $wpdb;
4570
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
4571
  ewww_image_optimizer_db_init();
4596
  ewwwio_debug_message( 'removing: ' . $webpfileold );
4597
  ewwwio_delete_file( $webpfileold );
4598
  }
4599
+ $eio_backup->delete_local_backup( $image['path'] );
4600
  }
4601
  if ( ! empty( $image['converted'] ) ) {
4602
  $image['converted'] = ewww_image_optimizer_absolutize_path( $image['converted'] );
4603
+ $eio_backup->delete_local_backup( $image['converted'] );
4604
  }
4605
  if ( ! empty( $image['converted'] ) && ewwwio_is_file( $image['converted'] ) ) {
4606
  ewwwio_debug_message( 'removing: ' . $image['converted'] );
4650
  if ( ewwwio_is_file( $file_path ) && empty( $rows ) ) {
4651
  ewwwio_debug_message( 'removing: ' . $file_path );
4652
  ewwwio_delete_file( $file_path );
4653
+ $eio_backup->delete_local_backup( $file_path );
4654
  $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $file_path ) ) );
4655
  }
4656
  }
4671
  ewwwio_debug_message( 'removing: ' . $s3_dir . wp_basename( $meta['original_image'] ) . '.webp' );
4672
  unlink( $s3_dir . wp_basename( $meta['original_image'] ) . '.webp' );
4673
  }
4674
+ $eio_backup->delete_local_backup( $orig_path );
4675
  $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $orig_path ) ) );
4676
  }
4677
  // Remove the regular image from the ewwwio_images tables.
4696
  ewwwio_debug_message( 'removing: ' . $s3_dir . wp_basename( $data['file'] ) . '.webp' );
4697
  unlink( $s3_dir . wp_basename( $data['file'] ) . '.webp' );
4698
  }
4699
+ $eio_backup->delete_local_backup( $base_dir . wp_basename( $data['file'] ) );
4700
  $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $base_dir . $data['file'] ) ) );
4701
  // If the original resize is set, and still exists.
4702
  if ( ! empty( $data['orig_file'] ) && ewwwio_is_file( $base_dir . $data['orig_file'] ) ) {
4710
  if ( empty( $srows ) ) {
4711
  ewwwio_debug_message( 'removing: ' . $base_dir . $data['orig_file'] );
4712
  ewwwio_delete_file( $base_dir . $data['orig_file'] );
4713
+ $eio_backup->delete_local_backup( $base_dir . $data['orig_file'] );
4714
  $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'path' => ewww_image_optimizer_relativize_path( $base_dir . $data['orig_file'] ) ) );
4715
  }
4716
  }
4725
  ewwwio_debug_message( 'removing: ' . $webpfileold );
4726
  ewwwio_delete_file( $webpfileold );
4727
  }
4728
+ $eio_backup->delete_local_backup( $file_path );
4729
  }
4730
 
4731
  /**
4741
  */
4742
  function ewww_image_optimizer_file_deleted( $id, $file ) {
4743
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
4744
+ global $eio_backup;
4745
  global $wpdb;
4746
  if ( strpos( $wpdb->charset, 'utf8' ) === false ) {
4747
  ewww_image_optimizer_db_init();
4771
  ewwwio_delete_file( $image['converted'] . '.webp' );
4772
  }
4773
  }
4774
+ $eio_backup->delete_local_backup( $image['converted'] );
4775
  $ewwwdb->delete( $ewwwdb->ewwwio_images, array( 'id' => $image['id'] ) );
4776
  }
4777
  }
4778
  if ( ewwwio_is_file( $file . '.webp' ) ) {
4779
  ewwwio_delete_file( $file . '.webp' );
4780
  }
4781
+ $eio_backup->delete_local_backup( $file );
4782
  }
4783
 
4784
  /**
5445
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_gif_level', 10 );
5446
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_pdf_level', 10 );
5447
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_svg_level', 10 );
5448
+ if ( 'local' !== ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
5449
+ ewww_image_optimizer_set_option( 'ewww_image_optimizer_backup_files', 'cloud' );
5450
+ }
5451
  }
5452
 
5453
  /**
5488
  update_site_option( 'ewww_image_optimizer_pdf_level', 0 );
5489
  update_option( 'ewww_image_optimizer_pdf_level', 0 );
5490
  }
5491
+ if ( 'local' !== ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
5492
+ update_site_option( 'ewww_image_optimizer_backup_files', '' );
5493
+ update_option( 'ewww_image_optimizer_backup_files', '' );
5494
+ }
5495
  return false;
5496
  }
5497
  if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_exceeded' ) > time() ) {
5503
  if ( ! ewww_image_optimizer_detect_wpsf_location_lock() && $cache && preg_match( '/great/', $ewww_cloud_status ) ) {
5504
  ewwwio_debug_message( 'using cached verification' );
5505
  global $ewwwio_async_key_verification;
 
 
 
5506
  if ( ! is_object( $ewwwio_async_key_verification ) ) {
5507
  $ewwwio_async_key_verification = new EWWWIO_Async_Key_Verification();
5508
  }
5793
  if ( 'image/png' === $type && 30 === (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_png_level' ) ) {
5794
  $png_compress = 1;
5795
  }
5796
+ $backup_exclusions = array(
5797
+ EWWWIO_CONTENT_DIR,
5798
+ '/wp-admin/',
5799
+ '/wp-includes/',
5800
+ '/wp-content/themes/',
5801
+ '/wp-content/plugins/',
5802
+ '/cache/',
5803
+ '/dynamic/', // Nextgen dynamic images.
5804
+ );
5805
+ $backup_exclusions = apply_filters( 'ewww_image_optimizer_backup_exclusions', $backup_exclusions );
5806
+ $backup_excluded = false;
5807
+ foreach ( $backup_exclusions as $backup_exclusion ) {
5808
+ if ( false !== strpos( $file, $backup_exclusion ) ) {
5809
+ $backup_excluded = true;
5810
+ }
5811
+ }
5812
+ if ( ! $webp && 'cloud' === ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) && ! $backup_excluded ) {
5813
  global $ewww_image;
5814
  if ( is_object( $ewww_image ) && $ewww_image->file === $file && ! empty( $ewww_image->backup ) ) {
5815
  $hash = $ewww_image->backup;
6095
  if ( empty( $api_key ) ) {
6096
  return false;
6097
  }
6098
+ if ( 'cloud' !== ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
6099
  return false;
6100
  }
6101
  if ( ! ewwwio_is_file( $file ) || ! ewwwio_is_readable( $file ) ) {
8013
  }
8014
  $new_jpeg->saveFile( $new_file );
8015
  }
8016
+ // Backup the file before we replace the original.
8017
+ global $eio_backup;
8018
+ $eio_backup->backup_file( $file );
8019
+ // ewww_image_optimizer_cloud_backup( $file );.
8020
  $new_type = (string) ewww_image_optimizer_mimetype( $new_file, 'i' );
8021
  if ( $type === $new_type ) {
8022
  ewwwio_rename( $new_file, $file );
8153
  if ( empty( $ewww_force ) ) {
8154
  return $meta;
8155
  }
8156
+ if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
8157
  return $meta;
8158
  }
8159
  if ( 'image/jpeg' === $type && (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_jpg_level' ) > 20 ) {
8168
  $compression_level = ewww_image_optimizer_get_level( $type );
8169
  // Retrieve any records for this image.
8170
  global $wpdb;
8171
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
8172
  foreach ( $optimized_images as $optimized_image ) {
8173
  if ( 'full' === $optimized_image['resize'] && $compression_level < $optimized_image['level'] ) {
8174
+ global $eio_backup;
8175
+ if ( $eio_backup->is_backup_available( $optimized_image['path'], $optimized_image ) ) {
8176
+ return $eio_backup->restore_backup_from_meta_data( $id, 'media', $meta );
8177
  }
8178
  }
8179
  }
8587
  add_filter( 'as3cf_pre_update_attachment_metadata', '__return_true' );
8588
  }
8589
  global $ewwwio_media_background;
 
 
 
8590
  if ( ! is_object( $ewwwio_media_background ) ) {
8591
  $ewwwio_media_background = new EWWWIO_Media_Background_Process();
8592
  }
8633
  add_filter( 'http_headers_useragent', 'ewww_image_optimizer_cloud_useragent', PHP_INT_MAX );
8634
  $parallel_sizes['full'] = $file_path;
8635
  global $ewwwio_async_optimize_media;
 
 
 
8636
  if ( ! is_object( $ewwwio_async_optimize_media ) ) {
8637
  $ewwwio_async_optimize_media = new EWWWIO_Async_Request();
8638
  }
8844
  $timer_max = (int) apply_filters( 'ewww_image_optimizer_background_timer_max', 20 );
8845
  $processing_sizes = array();
8846
  global $ewwwio_async_optimize_media;
 
 
 
8847
  if ( ! is_object( $ewwwio_async_optimize_media ) ) {
8848
  $ewwwio_async_optimize_media = new EWWWIO_Async_Request();
8849
  }
8994
  return $meta;
8995
  }
8996
 
8997
+ /**
8998
+ * Optimize by attachment ID with optional meta.
8999
+ *
9000
+ * Proxy for ewww_image_optimizer_resize_from_meta_data(), used by Imsanity.
9001
+ *
9002
+ * @param int $id The attachment ID number.
9003
+ * @param array $meta The attachment metadata generated by WordPress. Optional.
9004
+ */
9005
+ function ewww_image_optimizer_optimize_by_id( $id, $meta = false ) {
9006
+ ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
9007
+ if ( empty( $id ) ) {
9008
+ return;
9009
+ }
9010
+ if ( ! ewww_image_optimizer_iterable( $meta ) ) {
9011
+ $meta = wp_get_attachment_metadata( $id );
9012
+ }
9013
+
9014
+ $meta = ewww_image_optimizer_resize_from_meta_data( $meta, $id );
9015
+ wp_update_attachment_metadata( $id, $meta );
9016
+ }
9017
+
9018
  /**
9019
  * Only runs during WP/LR Sync to check if an attachment has been updated.
9020
  *
9054
 
9055
  // Get a list of all the image files optimized for this attachment.
9056
  global $wpdb;
9057
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
9058
  if ( ewww_image_optimizer_iterable( $optimized_images ) ) {
9059
  foreach ( $optimized_images as $optimized_image ) {
9060
  $image_path = ewww_image_optimizer_absolutize_path( $optimized_image['path'] );
10041
  $in_progress = true;
10042
  }
10043
  if ( ! $in_progress ) {
10044
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
10045
  if ( ! $optimized_images ) {
10046
  // Attempt migration, but only if the original image is in the db, $migrated will be metadata on success, false on failure.
10047
  $migrated = ewww_image_optimizer_migrate_meta_to_db( $id, $meta, true );
10048
  }
10049
  if ( $migrated ) {
10050
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
10051
  }
10052
  if ( ! $optimized_images ) {
10053
  list( $possible_action_id, $optimized_images ) = ewww_image_optimizer_get_wpml_results( $id );
10075
  }
10076
  if ( $backup_available && current_user_can( apply_filters( 'ewww_image_optimizer_manual_permissions', '' ) ) ) {
10077
  echo '<div>' . sprintf(
10078
+ '<a class="ewww-manual-image-restore" data-id="%1$d" data-nonce="%2$s" href="%3$s">%4$s</a>',
10079
  (int) $action_id,
10080
  esc_attr( $ewww_manual_nonce ),
10081
+ esc_url( admin_url( "admin.php?action=ewww_image_optimizer_manual_image_restore&ewww_manual_nonce=$ewww_manual_nonce&ewww_attachment_ID=$action_id" ) ),
10082
  esc_html__( 'Restore original', 'ewww-image-optimizer' )
10083
  ) . '</div>';
10084
  }
10119
  $in_progress = true;
10120
  }
10121
  if ( ! $in_progress ) {
10122
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
10123
  if ( ! $optimized_images ) {
10124
  // Attempt migration, but only if the original image is in the db, $migrated will be metadata on success, false on failure.
10125
  $migrated = ewww_image_optimizer_migrate_meta_to_db( $id, $meta, true );
10126
  }
10127
  if ( $migrated ) {
10128
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $id ), ARRAY_A );
10129
  }
10130
  if ( ! $optimized_images ) {
10131
  list( $possible_action_id, $optimized_images ) = ewww_image_optimizer_get_wpml_results( $id );
10191
  ) . '</div>';
10192
  } elseif ( $backup_available && current_user_can( apply_filters( 'ewww_image_optimizer_manual_permissions', '' ) ) ) {
10193
  echo '<div>' . sprintf(
10194
+ '<a class="ewww-manual-image-restore" data-id="%1$d" data-nonce="%2$s" href="%3$s">%4$s</a>',
10195
  (int) $action_id,
10196
  esc_attr( $ewww_manual_nonce ),
10197
+ esc_url( admin_url( "admin.php?action=ewww_image_optimizer_manual_image_restore&ewww_manual_nonce=$ewww_manual_nonce&ewww_attachment_ID=$action_id" ) ),
10198
  esc_html__( 'Restore original', 'ewww-image-optimizer' )
10199
  ) . '</div>';
10200
  }
10270
  if ( empty( $compression_level ) ) {
10271
  return '';
10272
  }
10273
+ if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
10274
  return '';
10275
  }
10276
  ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' );
10278
  if ( 'full' === $optimized_image['resize'] ) {
10279
  ewwwio_debug_message( "comparing $compression_level (current) vs. {$optimized_image['level']} (previous)" );
10280
  if ( $compression_level < 30 && $compression_level < $optimized_image['level'] && $optimized_image['level'] > 20 ) {
10281
+ global $eio_backup;
10282
+ return $eio_backup->is_backup_available( $optimized_image['path'], $optimized_image );
 
 
10283
  }
10284
  }
10285
  }
10389
  $opt_size += $optimized_image['image_size'];
10390
  if ( 'full' === $optimized_image['resize'] ) {
10391
  $updated_time = strtotime( $optimized_image['updated'] );
10392
+ global $eio_backup;
10393
+ $backup_available = $eio_backup->is_backup_available( $optimized_image['path'], $optimized_image );
 
 
 
10394
  }
10395
  if ( ! empty( $optimized_image['converted'] ) ) {
10396
  $converted = ewww_image_optimizer_absolutize_path( $optimized_image['converted'] );
10483
  continue;
10484
  }
10485
  ewwwio_debug_message( "checking {$translation->element_id} for results with WPML" );
10486
+ $optimized_images = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media' AND image_size <> 0 ORDER BY orig_size DESC", $translation->element_id ), ARRAY_A );
10487
  if ( ! empty( $optimized_images ) ) {
10488
  return array( (int) $translation->element_id, $optimized_images );
10489
  }
11620
  ewwwio_debug_message( 'pdf level: ' . ewww_image_optimizer_get_option( 'ewww_image_optimizer_pdf_level' ) );
11621
  ewwwio_debug_message( 'svg level: ' . ewww_image_optimizer_get_option( 'ewww_image_optimizer_svg_level' ) );
11622
  ewwwio_debug_message( 'bulk delay: ' . ewww_image_optimizer_get_option( 'ewww_image_optimizer_delay' ) );
11623
+ ewwwio_debug_message( 'backup mode: ' . ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) );
11624
  ewwwio_debug_message( 'cloudinary upload: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_enable_cloudinary' ) ? 'on' : 'off' ) );
11625
  ewwwio_debug_message( 'ExactDN enabled: ' . ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ? 'on' : 'off' ) );
11626
  ewwwio_debug_message( 'ExactDN all the things: ' . ( ewww_image_optimizer_get_option( 'exactdn_all_the_things' ) ? 'on' : 'off' ) );
11801
  $webp_available = ewww_image_optimizer_webp_available();
11802
  $bulk_available = false;
11803
  $tools_available = true;
11804
+ $backup_mode = 'local';
11805
  if ( ! defined( 'EWWW_IMAGE_OPTIMIZER_NOEXEC' ) ) {
11806
  if ( defined( 'EWWW_IMAGE_OPTIMIZER_CLOUD' ) && EWWW_IMAGE_OPTIMIZER_CLOUD ) {
11807
  ewww_image_optimizer_disable_tools();
11870
  if ( ! empty( $_POST['ewwwio_wizard_step'] ) ) {
11871
  $wizard_step = (int) $_POST['ewwwio_wizard_step'];
11872
  }
11873
+ if ( 2 === $wizard_step ) {
11874
+ if ( ! empty( $_POST['ewww_image_optimizer_goal_save_space'] ) ) {
11875
+ ewwwio_debug_message( 'wants to save space' );
11876
+ update_option( 'ewww_image_optimizer_goal_save_space', true, false );
11877
+ } else {
11878
+ ewwwio_debug_message( 'storage space? who cares!' );
11879
+ update_option( 'ewww_image_optimizer_goal_save_space', false, false );
11880
+ }
11881
+ if ( ! empty( $_POST['ewww_image_optimizer_goal_site_speed'] ) ) {
11882
+ ewwwio_debug_message( 'hurray for speed!' );
11883
+ update_option( 'ewww_image_optimizer_goal_site_speed', true, false );
11884
+ } else {
11885
+ ewwwio_debug_message( "I'm not slow, you're slow!" );
11886
+ update_option( 'ewww_image_optimizer_goal_site_speed', false, false );
11887
+ }
11888
  }
11889
  if ( ! empty( $_POST['ewww_image_optimizer_budget'] ) && 'free' === $_POST['ewww_image_optimizer_budget'] ) {
11890
  if ( $display_exec_notice ) {
11915
  }
11916
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_enable_help', ! empty( $_POST['ewww_image_optimizer_enable_help'] ) );
11917
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_allow_tracking', ! empty( $_POST['ewww_image_optimizer_allow_tracking'] ) );
11918
+ if ( ! empty( $_POST['ewww_image_optimizer_backup_files'] ) && 'local' === $_POST['ewww_image_optimizer_backup_files'] ) {
11919
+ ewww_image_optimizer_set_option( 'ewww_image_optimizer_backup_files', 'local' );
11920
+ } elseif ( ! empty( $_POST['ewww_image_optimizer_backup_files'] ) && 'cloud' === $_POST['ewww_image_optimizer_backup_files'] ) {
11921
+ ewww_image_optimizer_set_option( 'ewww_image_optimizer_backup_files', 'cloud' );
11922
+ }
11923
  update_option( 'ewww_image_optimizer_wizard_complete', true, false );
11924
  global $eio_debug;
11925
  $debug_info = '';
11934
  );
11935
  }
11936
  $cloud_key = ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' );
11937
+ if ( $cloud_key && 'local' !== ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
11938
+ $backup_mode = 'cloud';
11939
+ }
11940
+ if (
11941
+ 'local' === $backup_mode &&
11942
+ get_option( 'ewww_image_optimizer_goal_save_space' ) &&
11943
+ 'local' !== ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' )
11944
+ ) {
11945
+ $backup_mode = '';
11946
+ }
11947
  ?>
11948
  <div id='ewww-settings-wrap' class='wrap'>
11949
  <div id='ewwwio-wizard'>
12137
  <span class='description'><?php esc_html_e( 'Resize uploaded images to these dimensions (in pixels).', 'ewww-image-optimizer' ); ?></span>
12138
  </p>
12139
  <?php endif; ?>
12140
+ <p>
12141
+ <select id='ewww_image_optimizer_backup_files' name='ewww_image_optimizer_backup_files'>
12142
+ <option value=''>
12143
+ <?php esc_html_e( 'Disabled', 'ewww-image-optimizer' ); ?>
12144
+ </option>
12145
+ <option value='local' <?php selected( $backup_mode, 'local' ); ?>>
12146
+ <?php esc_html_e( 'Local', 'ewww-image-optimizer' ); ?>
12147
+ </option>
12148
+ <option <?php disabled( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) ); ?> value='cloud' <?php selected( $backup_mode, 'cloud' ); ?>>
12149
+ <?php esc_html_e( 'Cloud', 'ewww-image-optimizer' ); ?>
12150
+ </option>
12151
+ </select>
12152
+ <span class='description'><?php esc_html_e( 'Image Backups', 'ewww-image-optimizer' ); ?></span>
12153
+ </p>
12154
  <p>
12155
  <input type='checkbox' id='ewww_image_optimizer_enable_help' name='ewww_image_optimizer_enable_help' value='true' />
12156
  <label for='ewww_image_optimizer_enable_help'><?php esc_html_e( 'Embedded Help', 'ewww-image-optimizer' ); ?></label><br>
13306
  <textarea id='exactdn_exclude' name='exactdn_exclude' rows='3' cols='60'><?php echo esc_html( $eio_exclude_paths ); ?></textarea>
13307
  <p class='description'>
13308
  <?php esc_html_e( 'One exclusion per line, no wildcards (*) needed. Any pattern or path provided will not be routed through Easy IO.', 'ewww-image-optimizer' ); ?>
13309
+ <?php esc_html_e( 'Exclude entire pages with page:/xyz/ syntax.', 'ewww-image-optimizer' ); ?>
13310
  </p>
13311
  </td>
13312
  </tr>
13467
  <textarea id='ewww_image_optimizer_ll_exclude' name='ewww_image_optimizer_ll_exclude' rows='3' cols='60'><?php echo esc_html( $ll_exclude_paths ); ?></textarea>
13468
  <p class='description'>
13469
  <?php esc_html_e( 'One exclusion per line, no wildcards (*) needed. Use any string that matches the desired element(s) or exclude entire element types like "div", "span", etc. The class "skip-lazy" and attribute "data-skip-lazy" are excluded by default.', 'ewww-image-optimizer' ); ?>
13470
+ <?php esc_html_e( 'Exclude entire pages with page:/xyz/ syntax.', 'ewww-image-optimizer' ); ?>
13471
  </p>
13472
  </td>
13473
  </tr>
13698
  <td>
13699
  <label for='ewww_image_optimizer_webp_rewrite_exclude'><strong><?php esc_html_e( 'JS WebP and Picture Web Exclusions', 'ewww-image-optimizer' ); ?></strong></label><br>
13700
  <textarea id='ewww_image_optimizer_webp_rewrite_exclude' name='ewww_image_optimizer_webp_rewrite_exclude' rows='3' cols='60'><?php echo esc_html( $webp_exclude_paths ); ?></textarea>
13701
+ <p class='description'>
13702
+ <?php esc_html_e( 'One exclusion per line, no wildcards (*) needed. Use any string that matches the desired element(s) or exclude entire element types like "div", "span", etc.', 'ewww-image-optimizer' ); ?>
13703
+ <?php esc_html_e( 'Exclude entire pages with page:/xyz/ syntax.', 'ewww-image-optimizer' ); ?>
13704
+ </p>
13705
  </td>
13706
  </tr>
13707
  <?php if ( ! $easymode ) : ?>
13938
  <?php ewwwio_help_link( 'https://docs.ewww.io/article/102-local-compression-options', '60c24b24a6d12c2cd643e9fb' ); ?>
13939
  </th>
13940
  <td>
13941
+ <select id='ewww_image_optimizer_backup_files' name='ewww_image_optimizer_backup_files'>
13942
+ <option value='' <?php selected( (string) ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ), '' ); ?>>
13943
+ <?php esc_html_e( 'Disabled', 'ewww-image-optimizer' ); ?>
13944
+ </option>
13945
+ <option value='local' <?php selected( ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ), 'local' ); ?>>
13946
+ <?php esc_html_e( 'Local', 'ewww-image-optimizer' ); ?>
13947
+ </option>
13948
+ <option <?php disabled( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) ); ?> value='cloud' <?php selected( ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ), 'cloud' ); ?>>
13949
+ <?php esc_html_e( 'Cloud', 'ewww-image-optimizer' ); ?>
13950
+ </option>
13951
+ </select>
13952
+ <p class='description'>
13953
+ <?php esc_html_e( 'Local mode stores image backups on your server. With an active API key you may store image backups on our secure cloud storage for 30 days.', 'ewww-image-optimizer' ); ?>
13954
+ </p>
13955
  </td>
13956
  </tr>
13957
  </table>
14594
  }
14595
  ewww_image_optimizer_set_option( 'ewww_image_optimizer_cloud_exceeded', 0 );
14596
  delete_transient( 'ewww_image_optimizer_cloud_status' );
14597
+ if ( 'local' !== ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
14598
+ ewww_image_optimizer_set_option( 'ewww_image_optimizer_backup_files', '' );
14599
+ }
14600
  if ( 'none' !== $redirect ) {
14601
  wp_safe_redirect( wp_get_referer() );
14602
  exit;
ewww-image-optimizer.php CHANGED
@@ -13,7 +13,7 @@ Plugin Name: EWWW Image Optimizer
13
  Plugin URI: https://wordpress.org/plugins/ewww-image-optimizer/
14
  Description: Smaller Images, Faster Sites, Happier Visitors. Comprehensive image optimization that doesn't require a degree in rocket science.
15
  Author: Exactly WWW
16
- Version: 6.7.0
17
  Requires at least: 5.8
18
  Requires PHP: 7.2
19
  Author URI: https://ewww.io/
@@ -28,7 +28,6 @@ if ( ! defined( 'EWWW_IO_CLOUD_PLUGIN' ) ) {
28
  define( 'EWWW_IO_CLOUD_PLUGIN', false );
29
  }
30
 
31
-
32
  // Check the PHP version.
33
  if ( ! defined( 'PHP_VERSION_ID' ) || PHP_VERSION_ID < 70200 ) {
34
  add_action( 'network_admin_notices', 'ewww_image_optimizer_unsupported_php' );
@@ -109,7 +108,7 @@ if ( ! defined( 'PHP_VERSION_ID' ) || PHP_VERSION_ID < 70200 ) {
109
  /**
110
  * The various class extensions for parallel and background optimization.
111
  */
112
- require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'background.php' );
113
  /**
114
  * EWWW_Image class for working with queued images and image records from the database.
115
  */
13
  Plugin URI: https://wordpress.org/plugins/ewww-image-optimizer/
14
  Description: Smaller Images, Faster Sites, Happier Visitors. Comprehensive image optimization that doesn't require a degree in rocket science.
15
  Author: Exactly WWW
16
+ Version: 6.8.0
17
  Requires at least: 5.8
18
  Requires PHP: 7.2
19
  Author URI: https://ewww.io/
28
  define( 'EWWW_IO_CLOUD_PLUGIN', false );
29
  }
30
 
 
31
  // Check the PHP version.
32
  if ( ! defined( 'PHP_VERSION_ID' ) || PHP_VERSION_ID < 70200 ) {
33
  add_action( 'network_admin_notices', 'ewww_image_optimizer_unsupported_php' );
108
  /**
109
  * The various class extensions for parallel and background optimization.
110
  */
111
+ require_once( EWWW_IMAGE_OPTIMIZER_PLUGIN_PATH . 'classes/class-ewwwio-media-background-process.php' );
112
  /**
113
  * EWWW_Image class for working with queued images and image records from the database.
114
  */
includes/eio-settings.js CHANGED
@@ -131,13 +131,12 @@ jQuery(document).ready(function($) {
131
  $('#ewww_image_optimizer_png_level option').prop('disabled', false);
132
  $('#ewww_image_optimizer_pdf_level option').prop('disabled', false);
133
  $('#ewww_image_optimizer_svg_level option').prop('disabled', false);
134
- $('#ewww_image_optimizer_backup_files').prop('disabled', false);
135
  $('#ewww_image_optimizer_jpg_level').val(30);
136
  $('#ewww_image_optimizer_png_level').val(20);
137
  $('#ewww_image_optimizer_gif_level').val(10);
138
  $('#ewww_image_optimizer_pdf_level').val(10);
139
  $('#ewww_image_optimizer_svg_level').val(10);
140
- $('#ewww_image_optimizer_backup_files').prop('checked', true);
141
  }
142
  }
143
  var easyio_registration_error = '';
131
  $('#ewww_image_optimizer_png_level option').prop('disabled', false);
132
  $('#ewww_image_optimizer_pdf_level option').prop('disabled', false);
133
  $('#ewww_image_optimizer_svg_level option').prop('disabled', false);
134
+ $('#ewww_image_optimizer_backup_files option').prop('disabled', false);
135
  $('#ewww_image_optimizer_jpg_level').val(30);
136
  $('#ewww_image_optimizer_png_level').val(20);
137
  $('#ewww_image_optimizer_gif_level').val(10);
138
  $('#ewww_image_optimizer_pdf_level').val(10);
139
  $('#ewww_image_optimizer_svg_level').val(10);
 
140
  }
141
  }
142
  var easyio_registration_error = '';
includes/eio-tools.js CHANGED
@@ -265,6 +265,63 @@ jQuery(document).ready(function($) {
265
  }
266
  return false;
267
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  var ewww_total_originals = 0;
269
  var ewww_original_attachments = false;
270
  $('#ewww-clean-originals').on( 'submit', function() {
@@ -410,11 +467,11 @@ jQuery(document).ready(function($) {
410
  ewwwCleanConvertedOriginals(converted_offset);
411
  });
412
  }
413
- var ewww_total_webp = 0;
414
- var ewww_webp_attachments = false;
415
  $('#ewww-clean-webp').on( 'submit', function() {
416
  var ewww_webp_data = {
417
- action: 'ewwwio_get_all_attachments',
418
  ewww_wpnonce: ewww_vars._wpnonce,
419
  };
420
  var header_label = $(this).find('input[type="submit"]').val();
@@ -430,7 +487,7 @@ jQuery(document).ready(function($) {
430
  console.log(response);
431
  return false;
432
  }
433
- ewww_total_webp = ewww_webp_attachments.length;
434
  $('.ewww-tool-info').hide();
435
  $('.ewww-tool-form').hide();
436
  $('.ewww-tool-divider').hide();
@@ -443,12 +500,9 @@ jQuery(document).ready(function($) {
443
  return false;
444
  });
445
  function ewwwRemoveWebPByID(){
446
- var attachment_id = ewww_webp_attachments.pop();
447
- console.log('removing webp for attachment: ' + attachment_id);
448
  var ewww_webp_data = {
449
  action: 'bulk_aux_images_delete_webp',
450
  ewww_wpnonce: ewww_vars._wpnonce,
451
- attachment_id: attachment_id,
452
  };
453
  $.post(ajaxurl, ewww_webp_data, function(response) {
454
  try {
@@ -465,25 +519,25 @@ jQuery(document).ready(function($) {
465
  $('#ewww-clean-webp-progress').html('<span style="color: red"><b>' + ewww_response.error + '</b></span>');
466
  return false;
467
  }
468
- if(!ewww_webp_attachments.length) {
469
- ewww_total_webp = ewww_vars.image_count;
 
470
  $('#ewww-clean-webp-progressbar').progressbar({ max: ewww_total_webp });
471
  $('#ewww-clean-webp-progressbar').progressbar("option", "value", 0);
472
  $('#ewww-clean-webp-progress').html('<p>' + ewww_vars.stage2 + ' 0/' + ewww_total_webp + '</p>');
473
- ewwwRemoveWebP(0);
474
  return false;
475
  }
476
- var completed = ewww_total_webp - ewww_webp_attachments.length;
477
- $('#ewww-clean-webp-progressbar').progressbar("option", "value", completed);
478
- $('#ewww-clean-webp-progress').html('<p>' + ewww_vars.stage1 + ' ' + completed + '/' + ewww_total_webp + '</p>');
479
  ewwwRemoveWebPByID();
480
  });
481
  }
482
- function ewwwRemoveWebP(webp_offset){
483
  var ewww_webp_data = {
484
  action: 'bulk_aux_images_webp_clean',
485
  ewww_wpnonce: ewww_vars._wpnonce,
486
- ewww_offset: webp_offset,
487
  };
488
  $.post(ajaxurl, ewww_webp_data, function(response) {
489
  try {
@@ -504,10 +558,10 @@ jQuery(document).ready(function($) {
504
  $('#ewww-clean-webp-progress').html(ewww_vars.finished);
505
  return false;
506
  }
507
- webp_offset += ewww_response.completed;
508
- $('#ewww-clean-webp-progressbar').progressbar("option", "value", webp_offset);
509
- $('#ewww-clean-webp-progress').html('<p>' + ewww_vars.stage2 + ' ' + webp_offset + '/' + ewww_total_webp + '</p>');
510
- ewwwRemoveWebP(webp_offset);
511
  });
512
  }
513
  $('#ewww-clean-table').on( 'submit', function() {
@@ -631,7 +685,7 @@ jQuery(document).ready(function($) {
631
  $('.ewww-aux-table').on( 'click', '.ewww-restore-image', function() {
632
  var imageID = $(this).data('id');
633
  var ewww_image_restore = {
634
- action: 'ewww_manual_cloud_restore_single',
635
  ewww_wpnonce: ewww_vars._wpnonce,
636
  ewww_image_id: imageID,
637
  };
265
  }
266
  return false;
267
  });
268
+ var ewww_total_restored = 0;
269
+ $('#ewww-restore-originals').on( 'submit', function() {
270
+ if (!confirm(ewww_vars.tool_warning)) {
271
+ return false;
272
+ }
273
+ var header_label = $(this).find('input[type="submit"]').val();
274
+ if (header_label) {
275
+ $('#ewwwio-tools-header').html(header_label);
276
+ }
277
+ $('.ewww-tool-info').hide();
278
+ $('.ewww-tool-form').hide();
279
+ $('.ewww-tool-divider').hide();
280
+ $('#ewww-restore-originals-progressbar').progressbar({ max: ewww_vars.restorable_images });
281
+ $('#ewww-restore-originals-progress').html('<p> 0/' + ewww_vars.restorable_images + '</p>');
282
+ $('#ewww-restore-originals-progressbar').show();
283
+ $('#ewww-restore-originals-progress').show();
284
+ ewwwRestoreOriginals();
285
+ return false;
286
+ });
287
+ function ewwwRestoreOriginals(){
288
+ var ewww_originals_data = {
289
+ action: 'bulk_aux_images_restore_original',
290
+ ewww_wpnonce: ewww_vars._wpnonce,
291
+ };
292
+ $.post(ajaxurl, ewww_originals_data, function(response) {
293
+ try {
294
+ var ewww_response = JSON.parse(response);
295
+ } catch (err) {
296
+ $('#ewww-restore-originals-progressbar').hide();
297
+ $('#ewww-restore-originals-progress').html('<span style="color: red"><b>' + ewww_vars.invalid_response + '</b></span>');
298
+ console.log(err);
299
+ console.log(response);
300
+ return false;
301
+ }
302
+ if ( ewww_response.error ) {
303
+ $('#ewww-restore-originals-progressbar').hide();
304
+ $('#ewww-restore-originals-progress').html('<span style="color: red"><b>' + ewww_response.error + '</b></span>');
305
+ return false;
306
+ }
307
+ if(ewww_response.finished) {
308
+ $('#ewww-restore-originals-messages').append(ewww_vars.finished);
309
+ $('#ewww-restore-originals-messages').show();
310
+ return false;
311
+ }
312
+ if (ewww_response.messages) {
313
+ $('#ewww-restore-originals-messages').append(ewww_response.messages);
314
+ $('#ewww-restore-originals-messages').show();
315
+ }
316
+ ewww_total_restored += ewww_response.completed;
317
+ $('#ewww-restore-originals-progressbar').progressbar("option", "value", ewww_total_restored);
318
+ $('#ewww-restore-originals-progress').html('<p>' + ewww_total_restored + '/' + ewww_vars.restorable_images + '</p>');
319
+ if ( ewww_total_restored > ewww_vars.restorable_images + 100 ) {
320
+ $('#ewww-restore-originals-messages').append('<p><b>' + ewww_vars.too_far) + '</b></p>';
321
+ }
322
+ ewwwRestoreOriginals();
323
+ });
324
+ }
325
  var ewww_total_originals = 0;
326
  var ewww_original_attachments = false;
327
  $('#ewww-clean-originals').on( 'submit', function() {
467
  ewwwCleanConvertedOriginals(converted_offset);
468
  });
469
  }
470
+ var ewww_total_webp = 0;
471
+ var ewww_webp_cleaned = 0;
472
  $('#ewww-clean-webp').on( 'submit', function() {
473
  var ewww_webp_data = {
474
+ action: 'ewwwio_webp_attachment_count',
475
  ewww_wpnonce: ewww_vars._wpnonce,
476
  };
477
  var header_label = $(this).find('input[type="submit"]').val();
487
  console.log(response);
488
  return false;
489
  }
490
+ ewww_total_webp = ewww_webp_attachments.total;
491
  $('.ewww-tool-info').hide();
492
  $('.ewww-tool-form').hide();
493
  $('.ewww-tool-divider').hide();
500
  return false;
501
  });
502
  function ewwwRemoveWebPByID(){
 
 
503
  var ewww_webp_data = {
504
  action: 'bulk_aux_images_delete_webp',
505
  ewww_wpnonce: ewww_vars._wpnonce,
 
506
  };
507
  $.post(ajaxurl, ewww_webp_data, function(response) {
508
  try {
519
  $('#ewww-clean-webp-progress').html('<span style="color: red"><b>' + ewww_response.error + '</b></span>');
520
  return false;
521
  }
522
+ if(ewww_response.finished) {
523
+ ewww_total_webp = ewww_vars.webp_cleanable;
524
+ ewww_webp_cleaned = 0;
525
  $('#ewww-clean-webp-progressbar').progressbar({ max: ewww_total_webp });
526
  $('#ewww-clean-webp-progressbar').progressbar("option", "value", 0);
527
  $('#ewww-clean-webp-progress').html('<p>' + ewww_vars.stage2 + ' 0/' + ewww_total_webp + '</p>');
528
+ ewwwRemoveWebP();
529
  return false;
530
  }
531
+ ewww_webp_cleaned++;
532
+ $('#ewww-clean-webp-progressbar').progressbar("option", "value", ewww_webp_cleaned);
533
+ $('#ewww-clean-webp-progress').html('<p>' + ewww_vars.stage1 + ' ' + ewww_webp_cleaned + '/' + ewww_total_webp + '</p>');
534
  ewwwRemoveWebPByID();
535
  });
536
  }
537
+ function ewwwRemoveWebP(){
538
  var ewww_webp_data = {
539
  action: 'bulk_aux_images_webp_clean',
540
  ewww_wpnonce: ewww_vars._wpnonce,
 
541
  };
542
  $.post(ajaxurl, ewww_webp_data, function(response) {
543
  try {
558
  $('#ewww-clean-webp-progress').html(ewww_vars.finished);
559
  return false;
560
  }
561
+ ewww_webp_cleaned += ewww_response.completed;
562
+ $('#ewww-clean-webp-progressbar').progressbar("option", "value", ewww_webp_cleaned);
563
+ $('#ewww-clean-webp-progress').html('<p>' + ewww_vars.stage2 + ' ' + ewww_webp_cleaned + '/' + ewww_total_webp + '</p>');
564
+ ewwwRemoveWebP();
565
  });
566
  }
567
  $('#ewww-clean-table').on( 'submit', function() {
685
  $('.ewww-aux-table').on( 'click', '.ewww-restore-image', function() {
686
  var imageID = $(this).data('id');
687
  var ewww_image_restore = {
688
+ action: 'ewww_manual_image_restore_single',
689
  ewww_wpnonce: ewww_vars._wpnonce,
690
  ewww_image_id: imageID,
691
  };
includes/flag.js CHANGED
@@ -18,11 +18,11 @@ jQuery(document).on( 'click', '.ewww-manual-optimize', function() {
18
  });
19
  return false;
20
  });
21
- jQuery(document).on( 'click', '.ewww-manual-cloud-restore', function() {
22
  var post_id = jQuery(this).data('id');
23
  var ewww_nonce = jQuery(this).data('nonce');
24
  var ewww_manual_optimize_data = {
25
- action: 'ewww_flag_cloud_restore',
26
  ewww_manual_nonce: ewww_nonce,
27
  ewww_attachment_ID: post_id,
28
  };
18
  });
19
  return false;
20
  });
21
+ jQuery(document).on( 'click', '.ewww-manual-image-restore', function() {
22
  var post_id = jQuery(this).data('id');
23
  var ewww_nonce = jQuery(this).data('nonce');
24
  var ewww_manual_optimize_data = {
25
+ action: 'ewww_flag_image_restore',
26
  ewww_manual_nonce: ewww_nonce,
27
  ewww_attachment_ID: post_id,
28
  };
includes/media.js CHANGED
@@ -73,11 +73,11 @@ jQuery(document).on('click', '.ewww-manual-restore', function() {
73
  });
74
  return false;
75
  });
76
- jQuery(document).on('click', '.ewww-manual-cloud-restore', function() {
77
  var post_id = jQuery(this).data('id');
78
  var ewww_nonce = jQuery(this).data('nonce');
79
  var ewww_manual_optimize_data = {
80
- action: 'ewww_manual_cloud_restore',
81
  ewww_manual_nonce: ewww_nonce,
82
  ewww_attachment_ID: post_id,
83
  };
73
  });
74
  return false;
75
  });
76
+ jQuery(document).on('click', '.ewww-manual-image-restore', function() {
77
  var post_id = jQuery(this).data('id');
78
  var ewww_nonce = jQuery(this).data('nonce');
79
  var ewww_manual_optimize_data = {
80
+ action: 'ewww_manual_image_restore',
81
  ewww_manual_nonce: ewww_nonce,
82
  ewww_attachment_ID: post_id,
83
  };
includes/nextgen.js CHANGED
@@ -18,11 +18,11 @@ jQuery(document).on( 'click', '.ewww-manual-optimize', function() {
18
  });
19
  return false;
20
  });
21
- jQuery(document).on( 'click', '.ewww-manual-cloud-restore', function() {
22
  var post_id = jQuery(this).data('id');
23
  var ewww_nonce = jQuery(this).data('nonce');
24
  var ewww_manual_optimize_data = {
25
- action: 'ewww_ngg_cloud_restore',
26
  ewww_manual_nonce: ewww_nonce,
27
  ewww_attachment_ID: post_id,
28
  };
18
  });
19
  return false;
20
  });
21
+ jQuery(document).on( 'click', '.ewww-manual-image-restore', function() {
22
  var post_id = jQuery(this).data('id');
23
  var ewww_nonce = jQuery(this).data('nonce');
24
  var ewww_manual_optimize_data = {
25
+ action: 'ewww_ngg_image_restore',
26
  ewww_manual_nonce: ewww_nonce,
27
  ewww_attachment_ID: post_id,
28
  };
mwebp.php CHANGED
@@ -242,4 +242,3 @@ add_action( 'admin_enqueue_scripts', 'ewww_image_optimizer_webp_script' );
242
  add_action( 'wp_ajax_webp_init', 'ewww_image_optimizer_webp_initialize' );
243
  add_action( 'wp_ajax_webp_loop', 'ewww_image_optimizer_webp_loop' );
244
  add_action( 'wp_ajax_webp_cleanup', 'ewww_image_optimizer_webp_cleanup' );
245
- ?>
242
  add_action( 'wp_ajax_webp_init', 'ewww_image_optimizer_webp_initialize' );
243
  add_action( 'wp_ajax_webp_loop', 'ewww_image_optimizer_webp_loop' );
244
  add_action( 'wp_ajax_webp_cleanup', 'ewww_image_optimizer_webp_cleanup' );
 
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: optimize, image, convert, webp, resize, compress, lazy load, optimization,
5
  Requires at least: 5.8
6
  Tested up to: 6.0
7
  Requires PHP: 7.2
8
- Stable tag: 6.7.0
9
  License: GPLv3
10
 
11
  Smaller Images, Faster Sites, Happier Visitors. Comprehensive image optimization that doesn't require a degree in rocket science.
@@ -137,6 +137,16 @@ That's not a question, but since I made it up, I'll answer it. See this resource
137
  * Feature requests can be viewed and submitted on our [feedback portal](https://feedback.ewww.io/b/features)
138
  * If you would like to help translate this plugin in your language, [join the team](https://translate.wordpress.org/projects/wp-plugins/ewww-image-optimizer/)
139
 
 
 
 
 
 
 
 
 
 
 
140
  = 6.7.0 =
141
  * added: API keys can be used to auto-register sites for Easy IO, including sub-keys
142
  * changed: expose legacy resize dimensions with removal option
5
  Requires at least: 5.8
6
  Tested up to: 6.0
7
  Requires PHP: 7.2
8
+ Stable tag: 6.8.0
9
  License: GPLv3
10
 
11
  Smaller Images, Faster Sites, Happier Visitors. Comprehensive image optimization that doesn't require a degree in rocket science.
137
  * Feature requests can be viewed and submitted on our [feedback portal](https://feedback.ewww.io/b/features)
138
  * If you would like to help translate this plugin in your language, [join the team](https://translate.wordpress.org/projects/wp-plugins/ewww-image-optimizer/)
139
 
140
+ = 6.8.0 =
141
+ * added: ability to store image backups on local storage
142
+ * added: tool to bulk restore images under Tools menu and WP-CLI
143
+ * added: WebP cleanup tool can be resumed and run via WP-CLI
144
+ * added: Delete Originals can be run via WP-CLI
145
+ * added: remove originals after conversion (like PNG to JPG) via WP-CLI
146
+ * added: exclude by page for Easy IO, Lazy Load, and WebP delivery methods
147
+ * changed: ensure full-size image is optimized after resizing with Imsanity
148
+ * fixed: incorrect cfasync attribute used for JS WebP scripts
149
+
150
  = 6.7.0 =
151
  * added: API keys can be used to auto-register sites for Easy IO, including sub-keys
152
  * changed: expose legacy resize dimensions with removal option
unique.php CHANGED
@@ -154,6 +154,7 @@ function ewww_image_optimizer_set_defaults() {
154
  add_option( 'ewww_image_optimizer_svg_level', '0' );
155
  add_option( 'ewww_image_optimizer_jpg_quality', '' );
156
  add_option( 'ewww_image_optimizer_webp_quality', '' );
 
157
  add_option( 'ewww_image_optimizer_resize_existing', true );
158
  add_option( 'ewww_image_optimizer_exactdn', false );
159
  add_option( 'ewww_image_optimizer_exactdn_plan_id', 0 );
@@ -185,6 +186,7 @@ function ewww_image_optimizer_set_defaults() {
185
  add_site_option( 'ewww_image_optimizer_svg_level', '0' );
186
  add_site_option( 'ewww_image_optimizer_jpg_quality', '' );
187
  add_site_option( 'ewww_image_optimizer_webp_quality', '' );
 
188
  add_site_option( 'ewww_image_optimizer_resize_existing', true );
189
  add_site_option( 'ewww_image_optimizer_disable_pngout', true );
190
  add_site_option( 'ewww_image_optimizer_disable_svgcleaner', true );
154
  add_option( 'ewww_image_optimizer_svg_level', '0' );
155
  add_option( 'ewww_image_optimizer_jpg_quality', '' );
156
  add_option( 'ewww_image_optimizer_webp_quality', '' );
157
+ add_option( 'ewww_image_optimizer_backup_files', '' );
158
  add_option( 'ewww_image_optimizer_resize_existing', true );
159
  add_option( 'ewww_image_optimizer_exactdn', false );
160
  add_option( 'ewww_image_optimizer_exactdn_plan_id', 0 );
186
  add_site_option( 'ewww_image_optimizer_svg_level', '0' );
187
  add_site_option( 'ewww_image_optimizer_jpg_quality', '' );
188
  add_site_option( 'ewww_image_optimizer_webp_quality', '' );
189
+ add_site_option( 'ewww_image_optimizer_backup_files', '' );
190
  add_site_option( 'ewww_image_optimizer_resize_existing', true );
191
  add_site_option( 'ewww_image_optimizer_disable_pngout', true );
192
  add_site_option( 'ewww_image_optimizer_disable_svgcleaner', true );