\n";
// Find out if the auxiliary image table has anything in it.
$already_optimized = ewww_image_optimizer_aux_images_table_count();
if ( ! $already_optimized ) {
esc_html_e( 'Nothing has been optimized yet!', 'ewww-image-optimizer' );
echo "
\n";
return;
}
echo "
\n";
echo "
" .
/* translators: %s: number of images */
sprintf( esc_html__( 'The plugin keeps track of already optimized images to prevent re-optimization. There are %s images that have been optimized so far.', 'ewww-image-optimizer' ), esc_html( number_format_i18n( $already_optimized ) ) ) .
"
" . sprintf( esc_html__( 'Current queue status: %s', 'ewww-image-optimizer' ), esc_html( $queue_status ) ) . " \n";
if ( $queue_count ) {
/* translators: %d: number of images */
echo sprintf( esc_html__( 'There are %d images in the queue currently.', 'ewww-image-optimizer' ), (int) $queue_count ) . "
\n";
$nonce = wp_create_nonce( 'ewww_image_optimizer_clear_queue' );
echo "\n";
} else {
echo esc_html__( 'There are no images in the queue currently.', 'ewww-image-optimizer' ) . "\n";
}
echo '';
echo "
\n
" .
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' );
echo "
";
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_backup_files' ) ) {
/* translators: %s: 'cloud' or 'local', translated separately */
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 ) );
if ( ! get_option( 'ewww_image_optimizer_bulk_restore_position' ) ) {
echo ' ';
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' );
}
} else {
esc_html_e( 'Backups are currently disabled in the Local settings.', 'ewww-image-optimizer' );
}
echo "
" .
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' ) . "
\n";
echo "\n
\n";
echo "";
echo "";
echo '';
echo "
\n
" .
esc_html__( 'If you have converted images (PNG to JPG and friends) without deleting the originals, you may remove them when ready.', 'ewww-image-optimizer' ) . " \n" .
'' . esc_html__( 'Please perform a site backup before proceeding.', 'ewww-image-optimizer' ) . "
\n";
echo "\n
\n";
echo "";
echo "";
echo '';
echo "
\n
" .
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' ) . "
" .
esc_html__( 'Older sites may have duplicate records or references to deleted files. Use the cleanup tool to remove such records.', 'ewww-image-optimizer' ) . ' ' .
'' . esc_html__( 'If you offload your media to external storage like Amazon S3, and remove the local files, do not run this tool.', 'ewww-image-optimizer' ) . "
" .
/* translators: 1: postmeta table name 2: ewwwio_images table name */
esc_html( sprintf( __( 'Sites using EWWW IO for 3+ years may have optimization data that still needs to be migrated between the %1$s and %2$s tables.', 'ewww-image-optimizer' ), $wpdb->postmeta, $wpdb->ewwwio_images ) ) . "
\n";
echo "\n
\n";
echo "";
echo "";
echo '';
echo "
" . esc_html__( 'Some plugins have bugs that cause them to re-create thumbnails and trigger re-optimization when the images are modified. Turn on the Debugging option to record trace logs for further investigation.', 'ewww-image-optimizer' ) . "
\n";
echo "\n";
echo "
\n";
}
/**
* Outputs the navigation controls for the optimized images table.
*
* @param string $location The placement of the controls relative to the table, either 'top' or 'bottom'.
*/
function ewwwio_table_nav_controls( $location = 'top' ) {
?>
' . __FUNCTION__ . '()' );
// Make sure we are being called from the bulk optimization page.
if ( 'tools_page_ewww-image-optimizer-tools' !== $hook ) {
return;
}
add_filter( 'admin_footer_text', 'ewww_image_optimizer_footer_review_text' );
wp_enqueue_script( 'ewww-tool-script', plugins_url( '/includes/eio-tools.js', __FILE__ ), array( 'jquery', 'jquery-ui-progressbar' ), EWWW_IMAGE_OPTIMIZER_VERSION, true );
// Number of images in the ewwwio_table (previously optimized images).
$image_count = ewww_image_optimizer_aux_images_table_count();
// Submit a couple variables for our javascript to work with.
$loading_image = plugins_url( '/images/wpspin.gif', __FILE__ );
$erase_warning = esc_html__( 'Warning: this cannot be undone and will cause a bulk optimize to re-optimize all images.', 'ewww-image-optimizer' );
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ) ) {
$erase_warning = esc_html__( 'Warning: this cannot be undone. Re-optimizing images will use additional API credits.', 'ewww-image-optimizer' );
}
global $wpdb;
$attachment_count = (int) $wpdb->get_var( "SELECT count(ID) FROM $wpdb->posts WHERE post_type = 'attachment' AND (post_mime_type LIKE '%%image%%' OR post_mime_type LIKE '%%pdf%%') ORDER BY ID DESC" );
$restore_position = (int) get_option( 'ewww_image_optimizer_bulk_restore_position' );
$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 ) );
$webp_clean_resume = get_option( 'ewww_image_optimizer_webp_clean_position' );
$webp_position = is_array( $webp_clean_resume ) && ! empty( $webp_clean_resume['stage2'] ) ? (int) $webp_clean_resume['stage2'] : 0;
$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 ) );
wp_localize_script(
'ewww-tool-script',
'ewww_vars',
array(
'_wpnonce' => wp_create_nonce( 'ewww-image-optimizer-tools' ),
'image_count' => $image_count,
'attachment_count' => $attachment_count,
/* translators: %d: number of attachments from Media Library */
'attachment_string' => sprintf( esc_html__( '%d attachments', 'ewww-image-optimizer' ), $attachment_count ),
/* translators: %d: number of images */
'count_string' => sprintf( esc_html__( '%d total images', 'ewww-image-optimizer' ), $image_count ),
'remove_failed' => esc_html__( 'Could not remove image from table.', 'ewww-image-optimizer' ),
'invalid_response' => esc_html__( 'Received an invalid response from your website, please check for errors in the Developer Tools console of your browser.', 'ewww-image-optimizer' ),
'original_restored' => esc_html__( 'Original Restored', 'ewww-image-optimizer' ),
'restoring' => '
',
'stage1' => esc_html__( 'Stage 1:', 'ewww-image-optimizer' ),
'stage2' => esc_html__( 'Stage 2:', 'ewww-image-optimizer' ),
/* translators: used for Table Cleanup progress bar, like so: batch 32/346 */
'batch' => esc_html__( 'batch', 'ewww-image-optimizer' ),
'erase_warning' => $erase_warning,
'tool_warning' => esc_html__( 'Please be sure to backup your site before proceeding. Do you wish to continue?', 'ewww-image-optimizer' ),
'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' ),
'restorable_images' => $restorable_images,
'webp_cleanable' => $webp_cleanable,
)
);
// Load the stylesheet for the jquery progressbar.
wp_enqueue_style( 'jquery-ui-progressbar', plugins_url( '/includes/jquery-ui-1.10.1.custom.css', __FILE__ ) );
ewwwio_memory( __FUNCTION__ );
}
/**
* Presents the bulk optimize form.
*/
function ewww_image_optimizer_bulk_preview() {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
ewwwio_debug_version_info();
// Retrieve the attachment IDs that were pre-loaded in the database.
echo '
' .
/* translators: 1: number of images 2: number of registered image sizes */
esc_html( sprintf( _n( '%1$s uploaded item in the Media Library has been selected with up to %2$d image files per upload.', '%1$s uploaded items in the Media Library have been selected with up to %2$d image files per upload.', $fullsize_count, 'ewww-image-optimizer' ), number_format_i18n( $fullsize_count ), $resize_count ) ) .
' ' . esc_html__( 'The total number of images found will be displayed before optimization begins.', 'ewww-image-optimizer' ) .
'
';
} else {
echo '
' .
/* translators: 1: number of images 2: number of registered image sizes */
esc_html( sprintf( _n( '%1$s uploaded item in the Media Library has been selected with up to %2$d image files per upload.', '%1$s uploaded items in the Media Library have been selected with up to %2$d image files per upload.', $fullsize_count, 'ewww-image-optimizer' ), number_format_i18n( $fullsize_count ), $resize_count ) ) .
' ' . esc_html__( 'The total number of images found will be displayed before optimization begins.', 'ewww-image-optimizer' ) .
' ' .
esc_html__( 'The active theme, BuddyPress, WP Symposium, and folders that you have configured will also be scanned for unoptimized images.', 'ewww-image-optimizer' ) .
'
';
}
}
ewww_image_optimizer_bulk_action_output( $button_text, $fullsize_count, $resume );
}
// If the 'bulk resume' option was not empty, offer to reset it so the user can start back from the beginning.
if ( 'true' === $resume ) {
ewww_image_optimizer_bulk_reset_form_output();
}
echo '';
ewwwio_memory( __FUNCTION__ );
ewww_image_optimizer_aux_images();
}
/**
* Make sure folks know their images will be resized during bulk optimization.
*/
function ewww_image_optimizer_bulk_resize_warning_message() {
if (
( ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediawidth' ) || ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediaheight' ) )
) {
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_resize_other_existing' ) ) {
printf(
/* translators: 1: width in pixels, 2: height in pixels */
esc_html__( 'All images will be scaled to %1$d x %2$d.', 'ewww-image-optimizer' ),
(int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediawidth' ),
(int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediaheight' )
);
} else {
printf(
/* translators: 1: width in pixels, 2: height in pixels */
esc_html__( 'All images in the Media Library will be scaled to %1$d x %2$d.', 'ewww-image-optimizer' ),
(int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediawidth' ),
(int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_maxmediaheight' )
);
}
}
}
/**
* Outputs the status area and delay/force controls for the Bulk optimize page.
*/
function ewww_image_optimizer_bulk_head_output() {
$loading_image = plugins_url( '/images/wpspin.gif', __FILE__ );
$delay = ewww_image_optimizer_get_option( 'ewww_image_optimizer_delay' ) ? (int) ewww_image_optimizer_get_option( 'ewww_image_optimizer_delay' ) : 0;
?>
force_smart ) ) ? ' checked' : ''; ?>>
webp_only ) ) ? ' checked' : ''; ?>>
' . __FUNCTION__ . '()' );
$permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', 'manage_options' );
if ( false === current_user_can( $permissions ) ) {
wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) );
}
check_admin_referer( 'ewww_image_optimizer_clear_queue', 'ewww_nonce' );
update_option( 'ewww_image_optimizer_pause_queues', false, false );
update_option( 'ewww_image_optimizer_pause_image_queue', false, false );
update_option( 'ewww_image_optimizer_aux_resume', '' );
update_option( 'ewww_image_optimizer_bulk_resume', '' );
ewwwio()->background_media->cancel_process();
ewwwio()->background_image->cancel_process();
ewww_image_optimizer_delete_pending();
update_option( 'ewwwio_stop_scheduled_scan', true, false );
sleep( 5 ); // Give the queues a little time to complete in-process items.
wp_safe_redirect( wp_get_referer() );
exit;
}
/**
* Pause the image queues until further notice.
*/
function ewww_image_optimizer_pause_queue() {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
$permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', 'manage_options' );
if ( false === current_user_can( $permissions ) ) {
wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) );
}
check_admin_referer( 'ewww_image_optimizer_clear_queue', 'ewww_nonce' );
update_option( 'ewww_image_optimizer_pause_queues', true, false );
update_option( 'ewwwio_stop_scheduled_scan', true, false );
wp_safe_redirect( wp_get_referer() );
exit;
}
/**
* Resumes async queues.
*/
function ewww_image_optimizer_resume_queue() {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
$permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', 'manage_options' );
if ( false === current_user_can( $permissions ) ) {
wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) );
}
check_admin_referer( 'ewww_image_optimizer_clear_queue', 'ewww_nonce' );
update_option( 'ewww_image_optimizer_pause_queues', false, false );
update_option( 'ewww_image_optimizer_pause_image_queue', false, false );
delete_option( 'ewwwio_stop_scheduled_scan' );
if ( ! ewwwio()->background_media->is_process_running() ) {
ewwwio_debug_message( 'media process idle, dispatching post-haste' );
ewwwio()->background_media->dispatch();
}
if ( ! ewwwio()->background_image->is_process_running() ) {
ewwwio_debug_message( 'media process idle, dispatching post-haste' );
ewwwio()->background_image->dispatch();
}
wp_safe_redirect( wp_get_referer() );
exit;
}
/**
* Retrieve image counts for the bulk process.
*
* For the media library, returns a simple count of the number of attachments. For other galleries,
* counts the number of thumbnails/resizes along with how many of each need to be optimized. Uses
* attachment "metadata" to calculate the counts, which will not be accurate for long.
*
* @param string $gallery Bulk page that is calling the function. Accepts 'media', 'ngg', and 'flag'.
* @return int|array {
* The image count(s) found during the search.
*
* @type int $full_count The number of original uploads found.
* @type int $resize_count The number of thumbnails/resizes found.
* }
*/
function ewww_image_optimizer_count_optimized( $gallery ) {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
ewwwio_debug_message( "scanning for $gallery" );
global $wpdb;
$full_count = 0;
$resize_count = 0;
$attachment_query = '';
$started = microtime( true ); // Retrieve the time when the counting starts.
$max_query = (int) apply_filters( 'ewww_image_optimizer_count_optimized_queries', 4000 );
/**
* Set a maximum for a query, 1k less than WPE's 16k limit, just to be safe.
*
* @param int 15000 The maximum query length.
*/
$max_query_length = apply_filters( 'ewww_image_optimizer_max_query_length', 15000 );
$attachment_query_count = 0;
switch ( $gallery ) {
case 'media':
return ewww_image_optimizer_count_attachments();
break;
case 'ngg':
// See if we were given attachment IDs to work with via GET/POST.
if ( ! empty( $_REQUEST['doaction'] ) || get_option( 'ewww_image_optimizer_bulk_ngg_resume' ) ) { // phpcs:ignore WordPress.Security.NonceVerification
// Retrieve the attachment IDs that were pre-loaded in the database.
$attachment_ids = get_option( 'ewww_image_optimizer_bulk_ngg_attachments' );
array_walk( $attachment_ids, 'intval' );
while ( $attachment_ids && strlen( $attachment_query ) < $max_query_length ) {
$attachment_query .= "'" . array_pop( $attachment_ids ) . "',";
++$attachment_query_count;
}
$attachment_query = 'WHERE pid IN (' . substr( $attachment_query, 0, -1 ) . ')';
$max_query = $attachment_query_count;
}
// Get an array of sizes available for the $image.
global $ewwwngg;
$sizes = $ewwwngg->get_image_sizes();
$offset = 0;
$attachments = $wpdb->get_col( "SELECT meta_data FROM $wpdb->nggpictures $attachment_query LIMIT $offset, $max_query" ); // phpcs:ignore WordPress.DB.PreparedSQL
while ( $attachments ) {
foreach ( $attachments as $attachment ) {
if ( class_exists( 'Ngg_Serializable' ) ) {
$serializer = new Ngg_Serializable();
$meta = $serializer->unserialize( $attachment );
} elseif ( class_exists( 'C_NextGen_Serializable' ) ) {
$meta = C_NextGen_Serializable::unserialize( $attachment );
} else {
$meta = unserialize( $attachment );
}
if ( ! is_array( $meta ) ) {
continue;
}
$ngg_sizes = $ewwwngg->maybe_get_more_sizes( $sizes, $meta );
if ( ewww_image_optimizer_iterable( $ngg_sizes ) ) {
foreach ( $ngg_sizes as $size ) {
if ( 'full' !== $size ) {
++$resize_count;
}
}
}
}
$full_count += count( $attachments );
$offset += $max_query;
if ( ! empty( $attachment_ids ) ) {
$attachment_query = '';
$attachment_query_count = 0;
$offset = 0;
while ( $attachment_ids && strlen( $attachment_query ) < $max_query_length ) {
$attachment_query .= "'" . array_pop( $attachment_ids ) . "',";
++$attachment_query_count;
}
$attachment_query = 'WHERE pid IN (' . substr( $attachment_query, 0, -1 ) . ')';
$max_query = $attachment_query_count;
}
$attachments = $wpdb->get_col( "SELECT meta_data FROM $wpdb->nggpictures $attachment_query LIMIT $offset, $max_query" ); // phpcs:ignore WordPress.DB.PreparedSQL
} // End while().
break;
case 'flag':
if ( ! empty( $_REQUEST['doaction'] ) || get_option( 'ewww_image_optimizer_bulk_flag_resume' ) ) { // phpcs:ignore WordPress.Security.NonceVerification
// Retrieve the attachment IDs that were pre-loaded in the database.
$attachment_ids = get_option( 'ewww_image_optimizer_bulk_flag_attachments' );
array_walk( $attachment_ids, 'intval' );
while ( $attachment_ids && strlen( $attachment_query ) < $max_query_length ) {
$attachment_query .= "'" . array_pop( $attachment_ids ) . "',";
++$attachment_query_count;
}
$attachment_query = 'WHERE pid IN (' . substr( $attachment_query, 0, -1 ) . ')';
$max_query = $attachment_query_count;
}
$offset = 0;
$attachments = $wpdb->get_col( "SELECT meta_data FROM $wpdb->flagpictures $attachment_query LIMIT $offset, $max_query" ); // phpcs:ignore WordPress.DB.PreparedSQL
while ( $attachments ) {
foreach ( $attachments as $attachment ) {
$meta = unserialize( $attachment );
if ( ! is_array( $meta ) ) {
continue;
}
if ( ! empty( $meta['webview'] ) ) {
++$resize_count;
}
if ( ! empty( $meta['thumbnail'] ) ) {
++$resize_count;
}
}
$full_count += count( $attachments );
$offset += $max_query;
if ( ! empty( $attachment_ids ) ) {
$attachment_query = '';
$attachment_query_count = 0;
$offset = 0;
while ( $attachment_ids && strlen( $attachment_query ) < $max_query_length ) {
$attachment_query .= "'" . array_pop( $attachment_ids ) . "',";
++$attachment_query_count;
}
$attachment_query = 'WHERE pid IN (' . substr( $attachment_query, 0, -1 ) . ')';
$max_query = $attachment_query_count;
}
$attachments = $wpdb->get_col( "SELECT meta_data FROM $wpdb->flagpictures $attachment_query LIMIT $offset, $max_query" ); // phpcs:ignore WordPress.DB.PreparedSQL
}
break;
} // End switch().
if ( empty( $full_count ) && ! empty( $attachment_ids ) ) {
ewwwio_debug_message( 'query appears to have failed, just counting total images instead' );
$full_count = count( $attachment_ids );
}
$elapsed = microtime( true ) - $started;
ewwwio_debug_message( "counting images took $elapsed seconds" );
ewwwio_debug_message( "found $full_count fullsize and $resize_count resizes" );
ewwwio_memory( __FUNCTION__ );
return array( $full_count, $resize_count );
}
/**
* Prepares the bulk operation and includes the javascript functions.
*
* Checks to see if a scan was in progress, or if attachment IDs were POSTed, and loads the
* appropriate attachments into the list to be scanned. Also sets up the js includes, and
* defines a few js variables needed for the bulk operation.
*
* @global object $wpdb
*
* @param string $hook An indicator if this was not called from AJAX, like WP-CLI.
*/
function ewww_image_optimizer_bulk_script( $hook ) {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
// Make sure we are being called from the bulk optimization page.
if ( 'media_page_ewww-image-optimizer-bulk' !== $hook ) {
return;
}
add_filter( 'admin_footer_text', 'ewww_image_optimizer_footer_review_text' );
global $wpdb;
// Initialize the $attachments variable.
$attachments = array();
// Check to see if we are supposed to reset the bulk operation and verify we are authorized to do so.
if ( ! empty( $_REQUEST['ewww_reset'] ) && ! empty( $_REQUEST['ewww_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-bulk-reset' ) ) {
ewwwio_debug_message( 'resetting resume flags' );
// Set the 'bulk resume' option to an empty string to reset the bulk operation.
update_option( 'ewww_image_optimizer_bulk_resume', '' );
update_option( 'ewww_image_optimizer_aux_resume', '' );
ewww_image_optimizer_delete_queue_images();
ewww_image_optimizer_delete_pending();
}
// Check to see if we are supposed to convert the auxiliary images table and verify we are authorized to do so.
if ( ! empty( $_REQUEST['ewww_convert'] ) && ! empty( $_REQUEST['ewww_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-aux-images-convert' ) ) {
ewww_image_optimizer_aux_images_convert();
}
if ( ! empty( $_GET['ewww_webp_only'] ) ) {
ewwwio()->webp_only = true;
}
if ( ! empty( $_GET['ewww_force'] ) ) {
ewwwio()->force = true;
}
// Check the 'bulk resume' option.
$resume = get_option( 'ewww_image_optimizer_bulk_resume' );
$scanning = get_option( 'ewww_image_optimizer_aux_resume' );
if ( 'scanning' !== $scanning && ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_auto' ) ) {
$scanning = false;
}
if ( get_option( 'ewww_image_optimizer_pause_queues' ) || get_option( 'ewww_image_optimizer_pause_image_queue' ) ) {
if ( ewwwio()->background_media->count_queue() || ewwwio()->background_image->count_queue() ) {
$resume = true;
}
}
if ( ! $resume && ! $scanning ) {
ewwwio_debug_message( 'not resuming/scanning, so clearing any pending images in both tables' );
ewww_image_optimizer_delete_queue_images();
ewww_image_optimizer_delete_pending();
}
// See if we were given attachment IDs to work with via GET/POST.
$ids = array();
if ( ! empty( $_REQUEST['ids'] ) && ( preg_match( '/^[\d,]+$/', sanitize_text_field( wp_unslash( $_REQUEST['ids'] ) ), $request_ids ) || is_numeric( sanitize_text_field( wp_unslash( $_REQUEST['ids'] ) ) ) ) ) {
ewww_image_optimizer_delete_pending();
set_transient( 'ewww_image_optimizer_skip_aux', true, 3 * MINUTE_IN_SECONDS );
if ( is_numeric( sanitize_text_field( wp_unslash( $_REQUEST['ids'] ) ) ) ) {
$ids[] = (int) $_REQUEST['ids'];
} else {
$ids = explode( ',', $request_ids[0] );
array_walk( $ids, 'intval' );
}
ewwwio_debug_message( "validating requested ids: {$request_ids[0]}" );
// Retrieve post IDs correlating to the IDs submitted to make sure they are all valid.
$attachments = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND (post_mime_type LIKE '%%image%%' OR post_mime_type LIKE '%%pdf%%') AND ID IN ({$request_ids[0]}) ORDER BY ID DESC" ); // phpcs:ignore WordPress.DB.PreparedSQL
// Unset the 'bulk resume' option since we were given specific IDs to optimize.
update_option( 'ewww_image_optimizer_bulk_resume', '' );
// Check if there is a previous bulk operation to resume.
} elseif ( $scanning || $resume ) {
ewwwio_debug_message( 'scanning/resuming, nothing doing' );
} elseif ( empty( $attachments ) ) {
ewwwio_debug_message( 'load em all up' );
// Since we aren't resuming, and weren't given a list of IDs, we will optimize everything.
delete_transient( 'ewww_image_optimizer_scan_aux' );
// Load up all the image attachments we can find.
$attachments = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND (post_mime_type LIKE '%%image%%' OR post_mime_type LIKE '%%pdf%%') ORDER BY ID DESC" );
} // End if().
if ( ! empty( $attachments ) ) {
// Store the attachment IDs we retrieved in the queue table so we can keep track of our progress in the database.
ewwwio_debug_message( 'loading attachments into queue table' );
ewww_image_optimizer_insert_unscanned( $attachments );
$attachment_count = count( $attachments );
} else {
$attachment_count = ewww_image_optimizer_count_unscanned_attachments();
}
if ( empty( $attachment_count ) && ! ewww_image_optimizer_count_attachments() && ! ewww_image_optimizer_aux_images_table_count_pending() ) {
update_option( 'ewww_image_optimizer_bulk_resume', '' );
update_option( 'ewww_image_optimizer_aux_resume', '' );
}
wp_enqueue_script( 'ewww-beacon-script', plugins_url( '/includes/eio-beacon.js', __FILE__ ), array( 'jquery' ), EWWW_IMAGE_OPTIMIZER_VERSION );
wp_enqueue_script( 'ewww-bulk-script', plugins_url( '/includes/eio-bulk.js', __FILE__ ), array( 'jquery', 'jquery-ui-slider', 'jquery-ui-progressbar', 'postbox', 'dashboard' ), EWWW_IMAGE_OPTIMIZER_VERSION );
// Number of images in the ewwwio_table (previously optimized images).
$image_count = ewww_image_optimizer_aux_images_table_count();
// Submit a couple variables for our javascript to work with.
$loading_image = plugins_url( '/images/wpspin.gif', __FILE__ );
wp_localize_script(
'ewww-bulk-script',
'ewww_vars',
array(
'_wpnonce' => wp_create_nonce( 'ewww-image-optimizer-bulk' ),
'attachments' => ewww_image_optimizer_aux_images_table_count_pending(),
'image_count' => $image_count,
/* translators: %d: number of images */
'count_string' => sprintf( esc_html__( '%d images', 'ewww-image-optimizer' ), $image_count ),
'scan_fail' => esc_html__( 'Operation timed out, you may need to increase the max_execution_time or memory_limit for PHP', 'ewww-image-optimizer' ),
'scan_incomplete' => esc_html__( 'Scan did not complete, will try again', 'ewww-image-optimizer' ) . " ",
'operation_stopped' => esc_html__( 'Optimization stopped, reload page to resume.', 'ewww-image-optimizer' ),
'operation_interrupted' => esc_html__( 'Operation Interrupted', 'ewww-image-optimizer' ),
'temporary_failure' => esc_html__( 'Temporary failure, attempts remaining:', 'ewww-image-optimizer' ),
'invalid_response' => esc_html__( 'Received an invalid response from your website, please check for errors in the Developer Tools console of your browser.', 'ewww-image-optimizer' ),
'bad_attachment' => esc_html__( 'Previous failure due to broken/missing metadata, skipped resizes for attachment:', 'ewww-image-optimizer' ),
'remove_failed' => esc_html__( 'Could not remove image from table.', 'ewww-image-optimizer' ),
/* translators: used for Bulk Optimize progress bar, like so: Optimized 32/346 */
'optimized' => esc_html__( 'Optimized', 'ewww-image-optimizer' ),
'last_image_header' => esc_html__( 'Last Image Optimized', 'ewww-image-optimizer' ),
'time_remaining' => esc_html__( 'remaining', 'ewww-image-optimizer' ),
'original_restored' => esc_html__( 'Original Restored', 'ewww-image-optimizer' ),
'restoring' => '
";
// Do metadata update after full-size is processed, usually because of conversion or resizing.
if ( 'full' === $image->resize && $image->attachment_id ) {
ewwwio_debug_message( 'saving meta for ' . $image->attachment_id );
if ( ! empty( $meta ) && is_array( $meta ) ) {
clearstatcache();
if ( ! empty( $image->file ) && is_file( $image->file ) ) {
$meta['filesize'] = filesize( $image->file );
}
add_filter( 'as3cf_pre_update_attachment_metadata', '__return_true' );
$meta_saved = wp_update_attachment_metadata( $image->attachment_id, $meta );
if ( ! $meta_saved ) {
ewwwio_debug_message( 'failed to save meta' );
}
}
}
// Pull the next image.
$next_image = new EWWW_Image( $attachment, 'media' );
// When we finish all the sizes, we stop the loop so we can fire off any filters for plugins that might need to take action when an image is updated.
// The call to wp_get_attachment_metadata() will be done in a separate AJAX request for better reliability, giving it the full request time to complete.
if ( $attachment && (int) $attachment !== (int) $next_image->attachment_id ) {
if ( defined( 'WP_CLI' ) && WP_CLI ) {
remove_all_filters( 'as3cf_pre_update_attachment_metadata' );
ewwwio_debug_message( 'saving attachment meta' );
$meta = wp_get_attachment_metadata( $image->attachment_id );
if ( ewww_image_optimizer_s3_uploads_enabled() ) {
ewwwio_debug_message( 're-uploading to S3(_Uploads)' );
ewww_image_optimizer_remote_push( $meta, $image->attachment_id );
}
if ( class_exists( 'Windows_Azure_Helper' ) && function_exists( 'windows_azure_storage_wp_generate_attachment_metadata' ) ) {
$meta = windows_azure_storage_wp_generate_attachment_metadata( $meta, $image->attachment_id );
if ( Windows_Azure_Helper::delete_local_file() && function_exists( 'windows_azure_storage_delete_local_files' ) ) {
windows_azure_storage_delete_local_files( $meta, $image->attachment_id );
}
}
wp_update_attachment_metadata( $image->attachment_id, $meta );
do_action( 'ewww_image_optimizer_after_optimize_attachment', $image->attachment_id, $meta );
} else {
$batch_image_limit = 1;
$output['update_meta'] = (int) $attachment;
}
}
// When an image (attachment) is done, pull the next attachment ID off the stack.
if ( ( 'full' === $next_image->resize || empty( $next_image->resize ) ) && ! empty( $attachment ) && (int) $attachment !== (int) $next_image->attachment_id ) {
ewwwio_debug_message( 'grabbing next attachment id' );
ewww_image_optimizer_delete_queued_images( array( $attachment ) );
if ( 1 === count( $attachments ) && 1 === (int) $batch_image_limit ) {
$attachments = ewww_image_optimizer_get_queued_attachments( 'media', $batch_image_limit );
} else {
$attachment = (int) array_shift( $attachments ); // Pull the first image off the stack.
}
if ( ! empty( $attachments ) && is_array( $attachments ) ) {
$attachment = (int) $attachments[0]; // Then grab the next one (if any are left).
} else {
$attachment = 0;
}
ewwwio_debug_message( "next id is $attachment" );
$next_image = new EWWW_Image( $attachment, 'media' );
}
$image = $next_image;
$time_adjustment = $image->time_estimate();
} // End while().
ewwwio_debug_message( 'ending bulk loop for now' );
// Calculate how much time has elapsed since we started.
$elapsed = microtime( true ) - $started;
// Output how much time has elapsed since we started.
if ( defined( 'WP_CLI' ) && WP_CLI ) {
/* translators: %s: number of seconds */
WP_CLI::line( sprintf( _n( 'Elapsed: %s second', 'Elapsed: %s seconds', $elapsed, 'ewww-image-optimizer' ), number_format_i18n( $elapsed, 2 ) ) );
if ( ewww_image_optimizer_function_exists( 'sleep' ) ) {
sleep( $delay );
}
}
/* translators: %s: number of seconds */
$output['results'] .= sprintf( '
";
}
} else {
$output['done'] = 1;
if ( defined( 'WP_CLI' ) && WP_CLI ) {
delete_transient( 'ewww_image_optimizer_bulk_counter_measures' );
delete_transient( 'ewww_image_optimizer_bulk_current_image' );
return false;
}
}
ewww_image_optimizer_debug_log();
delete_transient( 'ewww_image_optimizer_bulk_counter_measures' );
delete_transient( 'ewww_image_optimizer_bulk_current_image' );
ewwwio_memory( __FUNCTION__ );
if ( defined( 'WP_CLI' ) && WP_CLI ) {
return true;
}
$output['current_time'] = time();
ewwwio_ob_clean();
die( wp_json_encode( $output ) );
}
/**
* Called via AJAX to trigger any actions by other plugins.
*/
function ewww_image_optimizer_bulk_update_meta() {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
// Verify that an authorized user has started the optimizer.
$permissions = apply_filters( 'ewww_image_optimizer_bulk_permissions', '' );
if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-bulk' ) || ! current_user_can( $permissions ) ) {
ewwwio_ob_clean();
die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) );
}
if ( empty( $_REQUEST['attachment_id'] ) ) {
die( wp_json_encode( array( 'success' => 0 ) ) );
}
$attachment_id = (int) $_REQUEST['attachment_id'];
ewww_image_optimizer_post_optimize_attachment( $attachment_id );
die( wp_json_encode( array( 'success' => 1 ) ) );
}
/**
* Run metadata updates and other actions after an attachment is done processing.
*
* @param int $attachment_id The attachment ID number.
*/
function ewww_image_optimizer_post_optimize_attachment( $attachment_id ) {
ewwwio_debug_message( '' . __FUNCTION__ . '()' );
ewwwio_debug_message( "running post opt for attachment $attachment_id" );
$meta = wp_get_attachment_metadata( $attachment_id );
$meta = ewww_image_optimizer_update_filesize_metadata( $meta, $attachment_id );
remove_filter( 'wp_update_attachment_metadata', 'ewww_image_optimizer_update_filesize_metadata', 9 );
if ( ewww_image_optimizer_s3_uploads_enabled() ) {
ewwwio_debug_message( 're-uploading to S3(_Uploads)' );
ewww_image_optimizer_remote_push( $meta, $attachment_id );
}
if ( class_exists( 'Windows_Azure_Helper' ) && function_exists( 'windows_azure_storage_wp_generate_attachment_metadata' ) ) {
$meta = windows_azure_storage_wp_generate_attachment_metadata( $meta, $attachment_id );
if ( Windows_Azure_Helper::delete_local_file() && function_exists( 'windows_azure_storage_delete_local_files' ) ) {
windows_azure_storage_delete_local_files( $meta, $attachment_id );
}
}
global $ewww_attachment;
$ewww_attachment['id'] = $attachment_id;
$ewww_attachment['meta'] = $meta;
add_filter( 'w3tc_cdn_update_attachment_metadata', 'ewww_image_optimizer_w3tc_update_files' );
wp_update_attachment_metadata( $attachment_id, $meta );
do_action( 'ewww_image_optimizer_after_optimize_attachment', $attachment_id, $meta );
}
/**
* Called by javascript to cleanup after ourselves after a bulk operation.
*/
function ewww_image_optimizer_bulk_cleanup() {
// Verify that an authorized user has started the optimizer.
$permissions = apply_filters( 'ewww_image_optimizer_bulk_permissions', '' );
if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-bulk' ) || ! current_user_can( $permissions ) ) {
ewwwio_ob_clean();
die( '
' . esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) . '
' );
}
// All done, so we can update the bulk options with empty values.
update_option( 'ewww_image_optimizer_aux_resume', '' );
update_option( 'ewww_image_optimizer_bulk_resume', '' );
// update_option( 'ewww_image_optimizer_bulk_attachments', '', false );.
delete_transient( 'ewww_image_optimizer_skip_aux' );
delete_transient( 'ewww_image_optimizer_force_reopt' );
// Let the user know we are done.
ewwwio_memory( __FUNCTION__ );
ewwwio_ob_clean();
if ( ! apply_filters( 'ewwwio_whitelabel', false ) ) {
die(
'