ewww-image-optimizer
Last commit date
bin
9 years ago
binaries
2 years ago
classes
2 months ago
docs
7 years ago
images
3 months ago
includes
2 months ago
tests
2 months ago
vendor
10 months ago
.travis.yml
5 months ago
aux-optimize.php
2 months ago
bulk.php
2 months ago
changelog.txt
2 months ago
common.php
2 months ago
composer.json
10 months ago
composer.lock
3 years ago
ewww-image-optimizer.php
2 months ago
functions.php
6 months ago
license.txt
7 years ago
mwebp.php
2 months ago
phpcs.ruleset.xml
6 months ago
phpunit.xml
6 years ago
readme.txt
2 months ago
uninstall.php
7 years ago
unique.php
3 months ago
aux-optimize.php
2259 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Functions for dealing with auxiliary images |
| 4 | * |
| 5 | * This file contains functions for bulk optimizing images outside the Media |
| 6 | * Library, and AJAX hooks for handling the image status table on the bulk |
| 7 | * optimize page. |
| 8 | * |
| 9 | * @link https://ewww.io |
| 10 | * @package EWWW_Image_Optimizer |
| 11 | */ |
| 12 | |
| 13 | if ( ! defined( 'ABSPATH' ) ) { |
| 14 | exit; |
| 15 | } |
| 16 | |
| 17 | /** |
| 18 | * Displays 50 records from the images table. |
| 19 | * |
| 20 | * Called via AJAX to find 50 records from the images table and display them |
| 21 | * with alternating row style. |
| 22 | * |
| 23 | * @global object $wpdb |
| 24 | */ |
| 25 | function ewww_image_optimizer_aux_images_table() { |
| 26 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 27 | // Verify that an authorized user has called function. |
| 28 | $permissions = apply_filters( 'ewww_image_optimizer_bulk_permissions', '' ); |
| 29 | if ( |
| 30 | empty( $_REQUEST['ewww_wpnonce'] ) || |
| 31 | ( |
| 32 | ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) && |
| 33 | ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-bulk' ) |
| 34 | ) || |
| 35 | ! current_user_can( $permissions ) |
| 36 | ) { |
| 37 | ewwwio_ob_clean(); |
| 38 | die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); |
| 39 | } |
| 40 | global $wpdb; |
| 41 | $per_page = 50; |
| 42 | $offset = empty( $_POST['ewww_offset'] ) ? 0 : $per_page * abs( (int) $_POST['ewww_offset'] ); |
| 43 | $search = empty( $_POST['ewww_search'] ) ? '' : sanitize_text_field( wp_unslash( $_POST['ewww_search'] ) ); |
| 44 | $pending = empty( $_POST['ewww_pending'] ) ? 0 : 1; |
| 45 | if ( ! empty( $_POST['ewww_skew'] ) ) { |
| 46 | $skew = (int) $_POST['ewww_skew']; |
| 47 | if ( $skew > 0 ) { |
| 48 | $offset = $offset - $per_page + $skew; |
| 49 | } |
| 50 | if ( $offset < 0 ) { |
| 51 | $offset = 0; |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | $output = array(); |
| 56 | |
| 57 | $output['show_pending_button'] = false; |
| 58 | if ( ! $pending ) { |
| 59 | $output['show_pending_button'] = ewww_image_optimizer_aux_images_table_count_pending() > 0; |
| 60 | } |
| 61 | |
| 62 | if ( $pending ) { |
| 63 | $sort_column = 'id'; |
| 64 | $sort_direction = 'DESC'; |
| 65 | $size_sort_class = ''; |
| 66 | $attachment_sort = true; |
| 67 | if ( ! empty( $_POST['ewww_size_sort'] ) && 'asc' === $_POST['ewww_size_sort'] ) { |
| 68 | $sort_column = 'orig_size'; |
| 69 | $sort_direction = 'ASC'; |
| 70 | $size_sort_class = 'ewww-size-asc'; |
| 71 | $attachment_sort = false; |
| 72 | } elseif ( ! empty( $_POST['ewww_size_sort'] ) && 'desc' === $_POST['ewww_size_sort'] ) { |
| 73 | $sort_column = 'orig_size'; |
| 74 | $sort_direction = 'DESC'; |
| 75 | $size_sort_class = 'ewww-size-desc'; |
| 76 | $attachment_sort = false; |
| 77 | } |
| 78 | if ( ! empty( $search ) ) { |
| 79 | if ( 'ASC' === $sort_direction ) { |
| 80 | $already_optimized = $wpdb->get_results( |
| 81 | $wpdb->prepare( |
| 82 | 'SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,resize_error,webp_size,webp_error,updates,UNIX_TIMESTAMP(updated) AS updated FROM %i WHERE pending=1 AND path LIKE %s ORDER BY %i ASC LIMIT %d,%d', |
| 83 | $wpdb->ewwwio_images, |
| 84 | '%' . $wpdb->esc_like( $search ) . '%', |
| 85 | $sort_column, |
| 86 | $offset, |
| 87 | $per_page |
| 88 | ), |
| 89 | ARRAY_A |
| 90 | ); |
| 91 | } elseif ( ! $attachment_sort ) { |
| 92 | $already_optimized = $wpdb->get_results( |
| 93 | $wpdb->prepare( |
| 94 | 'SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,resize_error,webp_size,webp_error,updates,UNIX_TIMESTAMP(updated) AS updated FROM %i WHERE pending=1 AND path LIKE %s ORDER BY %i DESC LIMIT %d,%d', |
| 95 | $wpdb->ewwwio_images, |
| 96 | '%' . $wpdb->esc_like( $search ) . '%', |
| 97 | $sort_column, |
| 98 | $offset, |
| 99 | $per_page |
| 100 | ), |
| 101 | ARRAY_A |
| 102 | ); |
| 103 | } else { |
| 104 | $already_optimized = $wpdb->get_results( |
| 105 | $wpdb->prepare( |
| 106 | 'SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,resize_error,webp_size,webp_error,updates,UNIX_TIMESTAMP(updated) AS updated FROM %i WHERE pending=1 AND path LIKE %s ORDER BY attachment_id DESC, %i DESC LIMIT %d,%d', |
| 107 | $wpdb->ewwwio_images, |
| 108 | '%' . $wpdb->esc_like( $search ) . '%', |
| 109 | $sort_column, |
| 110 | $offset, |
| 111 | $per_page |
| 112 | ), |
| 113 | ARRAY_A |
| 114 | ); |
| 115 | } |
| 116 | $search_count = $wpdb->get_var( |
| 117 | $wpdb->prepare( |
| 118 | "SELECT COUNT(*) FROM $wpdb->ewwwio_images WHERE pending=1 AND path LIKE %s", |
| 119 | '%' . $wpdb->esc_like( $search ) . '%' |
| 120 | ) |
| 121 | ); |
| 122 | if ( $search_count < $per_page ) { |
| 123 | /* translators: %d: number of image records found */ |
| 124 | $output['search_result'] = sprintf( esc_html__( '%d items found', 'ewww-image-optimizer' ), count( $already_optimized ) ); |
| 125 | } else { |
| 126 | /* translators: 1: number of image records displayed, 2: number of total records found */ |
| 127 | $output['search_result'] = sprintf( esc_html__( '%1$d items displayed of %2$s records found', 'ewww-image-optimizer' ), count( $already_optimized ), number_format_i18n( $search_count ) ); |
| 128 | } |
| 129 | $total = ceil( $search_count / $per_page ); |
| 130 | } else { |
| 131 | if ( 'ASC' === $sort_direction ) { |
| 132 | $already_optimized = $wpdb->get_results( |
| 133 | $wpdb->prepare( |
| 134 | 'SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,resize_error,webp_size,webp_error,updates,UNIX_TIMESTAMP(updated) AS updated FROM %i WHERE pending=1 ORDER BY %i ASC LIMIT %d,%d', |
| 135 | $wpdb->ewwwio_images, |
| 136 | $sort_column, |
| 137 | $offset, |
| 138 | $per_page |
| 139 | ), |
| 140 | ARRAY_A |
| 141 | ); |
| 142 | } elseif ( ! $attachment_sort ) { |
| 143 | $already_optimized = $wpdb->get_results( |
| 144 | $wpdb->prepare( |
| 145 | 'SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,resize_error,webp_size,webp_error,updates,UNIX_TIMESTAMP(updated) AS updated FROM %i WHERE pending=1 ORDER BY %i DESC LIMIT %d,%d', |
| 146 | $wpdb->ewwwio_images, |
| 147 | $sort_column, |
| 148 | $offset, |
| 149 | $per_page |
| 150 | ), |
| 151 | ARRAY_A |
| 152 | ); |
| 153 | } else { |
| 154 | $already_optimized = $wpdb->get_results( |
| 155 | $wpdb->prepare( |
| 156 | 'SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,resize_error,webp_size,webp_error,updates,UNIX_TIMESTAMP(updated) AS updated FROM %i WHERE pending=1 ORDER BY attachment_id DESC, %i DESC LIMIT %d,%d', |
| 157 | $wpdb->ewwwio_images, |
| 158 | $sort_column, |
| 159 | $offset, |
| 160 | $per_page |
| 161 | ), |
| 162 | ARRAY_A |
| 163 | ); |
| 164 | } |
| 165 | $search_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->ewwwio_images WHERE pending=1" ); |
| 166 | $total = ceil( $search_count / $per_page ); |
| 167 | /* translators: %d: number of image records found */ |
| 168 | $output['search_result'] = sprintf( esc_html__( '%d items displayed', 'ewww-image-optimizer' ), count( $already_optimized ) ); |
| 169 | } |
| 170 | } elseif ( ! empty( $search ) ) { |
| 171 | $already_optimized = $wpdb->get_results( |
| 172 | $wpdb->prepare( |
| 173 | 'SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,resize_error,webp_size,webp_error,updates,UNIX_TIMESTAMP(updated) AS updated FROM %i WHERE pending=0 AND image_size > 0 AND path LIKE %s ORDER BY id DESC LIMIT %d,%d', |
| 174 | $wpdb->ewwwio_images, |
| 175 | '%' . $wpdb->esc_like( $search ) . '%', |
| 176 | $offset, |
| 177 | $per_page |
| 178 | ), |
| 179 | ARRAY_A |
| 180 | ); |
| 181 | $search_count = $wpdb->get_var( |
| 182 | $wpdb->prepare( |
| 183 | 'SELECT COUNT(*) FROM %i WHERE pending=0 AND image_size > 0 AND path LIKE %s', |
| 184 | $wpdb->ewwwio_images, |
| 185 | '%' . $wpdb->esc_like( $search ) . '%' |
| 186 | ) |
| 187 | ); |
| 188 | if ( $search_count < $per_page ) { |
| 189 | /* translators: %d: number of image records found */ |
| 190 | $output['search_result'] = sprintf( esc_html__( '%d items found', 'ewww-image-optimizer' ), count( $already_optimized ) ); |
| 191 | } else { |
| 192 | /* translators: 1: number of image records displayed, 2: number of total records found */ |
| 193 | $output['search_result'] = sprintf( esc_html__( '%1$d items displayed of %2$s records found', 'ewww-image-optimizer' ), count( $already_optimized ), number_format_i18n( $search_count ) ); |
| 194 | } |
| 195 | $total = ceil( $search_count / $per_page ); |
| 196 | } else { |
| 197 | $already_optimized = $wpdb->get_results( |
| 198 | $wpdb->prepare( |
| 199 | 'SELECT path,orig_size,image_size,id,backup,attachment_id,gallery,resize_error,webp_size,webp_error,updates,UNIX_TIMESTAMP(updated) AS updated FROM %i WHERE pending=0 AND image_size > 0 ORDER BY id DESC LIMIT %d,%d', |
| 200 | $wpdb->ewwwio_images, |
| 201 | $offset, |
| 202 | $per_page |
| 203 | ), |
| 204 | ARRAY_A |
| 205 | ); |
| 206 | $search_count = $wpdb->get_var( |
| 207 | $wpdb->prepare( |
| 208 | 'SELECT COUNT(*) FROM %i WHERE pending=0 AND image_size > 0', |
| 209 | $wpdb->ewwwio_images |
| 210 | ) |
| 211 | ); |
| 212 | $total = ceil( $search_count / $per_page ); |
| 213 | if ( empty( $output['search_result'] ) ) { |
| 214 | /* translators: %d: number of image records found */ |
| 215 | $output['search_result'] = sprintf( esc_html__( '%d items displayed', 'ewww-image-optimizer' ), count( $already_optimized ) ); |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | $output['pagination'] = sprintf( |
| 220 | /* translators: 1: current page in list of images 2: total pages for list of images */ |
| 221 | esc_html__( 'page %1$s of %2$s', 'ewww-image-optimizer' ), |
| 222 | '<span class="current-page">' . ( (int) $_POST['ewww_offset'] + 1 ) . '</span>', |
| 223 | '<span class="total-pages">' . esc_html( number_format_i18n( $total ) ) . '</span>' |
| 224 | ); |
| 225 | |
| 226 | $output['search_count'] = count( $already_optimized ); |
| 227 | $output['total_images'] = $search_count; |
| 228 | $output['total_pages'] = $total; |
| 229 | |
| 230 | $output['total_images_text'] = sprintf( |
| 231 | /* translators: %d: number of images */ |
| 232 | esc_html__( '%s total images', 'ewww-image-optimizer' ), |
| 233 | '<span class="total-images">' . number_format_i18n( $search_count ) . '</span>' |
| 234 | ); |
| 235 | |
| 236 | $output['table'] = '<table class="wp-list-table widefat media" cellspacing="0"><thead><tr><th> </th>' . |
| 237 | '<th>' . esc_html__( 'Filename', 'ewww-image-optimizer' ) . '</th>' . |
| 238 | '<th style="width:120px;">' . esc_html__( 'Image Type', 'ewww-image-optimizer' ) . '</th>' . |
| 239 | '<th style="width:120px;">' . esc_html__( 'Last Optimized', 'ewww-image-optimizer' ) . '</th>'; |
| 240 | if ( $pending ) { |
| 241 | $output['table'] .= '<th class="' . esc_attr( $size_sort_class ) . '"><a class="ewww-sort-size">' . |
| 242 | esc_html__( 'Image Size', 'ewww-image-optimizer' ) . |
| 243 | '<span class="ewww-sort-grid"><span class="ewww-sort-asc dashicons dashicons-arrow-up"></span><span class="ewww-sort-desc dashicons dashicons-arrow-down"></span></span>' . |
| 244 | '</a></th></tr></thead>'; |
| 245 | } else { |
| 246 | $output['table'] .= '<th>' . esc_html__( 'Results', 'ewww-image-optimizer' ) . '</th></tr></thead>'; |
| 247 | } |
| 248 | |
| 249 | $output['table'] .= '<tbody>'; |
| 250 | |
| 251 | if ( empty( $already_optimized ) ) { |
| 252 | $output['pagination'] = sprintf( |
| 253 | /* translators: 1: current page in list of images 2: total pages for list of images */ |
| 254 | esc_html__( 'page %1$d of %2$s', 'ewww-image-optimizer' ), |
| 255 | 1, |
| 256 | '<span class="total-pages">1</span>' |
| 257 | ); |
| 258 | if ( $pending ) { |
| 259 | $output['table'] .= '<tr class="ewww-no-images"><td colspan="5">' . esc_html__( 'No images in queue.', 'ewww-image-optimizer' ) . '</td></tr>'; |
| 260 | } else { |
| 261 | $output['table'] .= '<tr class="ewww-no-images"><td colspan="5">' . esc_html__( 'No images optimized!', 'ewww-image-optimizer' ) . '</td></tr>'; |
| 262 | } |
| 263 | } else { |
| 264 | $alternate = true; |
| 265 | foreach ( $already_optimized as $optimized_image ) { |
| 266 | $optimized_image['pending'] = $pending; |
| 267 | $output['table'] .= ewww_image_optimizer_get_image_table_row( $optimized_image, $alternate ); |
| 268 | $alternate = ! $alternate; |
| 269 | } // End foreach(). |
| 270 | } |
| 271 | |
| 272 | $output['table'] .= '</tbody></table>'; |
| 273 | die( wp_json_encode( $output ) ); |
| 274 | } |
| 275 | |
| 276 | /** |
| 277 | * Render (and return) the output for a row in the image results table. |
| 278 | * |
| 279 | * @param array $optimized_image An image record from the database. |
| 280 | * @param bool $alternate Whether this is an alternate row, used to add the 'alternate' class for styling. |
| 281 | * @param bool $show_links Whether to include remove/restore links in the output. Optional, defaults to true. |
| 282 | * @return string The HTML for the image table row. |
| 283 | */ |
| 284 | function ewww_image_optimizer_get_image_table_row( $optimized_image, $alternate, $show_links = true ) { |
| 285 | ob_start(); |
| 286 | global $eio_backup; |
| 287 | $file = ewww_image_optimizer_absolutize_path( $optimized_image['path'] ); |
| 288 | $image_name = str_replace( ABSPATH, '', $file ); |
| 289 | $thumb_url = ''; |
| 290 | $image_url = ''; |
| 291 | ewwwio_debug_message( "name is $image_name after replacing ABSPATH" ); |
| 292 | if ( 'media' === $optimized_image['gallery'] && ! empty( $optimized_image['attachment_id'] ) ) { |
| 293 | $thumb_url = wp_get_attachment_image_url( $optimized_image['attachment_id'] ); |
| 294 | } |
| 295 | if ( $file !== $image_name ) { |
| 296 | $image_url = site_url( $image_name ); |
| 297 | } else { |
| 298 | $image_name = str_replace( WP_CONTENT_DIR, '', $file ); |
| 299 | if ( $file !== $image_name ) { |
| 300 | $image_url = content_url( $image_name ); |
| 301 | } |
| 302 | } |
| 303 | if ( empty( $thumb_url ) && ! empty( $image_url ) ) { |
| 304 | $thumb_url = $image_url; |
| 305 | } elseif ( empty( $thumb_url ) ) { |
| 306 | $thumb_url = site_url( 'wp-includes/images/media/default.png' ); |
| 307 | } |
| 308 | // Retrieve the mimetype of the attachment. |
| 309 | $type = ewww_image_optimizer_quick_mimetype( $file, 'i' ); |
| 310 | |
| 311 | $savings = ''; |
| 312 | if ( $optimized_image['image_size'] ) { |
| 313 | $savings = esc_html( ewww_image_optimizer_image_results( $optimized_image['orig_size'], $optimized_image['image_size'] ) ); |
| 314 | } |
| 315 | if ( 946684800 > $optimized_image['updated'] ) { |
| 316 | $last_updated = ''; |
| 317 | } elseif ( $optimized_image['pending'] && empty( $optimized_image['image_size'] ) ) { |
| 318 | $last_updated = ''; |
| 319 | } elseif ( ! $show_links ) { |
| 320 | $last_updated = gmdate( 'M j, H:i:s', $optimized_image['updated'] ); |
| 321 | } else { |
| 322 | $last_updated = human_time_diff( $optimized_image['updated'] ); |
| 323 | } |
| 324 | |
| 325 | // Get a human readable filesize. |
| 326 | $file_size = ewww_image_optimizer_size_format( $optimized_image['image_size'] ); |
| 327 | if ( empty( $optimized_image['image_size'] ) ) { |
| 328 | if ( ! empty( $optimized_image['orig_size'] ) ) { |
| 329 | $file_size = ewww_image_optimizer_size_format( $optimized_image['orig_size'] ); |
| 330 | } elseif ( ewwwio_is_file( $file ) ) { |
| 331 | $file_size = ewww_image_optimizer_size_format( ewww_image_optimizer_filesize( $file ) ); |
| 332 | } else { |
| 333 | $file_size = __( 'unknown', 'ewww-image-optimizer' ); |
| 334 | } |
| 335 | } |
| 336 | /* translators: %s: human-readable filesize */ |
| 337 | $size_string = sprintf( __( 'Image Size: %s', 'ewww-image-optimizer' ), $file_size ); |
| 338 | |
| 339 | $remove_from_text = __( 'Remove from history', 'ewww-image-optimizer' ); |
| 340 | if ( $optimized_image['pending'] ) { |
| 341 | $remove_from_text = __( 'Remove from queue', 'ewww-image-optimizer' ); |
| 342 | } |
| 343 | ?> |
| 344 | <tr class="ewww-image-<?php echo (int) $optimized_image['id'] . ( $alternate ? ' alternate' : '' ); ?>"> |
| 345 | <td style="width:50px;" class="column-icon"><img style="width:50px;height:50px;object-fit:contain;" loading="lazy" src="<?php echo esc_url( $thumb_url ); ?>" /></td> |
| 346 | <td class="title"> |
| 347 | <?php echo esc_html( $image_name ); ?> |
| 348 | <?php if ( $show_links ) : ?> |
| 349 | <br><a class="ewww-remove-image" data-id="<?php echo (int) $optimized_image['id']; ?>"><?php echo esc_html( $remove_from_text ); ?></a> |
| 350 | <?php if ( $optimized_image['pending'] ) : ?> |
| 351 | | <a class="ewww-exclude-image" data-id="<?php echo (int) $optimized_image['id']; ?>"><?php esc_html_e( 'Add exclusion', 'ewww-image-optimizer' ); ?></a> |
| 352 | <?php endif; ?> |
| 353 | <?php if ( ! $optimized_image['pending'] && $eio_backup->is_backup_available( $optimized_image['path'], $optimized_image ) ) : ?> |
| 354 | | <a class="ewww-restore-image" data-id="<?php echo (int) $optimized_image['id']; ?>"><?php esc_html_e( 'Restore original', 'ewww-image-optimizer' ); ?></a> |
| 355 | <?php endif; ?> |
| 356 | <?php endif; ?> |
| 357 | <?php if ( ! empty( $optimized_image['debug'] ) ) : ?> |
| 358 | <?php $debug_id = uniqid(); ?> |
| 359 | <br><a class="ewww-show-debug-meta" href="#" data-id="<?php echo esc_attr( $debug_id ); ?>"><?php esc_html_e( 'Show Debug Output', 'ewww-image-optimizer' ); ?></a> |
| 360 | <div class="ewww-bulk-single-debug <?php echo esc_attr( "ewww-debug-meta-$debug_id" ); ?>" style="background-color:#f1f1f1;display:none;"><?php echo wp_kses_post( $optimized_image['debug'] ); ?></div> |
| 361 | <?php endif; ?> |
| 362 | </td> |
| 363 | <td><?php echo esc_html( $type ); ?></td> |
| 364 | <td><?php echo esc_html( $last_updated ); ?></td> |
| 365 | <td> |
| 366 | <?php if ( $optimized_image['pending'] ) : ?> |
| 367 | <?php echo esc_html( $file_size ); ?> |
| 368 | <?php else : ?> |
| 369 | <?php echo esc_html( $savings ); ?> |
| 370 | <br> |
| 371 | <?php echo esc_html( $size_string ); ?> |
| 372 | <?php |
| 373 | // Check for WebP results. |
| 374 | $webp_error = ''; |
| 375 | $webpurl = ''; |
| 376 | list( $webpfile, $oldwebpfile ) = ewww_image_optimizer_get_all_webp_paths( $file ); |
| 377 | $webp_size = ewww_image_optimizer_filesize( $webpfile ); |
| 378 | $resize_status = ewww_image_optimizer_resize_results_message( $optimized_image['path'], $optimized_image['resize_error'] ); |
| 379 | ?> |
| 380 | <?php if ( $show_links && ! str_ends_with( $file, '.webp' ) && ! ewww_image_optimizer_easy_active() && ewwwio_is_file( $oldwebpfile ) && current_user_can( apply_filters( 'ewww_image_optimizer_admin_permissions', '' ) ) ) : ?> |
| 381 | <br><a href="<?php echo esc_url( admin_url( 'options.php?page=ewww-image-optimizer-webp-migrate' ) ); ?>"><?php esc_html_e( 'Run WebP renaming', 'ewww-image-optimizer' ); ?></a> |
| 382 | <?php endif; ?> |
| 383 | <?php |
| 384 | if ( ! $webp_size ) { |
| 385 | if ( ! empty( $optimized_image['webp_size'] ) ) { |
| 386 | $webp_size = $optimized_image['webp_size']; |
| 387 | } elseif ( ! empty( $optimized_image['webp_error'] ) && 2 !== (int) $optimized_image['webp_error'] ) { |
| 388 | $webp_error = ewww_image_optimizer_webp_error_message( $optimized_image['webp_error'] ); |
| 389 | } |
| 390 | } |
| 391 | if ( $webp_size ) { |
| 392 | // Get a human readable filesize. |
| 393 | $webp_size = ewww_image_optimizer_size_format( $webp_size ); |
| 394 | if ( $image_url ) { |
| 395 | $webpurl = ewww_image_optimizer_get_webp_url( $file, $image_url ); |
| 396 | } |
| 397 | } |
| 398 | ?> |
| 399 | <?php if ( $webp_size ) : ?> |
| 400 | <?php if ( $webpurl ) : ?> |
| 401 | <br>WebP: <a href="<?php echo esc_url( $webpurl ); ?>" target="_blank"><?php echo esc_html( $webp_size ); ?></a> |
| 402 | <?php else : ?> |
| 403 | <br>WebP: <?php echo esc_html( $webp_size ); ?> |
| 404 | <?php endif; ?> |
| 405 | <?php elseif ( $webp_error ) : ?> |
| 406 | <br><?php echo esc_html( $webp_error ); ?> |
| 407 | <?php endif; ?> |
| 408 | <?php if ( ! empty( $resize_status ) ) : ?> |
| 409 | <br><?php echo esc_html( $resize_status ); ?> |
| 410 | <?php endif; ?> |
| 411 | <?php if ( ! empty( $optimized_image['elapsed'] ) ) : ?> |
| 412 | <?php /* translators: %s: number of seconds */ ?> |
| 413 | <br><?php printf( esc_html( _n( 'Elapsed: %s second', 'Elapsed: %s seconds', $optimized_image['elapsed'], 'ewww-image-optimizer' ) ), esc_html( number_format_i18n( $optimized_image['elapsed'], 1 ) ) ); ?> |
| 414 | <?php endif; ?> |
| 415 | <?php endif; ?> |
| 416 | </td> |
| 417 | </tr> |
| 418 | <?php |
| 419 | return \ob_get_clean(); |
| 420 | } |
| 421 | /** |
| 422 | * Excludes an image from the images table. |
| 423 | * |
| 424 | * Called via AJAX, this function will add an exclusion based on the record provided by the |
| 425 | * POST variable 'ewww_image_id' and return a '1' if successful. It will also toggle the pending |
| 426 | * indicator, and remove an image if it has not been optimized yet. |
| 427 | * |
| 428 | * @global object $wpdb |
| 429 | */ |
| 430 | function ewww_image_optimizer_aux_images_exclude() { |
| 431 | // Verify that an authorized user has called function. |
| 432 | $permissions = apply_filters( 'ewww_image_optimizer_bulk_permissions', '' ); |
| 433 | if ( |
| 434 | empty( $_REQUEST['ewww_wpnonce'] ) || |
| 435 | ( |
| 436 | ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) && |
| 437 | ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-bulk' ) |
| 438 | ) || |
| 439 | ! current_user_can( $permissions ) |
| 440 | ) { |
| 441 | ewwwio_ob_clean(); |
| 442 | die( esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ); |
| 443 | } |
| 444 | ewwwio_ob_clean(); |
| 445 | global $wpdb; |
| 446 | if ( empty( $_POST['ewww_image_id'] ) ) { |
| 447 | die(); |
| 448 | } else { |
| 449 | $id = (int) $_POST['ewww_image_id']; |
| 450 | } |
| 451 | $image = new \EWWW_Image( $id ); |
| 452 | ewww_image_optimizer_add_file_exclusion( $image->file ); |
| 453 | ewwwio_debug_message( "excluding {$image->file}" ); |
| 454 | if ( empty( $image->opt_size ) ) { |
| 455 | ewwwio_debug_message( 'not optimized, removing record' ); |
| 456 | if ( $wpdb->delete( |
| 457 | $wpdb->ewwwio_images, |
| 458 | array( |
| 459 | 'id' => $id, |
| 460 | ) |
| 461 | ) ) { |
| 462 | echo '1'; |
| 463 | } |
| 464 | } else { |
| 465 | ewwwio_debug_message( 'previously optimized, toggle pending record' ); |
| 466 | if ( $wpdb->update( |
| 467 | $wpdb->ewwwio_images, |
| 468 | array( |
| 469 | 'pending' => 0, |
| 470 | ), |
| 471 | array( |
| 472 | 'id' => $id, |
| 473 | ) |
| 474 | ) ) { |
| 475 | echo '1'; |
| 476 | } |
| 477 | } |
| 478 | die(); |
| 479 | } |
| 480 | |
| 481 | /** |
| 482 | * Removes an image from the auxiliary images table. |
| 483 | * |
| 484 | * Called via AJAX, this function will remove the record provided by the |
| 485 | * POST variable 'ewww_image_id' and return a '1' if successful. |
| 486 | * |
| 487 | * @global object $wpdb |
| 488 | */ |
| 489 | function ewww_image_optimizer_aux_images_remove() { |
| 490 | // Verify that an authorized user has called function. |
| 491 | $permissions = apply_filters( 'ewww_image_optimizer_bulk_permissions', '' ); |
| 492 | if ( |
| 493 | empty( $_REQUEST['ewww_wpnonce'] ) || |
| 494 | ( |
| 495 | ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) && |
| 496 | ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-bulk' ) |
| 497 | ) || |
| 498 | ! current_user_can( $permissions ) |
| 499 | ) { |
| 500 | ewwwio_ob_clean(); |
| 501 | die( esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ); |
| 502 | } |
| 503 | ewwwio_ob_clean(); |
| 504 | global $wpdb; |
| 505 | if ( empty( $_POST['ewww_image_id'] ) ) { |
| 506 | die(); |
| 507 | } else { |
| 508 | $id = (int) $_POST['ewww_image_id']; |
| 509 | } |
| 510 | if ( empty( $_POST['ewww_pending'] ) ) { |
| 511 | ewwwio_debug_message( "removing record for $id" ); |
| 512 | if ( $wpdb->delete( |
| 513 | $wpdb->ewwwio_images, |
| 514 | array( |
| 515 | 'id' => $id, |
| 516 | ) |
| 517 | ) ) { |
| 518 | echo '1'; |
| 519 | } |
| 520 | } else { |
| 521 | ewwwio_debug_message( "toggle pending for $id" ); |
| 522 | if ( $wpdb->update( |
| 523 | $wpdb->ewwwio_images, |
| 524 | array( |
| 525 | 'pending' => 0, |
| 526 | ), |
| 527 | array( |
| 528 | 'id' => $id, |
| 529 | ) |
| 530 | ) ) { |
| 531 | echo '1'; |
| 532 | } |
| 533 | } |
| 534 | ewwwio_memory( __FUNCTION__ ); |
| 535 | die(); |
| 536 | } |
| 537 | |
| 538 | /** |
| 539 | * Removes all images from the auxiliary images table. |
| 540 | * |
| 541 | * Called via AJAX, this function will return a '1' if successful. |
| 542 | * |
| 543 | * @global object $wpdb |
| 544 | */ |
| 545 | function ewww_image_optimizer_aux_images_clear_all() { |
| 546 | // Verify that an authorized user has called function. |
| 547 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 548 | if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) { |
| 549 | ewwwio_ob_clean(); |
| 550 | die( esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ); |
| 551 | } |
| 552 | ewwwio_ob_clean(); |
| 553 | global $wpdb; |
| 554 | if ( $wpdb->query( "TRUNCATE $wpdb->ewwwio_images" ) ) { |
| 555 | die( esc_html__( 'All records have been removed from the optimization history.', 'ewww-image-optimizer' ) ); |
| 556 | } |
| 557 | ewwwio_memory( __FUNCTION__ ); |
| 558 | die(); |
| 559 | } |
| 560 | |
| 561 | /** |
| 562 | * Reset the progress/position of the WebP cleanup routine. |
| 563 | */ |
| 564 | function ewww_image_optimizer_reset_webp_clean() { |
| 565 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 566 | check_admin_referer( 'ewww-image-optimizer-tools' ); |
| 567 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 568 | if ( ! current_user_can( $permissions ) ) { |
| 569 | wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ); |
| 570 | } |
| 571 | delete_option( 'ewww_image_optimizer_webp_clean_position' ); |
| 572 | wp_safe_redirect( wp_get_referer() ); |
| 573 | exit; |
| 574 | } |
| 575 | |
| 576 | /** |
| 577 | * Reset the progress/position of the bulk restore routine. |
| 578 | */ |
| 579 | function ewww_image_optimizer_reset_bulk_restore() { |
| 580 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 581 | check_admin_referer( 'ewww-image-optimizer-tools' ); |
| 582 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 583 | if ( ! current_user_can( $permissions ) ) { |
| 584 | wp_die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ); |
| 585 | } |
| 586 | delete_option( 'ewww_image_optimizer_bulk_restore_position' ); |
| 587 | wp_safe_redirect( wp_get_referer() ); |
| 588 | exit; |
| 589 | } |
| 590 | |
| 591 | /** |
| 592 | * Restore backups for images using records from the ewwwio_images table. |
| 593 | * |
| 594 | * @global object $wpdb |
| 595 | * @global object $eio_backup |
| 596 | */ |
| 597 | function ewww_image_optimizer_bulk_restore_handler() { |
| 598 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 599 | |
| 600 | session_write_close(); |
| 601 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 602 | if ( ! current_user_can( $permissions ) ) { |
| 603 | ewwwio_ob_clean(); |
| 604 | wp_die( wp_json_encode( array( 'error' => esc_html__( 'You do not have permission to optimize images.', 'ewww-image-optimizer' ) ) ) ); |
| 605 | } |
| 606 | if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) ) { |
| 607 | ewwwio_ob_clean(); |
| 608 | wp_die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); |
| 609 | } |
| 610 | |
| 611 | global $eio_backup; |
| 612 | global $wpdb; |
| 613 | |
| 614 | $completed = 0; |
| 615 | $position = (int) get_option( 'ewww_image_optimizer_bulk_restore_position' ); |
| 616 | $per_page = (int) apply_filters( 'ewww_image_optimizer_bulk_restore_batch_size', 20 ); |
| 617 | $started = time(); |
| 618 | |
| 619 | ewwwio_debug_message( "searching for $per_page records starting at $position" ); |
| 620 | $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 ); |
| 621 | |
| 622 | if ( empty( $optimized_images ) || ! is_countable( $optimized_images ) || 0 === count( $optimized_images ) ) { |
| 623 | ewwwio_debug_message( 'no more images, all done!' ); |
| 624 | delete_option( 'ewww_image_optimizer_bulk_restore_position' ); |
| 625 | ewwwio_ob_clean(); |
| 626 | wp_die( wp_json_encode( array( 'finished' => 1 ) ) ); |
| 627 | } |
| 628 | |
| 629 | // Because some plugins might have loose filters (looking at you WPML). |
| 630 | remove_all_filters( 'wp_delete_file' ); |
| 631 | |
| 632 | $messages = ''; |
| 633 | foreach ( $optimized_images as $optimized_image ) { |
| 634 | ++$completed; |
| 635 | ewwwio_debug_message( "submitting {$optimized_image['id']} to be restored" ); |
| 636 | $eio_backup->restore_file( $optimized_image ); |
| 637 | $error_message = $eio_backup->get_error(); |
| 638 | if ( $error_message ) { |
| 639 | $messages .= esc_html( $error_message ) . '<br>'; |
| 640 | } |
| 641 | update_option( 'ewww_image_optimizer_bulk_restore_position', $optimized_image['id'], false ); |
| 642 | if ( time() > $started + 20 ) { |
| 643 | break; |
| 644 | } |
| 645 | } // End foreach(). |
| 646 | |
| 647 | $new_nonce = ewwwio_maybe_get_new_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ); |
| 648 | |
| 649 | ewwwio_ob_clean(); |
| 650 | wp_die( |
| 651 | wp_json_encode( |
| 652 | array( |
| 653 | 'completed' => $completed, |
| 654 | 'messages' => $messages, |
| 655 | 'new_nonce' => $new_nonce, |
| 656 | ) |
| 657 | ) |
| 658 | ); |
| 659 | } |
| 660 | |
| 661 | /** |
| 662 | * Check a nonce to see if it is on it's last leg/tick. If so, create a new one! |
| 663 | * |
| 664 | * @param string $current_nonce The existing nonce value for AJAX verification. |
| 665 | * @param string $action The handle connected to the nonce that indicates the context of the action performed. |
| 666 | * @return string A new nonce, or an empty value. |
| 667 | */ |
| 668 | function ewwwio_maybe_get_new_nonce( $current_nonce, $action ) { |
| 669 | $tick = wp_verify_nonce( $current_nonce, $action ); |
| 670 | if ( 2 === $tick ) { |
| 671 | return wp_create_nonce( $action ); |
| 672 | } |
| 673 | return ''; |
| 674 | } |
| 675 | |
| 676 | /** |
| 677 | * Find the number of converted images in the ewwwio_images table. |
| 678 | * |
| 679 | * @global object $wpdb |
| 680 | */ |
| 681 | function ewww_image_optimizer_aux_images_count_converted() { |
| 682 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 683 | // Verify that an authorized user has called function. |
| 684 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 685 | if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) { |
| 686 | ewwwio_ob_clean(); |
| 687 | die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); |
| 688 | } |
| 689 | ewwwio_ob_clean(); |
| 690 | global $wpdb; |
| 691 | $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->ewwwio_images WHERE converted != ''" ); |
| 692 | die( wp_json_encode( array( 'total_converted' => $count ) ) ); |
| 693 | } |
| 694 | |
| 695 | /** |
| 696 | * Cleanup originals of converted images using records from the ewwwio_images table. |
| 697 | * |
| 698 | * @global object $wpdb |
| 699 | */ |
| 700 | function ewww_image_optimizer_aux_images_converted_clean() { |
| 701 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 702 | // Verify that an authorized user has called function. |
| 703 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 704 | if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) { |
| 705 | ewwwio_ob_clean(); |
| 706 | die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); |
| 707 | } |
| 708 | global $wpdb; |
| 709 | $completed = 0; |
| 710 | $per_page = 50; |
| 711 | |
| 712 | $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 ); |
| 713 | |
| 714 | if ( empty( $converted_images ) || ! is_countable( $converted_images ) || 0 === count( $converted_images ) ) { |
| 715 | die( wp_json_encode( array( 'finished' => 1 ) ) ); |
| 716 | } |
| 717 | |
| 718 | // Because some plugins might have loose filters (looking at you WPML). |
| 719 | remove_all_filters( 'wp_delete_file' ); |
| 720 | |
| 721 | $messages = ''; |
| 722 | foreach ( $converted_images as $optimized_image ) { |
| 723 | ++$completed; |
| 724 | $file = ewww_image_optimizer_absolutize_path( $optimized_image['converted'] ); |
| 725 | ewwwio_debug_message( "$file was converted, checking if it still exists" ); |
| 726 | if ( ! ewww_image_optimizer_stream_wrapped( $file ) && ewwwio_is_file( $file ) ) { |
| 727 | ewwwio_debug_message( "removing original: $file" ); |
| 728 | if ( ewwwio_delete_file( $file ) ) { |
| 729 | ewwwio_debug_message( "removed $file" ); |
| 730 | /* translators: %s: file name */ |
| 731 | $messages .= sprintf( esc_html__( 'Deleted %s', 'ewww-image-optimizer' ), esc_html( $file ) ) . '<br>'; |
| 732 | } else { |
| 733 | /* translators: %s: file name */ |
| 734 | 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 ) ) ) ) ); |
| 735 | } |
| 736 | } |
| 737 | $wpdb->update( |
| 738 | $wpdb->ewwwio_images, |
| 739 | array( |
| 740 | 'converted' => '', |
| 741 | ), |
| 742 | array( |
| 743 | 'id' => $optimized_image['id'], |
| 744 | ) |
| 745 | ); |
| 746 | } // End foreach(). |
| 747 | |
| 748 | $new_nonce = ewwwio_maybe_get_new_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ); |
| 749 | |
| 750 | die( |
| 751 | wp_json_encode( |
| 752 | array( |
| 753 | 'messages' => $messages, |
| 754 | 'completed' => $completed, |
| 755 | 'new_nonce' => $new_nonce, |
| 756 | ) |
| 757 | ) |
| 758 | ); |
| 759 | } |
| 760 | |
| 761 | /** |
| 762 | * Cleanup WebP images using records from the ewwwio_images table. |
| 763 | * |
| 764 | * @global object $wpdb |
| 765 | */ |
| 766 | function ewww_image_optimizer_aux_images_webp_clean_handler() { |
| 767 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 768 | // Verify that an authorized user has called function. |
| 769 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 770 | if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) { |
| 771 | ewwwio_ob_clean(); |
| 772 | die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); |
| 773 | } |
| 774 | global $wpdb; |
| 775 | $completed = 0; |
| 776 | $per_page = 50; |
| 777 | $resume = get_option( 'ewww_image_optimizer_webp_clean_position' ); |
| 778 | $position = is_array( $resume ) && ! empty( $resume['stage2'] ) ? (int) $resume['stage2'] : 0; |
| 779 | if ( ! is_array( $resume ) ) { |
| 780 | $resume = array(); |
| 781 | } |
| 782 | |
| 783 | ewwwio_debug_message( "searching for $per_page records starting at $position" ); |
| 784 | $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 ); |
| 785 | |
| 786 | if ( empty( $optimized_images ) || ! is_countable( $optimized_images ) || 0 === count( $optimized_images ) ) { |
| 787 | delete_option( 'ewww_image_optimizer_webp_clean_position' ); |
| 788 | die( wp_json_encode( array( 'finished' => 1 ) ) ); |
| 789 | } |
| 790 | |
| 791 | // Because some plugins might have loose filters (looking at you WPML). |
| 792 | remove_all_filters( 'wp_delete_file' ); |
| 793 | |
| 794 | $removed = 0; |
| 795 | foreach ( $optimized_images as $optimized_image ) { |
| 796 | ++$completed; |
| 797 | $removed += ewww_image_optimizer_aux_images_webp_clean( $optimized_image ); |
| 798 | } |
| 799 | |
| 800 | $resume['stage2'] = $optimized_image['id']; |
| 801 | update_option( 'ewww_image_optimizer_webp_clean_position', $resume, false ); |
| 802 | |
| 803 | $new_nonce = ewwwio_maybe_get_new_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ); |
| 804 | |
| 805 | die( |
| 806 | wp_json_encode( |
| 807 | array( |
| 808 | 'completed' => $completed, |
| 809 | 'removed' => $removed, |
| 810 | 'new_nonce' => $new_nonce, |
| 811 | ) |
| 812 | ) |
| 813 | ); |
| 814 | } |
| 815 | |
| 816 | /** |
| 817 | * Remove WebP images via db record. |
| 818 | * |
| 819 | * @param array $optimized_image The database record for an image from the optimization history. |
| 820 | * @return int Number of images removed. |
| 821 | */ |
| 822 | function ewww_image_optimizer_aux_images_webp_clean( $optimized_image ) { |
| 823 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 824 | $file = ewww_image_optimizer_absolutize_path( $optimized_image['path'] ); |
| 825 | $removed = 0; |
| 826 | ewwwio_debug_message( "looking for $file.webp" ); |
| 827 | if ( ! ewww_image_optimizer_stream_wrapped( $file ) && ewwwio_is_file( $file ) && ewwwio_is_file( $file . '.webp' ) ) { |
| 828 | ewwwio_debug_message( "removing: $file.webp" ); |
| 829 | if ( ewwwio_delete_file( $file . '.webp' ) ) { |
| 830 | ewwwio_debug_message( "removed $file.webp" ); |
| 831 | ++$removed; |
| 832 | } else { |
| 833 | if ( wp_doing_ajax() ) { |
| 834 | /* translators: %s: file name */ |
| 835 | 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' ) ) ) ) ); |
| 836 | } elseif ( defined( 'WP_CLI' ) && WP_CLI ) { |
| 837 | WP_CLI::error( |
| 838 | sprintf( |
| 839 | /* translators: %s: file name */ |
| 840 | esc_html__( 'Could not delete %s, please remove manually or fix permissions and try again.', 'ewww-image-optimizer' ), |
| 841 | esc_html( $file . '.webp' ) |
| 842 | ) |
| 843 | ); |
| 844 | } |
| 845 | } |
| 846 | } |
| 847 | if ( ! empty( $optimized_image['converted'] ) ) { |
| 848 | $file = ewww_image_optimizer_absolutize_path( $optimized_image['converted'] ); |
| 849 | ewwwio_debug_message( "$file was converted, checking if webp version exists" ); |
| 850 | if ( ! ewww_image_optimizer_stream_wrapped( $file ) && ewwwio_is_file( $file ) && ewwwio_is_file( $file . '.webp' ) ) { |
| 851 | ewwwio_debug_message( "removing: $file.webp" ); |
| 852 | if ( ewwwio_delete_file( $file . '.webp' ) ) { |
| 853 | ewwwio_debug_message( "removed $file.webp" ); |
| 854 | ++$removed; |
| 855 | } else { |
| 856 | if ( wp_doing_ajax() ) { |
| 857 | /* translators: %s: file name */ |
| 858 | 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' ) ) ) ) ); |
| 859 | } elseif ( defined( 'WP_CLI' ) && WP_CLI ) { |
| 860 | WP_CLI::error( |
| 861 | sprintf( |
| 862 | /* translators: %s: file name */ |
| 863 | esc_html__( 'Could not delete %s, please remove manually or fix permissions and try again.', 'ewww-image-optimizer' ), |
| 864 | esc_html( $file . '.webp' ) |
| 865 | ) |
| 866 | ); |
| 867 | } |
| 868 | } |
| 869 | } |
| 870 | } |
| 871 | return $removed; |
| 872 | } |
| 873 | |
| 874 | /** |
| 875 | * Cleanup WebP images via AJAX for a particular attachment. |
| 876 | * |
| 877 | * @global object $wpdb |
| 878 | */ |
| 879 | function ewww_image_optimizer_delete_webp_handler() { |
| 880 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 881 | // Verify that an authorized user has called function. |
| 882 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 883 | if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) { |
| 884 | ewwwio_ob_clean(); |
| 885 | die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); |
| 886 | } |
| 887 | global $wpdb; |
| 888 | $resume = get_option( 'ewww_image_optimizer_webp_clean_position' ); |
| 889 | $position = is_array( $resume ) && ! empty( $resume['stage1'] ) ? (int) $resume['stage1'] : 0; |
| 890 | if ( ! is_array( $resume ) ) { |
| 891 | $resume = array(); |
| 892 | } |
| 893 | |
| 894 | $id = (int) $wpdb->get_var( |
| 895 | $wpdb->prepare( |
| 896 | "SELECT ID FROM $wpdb->posts WHERE ID > %d AND post_type = 'attachment' AND (post_mime_type LIKE %s OR post_mime_type LIKE %s) ORDER BY ID LIMIT 1", |
| 897 | (int) $position, |
| 898 | '%image%', |
| 899 | '%pdf%' |
| 900 | ) |
| 901 | ); |
| 902 | if ( ! $id ) { |
| 903 | die( wp_json_encode( array( 'finished' => 1 ) ) ); |
| 904 | } |
| 905 | |
| 906 | // Because some plugins might have loose filters (looking at you WPML). |
| 907 | remove_all_filters( 'wp_delete_file' ); |
| 908 | |
| 909 | $removed = ewww_image_optimizer_delete_webp( $id ); |
| 910 | $resume['stage1'] = (int) $id; |
| 911 | update_option( 'ewww_image_optimizer_webp_clean_position', $resume, false ); |
| 912 | |
| 913 | $new_nonce = ewwwio_maybe_get_new_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ); |
| 914 | |
| 915 | die( |
| 916 | wp_json_encode( |
| 917 | array( |
| 918 | 'completed' => 1, |
| 919 | 'removed' => $removed, |
| 920 | 'new_nonce' => $new_nonce, |
| 921 | ) |
| 922 | ) |
| 923 | ); |
| 924 | } |
| 925 | |
| 926 | /** |
| 927 | * Cleanup WebP images for a particular attachment. |
| 928 | * |
| 929 | * @global object $wpdb |
| 930 | * |
| 931 | * @param int $id Attachment ID number for an image. |
| 932 | * @return int Number of images removed. |
| 933 | */ |
| 934 | function ewww_image_optimizer_delete_webp( $id ) { |
| 935 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 936 | global $wpdb; |
| 937 | |
| 938 | $removed = 0; |
| 939 | // Finds non-meta images to remove from disk, and from db, as well as converted originals. |
| 940 | $optimized_images = $wpdb->get_results( |
| 941 | $wpdb->prepare( |
| 942 | "SELECT path,converted FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = 'media'", |
| 943 | $id |
| 944 | ), |
| 945 | ARRAY_A |
| 946 | ); |
| 947 | if ( $optimized_images ) { |
| 948 | if ( ewww_image_optimizer_iterable( $optimized_images ) ) { |
| 949 | foreach ( $optimized_images as $image ) { |
| 950 | if ( ! empty( $image['path'] ) ) { |
| 951 | $image['path'] = ewww_image_optimizer_absolutize_path( $image['path'] ); |
| 952 | } |
| 953 | if ( ! empty( $image['path'] ) ) { |
| 954 | ewwwio_debug_message( 'looking for: ' . $image['path'] . '.webp' ); |
| 955 | if ( ewwwio_is_file( $image['path'] ) && ewwwio_is_file( $image['path'] . '.webp' ) ) { |
| 956 | ewwwio_debug_message( 'removing: ' . $image['path'] . '.webp' ); |
| 957 | if ( ewwwio_delete_file( $image['path'] . '.webp' ) ) { |
| 958 | ++$removed; |
| 959 | } |
| 960 | } |
| 961 | $webpfileold = preg_replace( '/\.\w+$/', '.webp', $image['path'] ); |
| 962 | if ( |
| 963 | ! preg_match( '/\.webp$/', $image['path'] ) && |
| 964 | ewwwio_is_file( $image['path'] ) && |
| 965 | ewwwio_is_file( $webpfileold ) |
| 966 | ) { |
| 967 | ewwwio_debug_message( 'removing: ' . $webpfileold ); |
| 968 | if ( ewwwio_delete_file( $webpfileold ) ) { |
| 969 | ++$removed; |
| 970 | } |
| 971 | } |
| 972 | } |
| 973 | if ( ! empty( $image['converted'] ) && ewwwio_is_file( $image['converted'] ) && ewwwio_is_file( $image['converted'] . '.webp' ) ) { |
| 974 | ewwwio_debug_message( 'removing: ' . $image['converted'] . '.webp' ); |
| 975 | if ( ewwwio_delete_file( $image['converted'] . '.webp' ) ) { |
| 976 | ++$removed; |
| 977 | } |
| 978 | } |
| 979 | } |
| 980 | } |
| 981 | } |
| 982 | $s3_path = false; |
| 983 | $s3_dir = false; |
| 984 | if ( ewww_image_optimizer_s3_uploads_enabled() ) { |
| 985 | $s3_path = get_attached_file( $id ); |
| 986 | if ( 0 === strpos( $s3_path, 's3://' ) ) { |
| 987 | $webp_paths = ewww_image_optimizer_get_all_webp_paths( $s3_path ); |
| 988 | foreach ( $webp_paths as $webp_path ) { |
| 989 | if ( ewwwio_is_file( $webp_path ) ) { |
| 990 | ewwwio_debug_message( 'removing: ' . $webp_path ); |
| 991 | unlink( $webp_path ); |
| 992 | } |
| 993 | } |
| 994 | } |
| 995 | $s3_dir = trailingslashit( dirname( $s3_path ) ); |
| 996 | } |
| 997 | // Retrieve the image metadata. |
| 998 | $meta = wp_get_attachment_metadata( $id ); |
| 999 | // If the attachment has an original file set. |
| 1000 | if ( ! empty( $meta['orig_file'] ) ) { |
| 1001 | // Get the filepath from the metadata. |
| 1002 | $file_path = $meta['orig_file']; |
| 1003 | // Get the base filename. |
| 1004 | $filename = wp_basename( $file_path ); |
| 1005 | // Delete any residual webp versions. |
| 1006 | $webpfile = $file_path . '.webp'; |
| 1007 | $webpfileold = preg_replace( '/\.\w+$/', '.webp', $file_path ); |
| 1008 | if ( ewwwio_is_file( $file_path ) && ewwwio_is_file( $webpfile ) ) { |
| 1009 | ewwwio_debug_message( 'removing: ' . $webpfile ); |
| 1010 | if ( ewwwio_delete_file( $webpfile ) ) { |
| 1011 | ++$removed; |
| 1012 | } |
| 1013 | } |
| 1014 | if ( |
| 1015 | ! preg_match( '/\.webp$/', $file_path ) && |
| 1016 | ewwwio_is_file( $file_path ) && |
| 1017 | ewwwio_is_file( $webpfileold ) |
| 1018 | ) { |
| 1019 | ewwwio_debug_message( 'removing: ' . $webpfileold ); |
| 1020 | if ( ewwwio_delete_file( $webpfileold ) ) { |
| 1021 | ++$removed; |
| 1022 | } |
| 1023 | } |
| 1024 | } |
| 1025 | $file_path = get_attached_file( $id ); |
| 1026 | // If the attachment has an original file set. |
| 1027 | if ( ! empty( $meta['original_image'] ) ) { |
| 1028 | // One way or another, $file_path is now set, and we can get the base folder name. |
| 1029 | $base_dir = dirname( $file_path ) . '/'; |
| 1030 | // Get the original filename from the metadata. |
| 1031 | $orig_path = $base_dir . wp_basename( $meta['original_image'] ); |
| 1032 | // Delete any residual webp versions. |
| 1033 | $webpfile = $orig_path . '.webp'; |
| 1034 | if ( ewwwio_is_file( $orig_path ) && ewwwio_is_file( $webpfile ) ) { |
| 1035 | ewwwio_debug_message( 'removing: ' . $webpfile ); |
| 1036 | if ( ewwwio_delete_file( $webpfile ) ) { |
| 1037 | ++$removed; |
| 1038 | } |
| 1039 | } |
| 1040 | if ( $s3_path && $s3_dir && wp_basename( $meta['original_image'] ) ) { |
| 1041 | ewwwio_debug_message( 'removing: ' . $s3_dir . wp_basename( $meta['original_image'] ) . '.webp' ); |
| 1042 | if ( unlink( $s3_dir . wp_basename( $meta['original_image'] ) . '.webp' ) ) { |
| 1043 | ++$removed; |
| 1044 | } |
| 1045 | } |
| 1046 | } |
| 1047 | // Resized versions, so we can continue. |
| 1048 | if ( isset( $meta['sizes'] ) && ewww_image_optimizer_iterable( $meta['sizes'] ) ) { |
| 1049 | // One way or another, $file_path is now set, and we can get the base folder name. |
| 1050 | $base_dir = dirname( $file_path ) . '/'; |
| 1051 | foreach ( $meta['sizes'] as $size => $data ) { |
| 1052 | if ( empty( $data['file'] ) ) { |
| 1053 | continue; |
| 1054 | } |
| 1055 | // Delete any residual webp versions. |
| 1056 | $webpfile = $base_dir . wp_basename( $data['file'] ) . '.webp'; |
| 1057 | $webpfileold = preg_replace( '/\.\w+$/', '.webp', $base_dir . wp_basename( $data['file'] ) ); |
| 1058 | if ( ewwwio_is_file( $base_dir . wp_basename( $data['file'] ) ) && ewwwio_is_file( $webpfile ) ) { |
| 1059 | ewwwio_debug_message( 'removing: ' . $webpfile ); |
| 1060 | if ( ewwwio_delete_file( $webpfile ) ) { |
| 1061 | ++$removed; |
| 1062 | } |
| 1063 | } |
| 1064 | if ( |
| 1065 | ! preg_match( '/\.webp$/', $base_dir . wp_basename( $data['file'] ) ) && |
| 1066 | ewwwio_is_file( $base_dir . wp_basename( $data['file'] ) ) && |
| 1067 | ewwwio_is_file( $webpfileold ) |
| 1068 | ) { |
| 1069 | ewwwio_debug_message( 'removing: ' . $webpfileold ); |
| 1070 | if ( ewwwio_delete_file( $webpfileold ) ) { |
| 1071 | ++$removed; |
| 1072 | } |
| 1073 | } |
| 1074 | if ( $s3_path && $s3_dir && wp_basename( $data['file'] ) ) { |
| 1075 | ewwwio_debug_message( 'removing: ' . $s3_dir . wp_basename( $data['file'] ) . '.webp' ); |
| 1076 | if ( unlink( $s3_dir . wp_basename( $data['file'] ) . '.webp' ) ) { |
| 1077 | ++$removed; |
| 1078 | } |
| 1079 | } |
| 1080 | // If the original resize is set, and still exists. |
| 1081 | if ( |
| 1082 | ! empty( $data['orig_file'] ) && |
| 1083 | ewwwio_is_file( $base_dir . $data['orig_file'] ) && |
| 1084 | ewwwio_is_file( $base_dir . $data['orig_file'] . '.webp' ) |
| 1085 | ) { |
| 1086 | ewwwio_debug_message( 'removing: ' . $base_dir . $data['orig_file'] . '.webp' ); |
| 1087 | if ( ewwwio_delete_file( $base_dir . $data['orig_file'] . '.webp' ) ) { |
| 1088 | ++$removed; |
| 1089 | } |
| 1090 | } |
| 1091 | } |
| 1092 | } |
| 1093 | ewwwio_debug_message( "looking for: $file_path.webp" ); |
| 1094 | if ( ewwwio_is_file( $file_path ) && ewwwio_is_file( $file_path . '.webp' ) ) { |
| 1095 | ewwwio_debug_message( 'removing: ' . $file_path . '.webp' ); |
| 1096 | if ( ewwwio_delete_file( $file_path . '.webp' ) ) { |
| 1097 | ++$removed; |
| 1098 | } |
| 1099 | } |
| 1100 | $webpfileold = preg_replace( '/\.\w+$/', '.webp', $file_path ); |
| 1101 | if ( |
| 1102 | ! preg_match( '/\.webp$/', $file_path ) && |
| 1103 | ewwwio_is_file( $file_path ) && |
| 1104 | ewwwio_is_file( $webpfileold ) |
| 1105 | ) { |
| 1106 | ewwwio_debug_message( 'removing: ' . $webpfileold ); |
| 1107 | if ( ewwwio_delete_file( $webpfileold ) ) { |
| 1108 | ++$removed; |
| 1109 | } |
| 1110 | } |
| 1111 | |
| 1112 | // Remove WebP notification from displaying in media library. |
| 1113 | $wpdb->update( |
| 1114 | $wpdb->ewwwio_images, |
| 1115 | array( |
| 1116 | 'webp_size' => 0, |
| 1117 | 'webp_error' => 0, |
| 1118 | ), |
| 1119 | array( |
| 1120 | 'attachment_id' => $id, |
| 1121 | ) |
| 1122 | ); |
| 1123 | return $removed; |
| 1124 | } |
| 1125 | |
| 1126 | /** |
| 1127 | * Cleans up original_image via AJAX for a particular attachment. |
| 1128 | */ |
| 1129 | function ewww_image_optimizer_ajax_delete_original() { |
| 1130 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1131 | // Verify that an authorized user has called function. |
| 1132 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 1133 | if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) { |
| 1134 | ewwwio_ob_clean(); |
| 1135 | die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); |
| 1136 | } |
| 1137 | if ( ! empty( $_POST['delete_originals_done'] ) ) { |
| 1138 | delete_option( 'ewww_image_optimizer_delete_originals_resume' ); |
| 1139 | die( wp_json_encode( array( 'done' => 1 ) ) ); |
| 1140 | } |
| 1141 | if ( empty( $_POST['attachment_id'] ) ) { |
| 1142 | die( wp_json_encode( array( 'error' => esc_html__( 'Missing attachment ID number.', 'ewww-image-optimizer' ) ) ) ); |
| 1143 | } |
| 1144 | |
| 1145 | // Because some plugins might have loose filters (looking at you WPML). |
| 1146 | remove_all_filters( 'wp_delete_file' ); |
| 1147 | |
| 1148 | $count = 0; |
| 1149 | if ( ! empty( $_POST['completed'] ) ) { |
| 1150 | $count = (int) $_POST['completed'] + 1; |
| 1151 | } |
| 1152 | |
| 1153 | $total = 0; |
| 1154 | if ( ! empty( $_POST['total'] ) ) { |
| 1155 | $total = (int) $_POST['total']; |
| 1156 | } |
| 1157 | |
| 1158 | $deleted = false; |
| 1159 | $id = (int) $_POST['attachment_id']; |
| 1160 | $old_meta = wp_get_attachment_metadata( $id ); |
| 1161 | $new_meta = ewwwio_remove_original_image( $id, $old_meta ); |
| 1162 | if ( ewww_image_optimizer_iterable( $new_meta ) ) { |
| 1163 | $deleted_image = ewwwio_get_original_image_path( $id, '', $old_meta ); |
| 1164 | wp_update_attachment_metadata( $id, $new_meta ); |
| 1165 | /* translators: %s: filename of deleted image */ |
| 1166 | $deleted = sprintf( esc_html__( 'Deleted %s', 'ewww-image-optimizer' ), esc_html( $deleted_image ) ); |
| 1167 | } |
| 1168 | |
| 1169 | update_option( 'ewww_image_optimizer_delete_originals_resume', $id, false ); |
| 1170 | |
| 1171 | /* translators: 1: number of images scanned so far, 2: total number of images to scan */ |
| 1172 | $progress = sprintf( esc_html__( '%1$s / %2$s images checked', 'ewww-image-optimizer' ), number_format_i18n( $count ), number_format_i18n( $total ) ); |
| 1173 | $new_nonce = ewwwio_maybe_get_new_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ); |
| 1174 | |
| 1175 | die( |
| 1176 | wp_json_encode( |
| 1177 | array( |
| 1178 | 'progress' => $progress, |
| 1179 | 'deleted' => $deleted, |
| 1180 | 'new_nonce' => $new_nonce, |
| 1181 | ) |
| 1182 | ) |
| 1183 | ); |
| 1184 | } |
| 1185 | |
| 1186 | /** |
| 1187 | * Cleanup duplicate and unreferenced records from the images table. |
| 1188 | * |
| 1189 | * Called via AJAX to find records from the images table and checks them for duplicates and |
| 1190 | * references to non-existent files. |
| 1191 | * |
| 1192 | * @global object $wpdb |
| 1193 | */ |
| 1194 | function ewww_image_optimizer_aux_images_clean() { |
| 1195 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1196 | // Verify that an authorized user has called function. |
| 1197 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 1198 | if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) { |
| 1199 | ewwwio_ob_clean(); |
| 1200 | die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); |
| 1201 | } |
| 1202 | global $wpdb; |
| 1203 | $per_page = 500; |
| 1204 | $offset = empty( $_POST['ewww_offset'] ) ? 0 : $per_page * (int) $_POST['ewww_offset']; |
| 1205 | |
| 1206 | $already_optimized = $wpdb->get_results( $wpdb->prepare( "SELECT path,orig_size,image_size,id,backup,updated FROM $wpdb->ewwwio_images WHERE pending=0 AND image_size > 0 ORDER BY id DESC LIMIT %d,%d", $offset, $per_page ), ARRAY_A ); |
| 1207 | |
| 1208 | foreach ( $already_optimized as $optimized_image ) { |
| 1209 | $file = ewww_image_optimizer_absolutize_path( $optimized_image['path'] ); |
| 1210 | ewwwio_debug_message( "checking $file for duplicates and dereferences" ); |
| 1211 | // Will remove duplicates. |
| 1212 | ewww_image_optimizer_find_already_optimized( $file ); |
| 1213 | if ( ! ewww_image_optimizer_stream_wrapped( $file ) && ! ewwwio_is_file( $file ) ) { |
| 1214 | ewwwio_debug_message( "removing defunct record for $file" ); |
| 1215 | $wpdb->delete( |
| 1216 | $wpdb->ewwwio_images, |
| 1217 | array( |
| 1218 | 'id' => $optimized_image['id'], |
| 1219 | ), |
| 1220 | array( '%d' ) |
| 1221 | ); |
| 1222 | } |
| 1223 | } // End foreach(). |
| 1224 | |
| 1225 | $new_nonce = ewwwio_maybe_get_new_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ); |
| 1226 | |
| 1227 | die( |
| 1228 | wp_json_encode( |
| 1229 | array( |
| 1230 | 'success' => 1, |
| 1231 | 'new_nonce' => $new_nonce, |
| 1232 | ) |
| 1233 | ) |
| 1234 | ); |
| 1235 | } |
| 1236 | |
| 1237 | /** |
| 1238 | * Cleanup and migrate optimization data from wp_postmeta to the images table. |
| 1239 | * |
| 1240 | * @global object $wpdb |
| 1241 | */ |
| 1242 | function ewww_image_optimizer_aux_meta_clean() { |
| 1243 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1244 | |
| 1245 | // Verify that an authorized user has called function. |
| 1246 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 1247 | if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) { |
| 1248 | ewwwio_ob_clean(); |
| 1249 | die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); |
| 1250 | } |
| 1251 | |
| 1252 | global $wpdb; |
| 1253 | $per_page = 50; |
| 1254 | $offset = empty( $_POST['ewww_offset'] ) ? 0 : (int) $_POST['ewww_offset']; |
| 1255 | ewwwio_debug_message( "getting $per_page attachments, starting at $offset" ); |
| 1256 | |
| 1257 | $attachments = $wpdb->get_col( |
| 1258 | $wpdb->prepare( |
| 1259 | "SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment' AND (post_mime_type LIKE %s OR post_mime_type LIKE %s) ORDER BY ID ASC LIMIT %d,%d", |
| 1260 | '%image%', |
| 1261 | '%pdf%', |
| 1262 | $offset, |
| 1263 | $per_page |
| 1264 | ) |
| 1265 | ); |
| 1266 | |
| 1267 | if ( empty( $attachments ) ) { |
| 1268 | die( wp_json_encode( array( 'done' => 1 ) ) ); |
| 1269 | } |
| 1270 | |
| 1271 | foreach ( $attachments as $attachment_id ) { |
| 1272 | ewwwio_debug_message( "checking $attachment_id for migration" ); |
| 1273 | $meta = wp_get_attachment_metadata( $attachment_id ); |
| 1274 | if ( is_array( $meta ) ) { |
| 1275 | ewww_image_optimizer_migrate_meta_to_db( $attachment_id, $meta ); |
| 1276 | } |
| 1277 | } |
| 1278 | |
| 1279 | $new_nonce = ewwwio_maybe_get_new_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ); |
| 1280 | |
| 1281 | die( |
| 1282 | wp_json_encode( |
| 1283 | array( |
| 1284 | 'success' => $per_page, |
| 1285 | 'new_nonce' => $new_nonce, |
| 1286 | ) |
| 1287 | ) |
| 1288 | ); |
| 1289 | } |
| 1290 | |
| 1291 | /** |
| 1292 | * Find the number of optimized images in the ewwwio_images table. |
| 1293 | * |
| 1294 | * @param bool $cached Whether to use a cached value. |
| 1295 | * @global object $wpdb |
| 1296 | * @return int The total number of records in the images table that are not pending and have a |
| 1297 | * valid file-size. |
| 1298 | */ |
| 1299 | function ewww_image_optimizer_aux_images_table_count( $cached = false ) { |
| 1300 | if ( $cached ) { |
| 1301 | $count = get_transient( 'ewwwio_images_table_count' ); |
| 1302 | if ( $count ) { |
| 1303 | return (int) $count; |
| 1304 | } |
| 1305 | } |
| 1306 | global $wpdb; |
| 1307 | $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->ewwwio_images WHERE pending=0 AND image_size > 0 AND updates > 0" ); |
| 1308 | // Verify that an authorized user has called function. |
| 1309 | $permissions = apply_filters( 'ewww_image_optimizer_bulk_permissions', '' ); |
| 1310 | if ( ! empty( $_REQUEST['ewww_inline'] ) && |
| 1311 | ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) |
| 1312 | ) { |
| 1313 | die(); |
| 1314 | } elseif ( ! empty( $_REQUEST['ewww_inline'] ) ) { |
| 1315 | ewwwio_ob_clean(); |
| 1316 | echo (int) $count; |
| 1317 | ewwwio_memory( __FUNCTION__ ); |
| 1318 | die(); |
| 1319 | } |
| 1320 | if ( $cached && $count ) { |
| 1321 | set_transient( 'ewwwio_images_table_count', (int) $count, HOUR_IN_SECONDS ); |
| 1322 | } |
| 1323 | ewwwio_memory( __FUNCTION__ ); |
| 1324 | return (int) $count; |
| 1325 | } |
| 1326 | |
| 1327 | /** |
| 1328 | * Find the number of un-optimized images in the ewwwio_images table. |
| 1329 | * |
| 1330 | * @global object $wpdb |
| 1331 | * @return int Number of pending images in queue. |
| 1332 | */ |
| 1333 | function ewww_image_optimizer_aux_images_table_count_pending() { |
| 1334 | global $wpdb; |
| 1335 | $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->ewwwio_images WHERE pending=1" ); |
| 1336 | return $count; |
| 1337 | } |
| 1338 | |
| 1339 | /** |
| 1340 | * Find the number of un-optimized (media) images in the ewwwio_images table. |
| 1341 | * |
| 1342 | * This is useful to know if we need to alert the user when the bulk attachments array is empty. |
| 1343 | * |
| 1344 | * @global object $wpdb |
| 1345 | * @return int Number of pending media images in queue. |
| 1346 | */ |
| 1347 | function ewww_image_optimizer_aux_images_table_count_pending_media() { |
| 1348 | global $wpdb; |
| 1349 | $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->ewwwio_images WHERE pending=1 AND gallery='media'" ); |
| 1350 | return $count; |
| 1351 | } |
| 1352 | |
| 1353 | /** |
| 1354 | * Set a batch of images to pending. |
| 1355 | * |
| 1356 | * @global object $wpdb |
| 1357 | * |
| 1358 | * @param array $reset_images A list of images to reset in the ewwwio_images table. |
| 1359 | */ |
| 1360 | function ewww_image_optimizer_reset_images( $reset_images ) { |
| 1361 | if ( ! ewww_image_optimizer_iterable( $reset_images ) ) { |
| 1362 | return; |
| 1363 | } |
| 1364 | array_walk( $reset_images, 'intval' ); |
| 1365 | global $wpdb; |
| 1366 | /** |
| 1367 | * Set a maximum for a query, 1k less than WPE's 16k limit, just to be safe. |
| 1368 | * |
| 1369 | * @param int 15000 The maximum query length. |
| 1370 | */ |
| 1371 | $max_query_length = apply_filters( 'ewww_image_optimizer_max_query_length', 15000 ); |
| 1372 | $reset_images_sql = ''; |
| 1373 | foreach ( $reset_images as $reset_image ) { |
| 1374 | if ( strlen( $reset_images_sql ) > $max_query_length ) { |
| 1375 | $reset_images_sql = rtrim( $reset_images_sql, ',' ); |
| 1376 | $updated = $wpdb->query( "UPDATE $wpdb->ewwwio_images SET pending = 1, updated = updated WHERE id IN ($reset_images_sql)" ); // phpcs:ignore WordPress.DB.PreparedSQL |
| 1377 | if ( ! $updated ) { |
| 1378 | ewwwio_debug_message( 'db error: ' . $wpdb->last_error ); |
| 1379 | } |
| 1380 | $reset_images_sql = ''; |
| 1381 | } |
| 1382 | $reset_images_sql .= $reset_image . ','; |
| 1383 | } |
| 1384 | $reset_images_sql = rtrim( $reset_images_sql, ',' ); |
| 1385 | $updated = $wpdb->query( "UPDATE $wpdb->ewwwio_images SET pending = 1, updated = updated WHERE id IN ($reset_images_sql)" ); // phpcs:ignore WordPress.DB.PreparedSQL |
| 1386 | if ( ! $updated ) { |
| 1387 | ewwwio_debug_message( 'db error: ' . $wpdb->last_error ); |
| 1388 | } |
| 1389 | } |
| 1390 | |
| 1391 | /** |
| 1392 | * Remove all un-optimized images from the ewwwio_images table. |
| 1393 | * |
| 1394 | * @global object $wpdb |
| 1395 | */ |
| 1396 | function ewww_image_optimizer_delete_pending() { |
| 1397 | global $wpdb; |
| 1398 | $wpdb->query( "DELETE from $wpdb->ewwwio_images WHERE pending=1 AND (image_size IS NULL OR image_size = 0)" ); |
| 1399 | $wpdb->update( |
| 1400 | $wpdb->ewwwio_images, |
| 1401 | array( |
| 1402 | 'pending' => 0, |
| 1403 | ), |
| 1404 | array( |
| 1405 | 'pending' => 1, |
| 1406 | ) |
| 1407 | ); |
| 1408 | } |
| 1409 | |
| 1410 | /** |
| 1411 | * Remove an un-optimized image from the ewwwio_images table. |
| 1412 | * |
| 1413 | * If the image was previously optimized, then simply toggle the pending column. |
| 1414 | * |
| 1415 | * @param int $id The ID of the pending image in the db. |
| 1416 | * @global object $wpdb |
| 1417 | */ |
| 1418 | function ewww_image_optimizer_delete_pending_image( $id ) { |
| 1419 | global $wpdb; |
| 1420 | $deleted = $wpdb->query( $wpdb->prepare( "DELETE from $wpdb->ewwwio_images WHERE id=%d AND pending=1 AND (image_size IS NULL OR image_size = 0)", $id ) ); |
| 1421 | if ( ! $deleted ) { |
| 1422 | ewww_image_optimizer_toggle_pending_image( $id ); |
| 1423 | } |
| 1424 | } |
| 1425 | |
| 1426 | /** |
| 1427 | * Toggle the pending flag for an image in the ewwwio_images table. |
| 1428 | * |
| 1429 | * @param int $id The ID of the pending image in the db. |
| 1430 | * @global object $wpdb |
| 1431 | */ |
| 1432 | function ewww_image_optimizer_toggle_pending_image( $id ) { |
| 1433 | global $wpdb; |
| 1434 | $wpdb->update( |
| 1435 | $wpdb->ewwwio_images, |
| 1436 | array( |
| 1437 | 'pending' => 0, |
| 1438 | 'retrieve' => '', |
| 1439 | ), |
| 1440 | array( |
| 1441 | 'id' => $id, |
| 1442 | ) |
| 1443 | ); |
| 1444 | } |
| 1445 | |
| 1446 | /** |
| 1447 | * Retrieve the number images from the ewwwio_queue table. |
| 1448 | * |
| 1449 | * @since 4.6.0 |
| 1450 | * |
| 1451 | * @global object $wpdb |
| 1452 | */ |
| 1453 | function ewww_image_optimizer_count_attachments() { |
| 1454 | global $wpdb; |
| 1455 | $count = $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" ); |
| 1456 | return $count; |
| 1457 | } |
| 1458 | |
| 1459 | /** |
| 1460 | * Retrieve the total number of images from the ewwwio_queue table. |
| 1461 | * |
| 1462 | * @since 8.5.0 |
| 1463 | * |
| 1464 | * @param string $gallery The type of attachments to count from the queue. |
| 1465 | * @global object $wpdb |
| 1466 | */ |
| 1467 | function ewww_image_optimizer_count_queued_attachments( $gallery = 'media' ) { |
| 1468 | global $wpdb; |
| 1469 | $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->ewwwio_queue WHERE gallery = %s", $gallery ) ); |
| 1470 | return $count; |
| 1471 | } |
| 1472 | |
| 1473 | /** |
| 1474 | * Retrieve the number of scanned images from the ewwwio_queue table. |
| 1475 | * |
| 1476 | * @since 8.5.0 |
| 1477 | * |
| 1478 | * @param string $gallery The type of attachments to count from the queue. |
| 1479 | * @global object $wpdb |
| 1480 | */ |
| 1481 | function ewww_image_optimizer_count_scanned_attachments( $gallery = 'media' ) { |
| 1482 | global $wpdb; |
| 1483 | $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->ewwwio_queue WHERE gallery = %s AND scanned = 1", $gallery ) ); |
| 1484 | return $count; |
| 1485 | } |
| 1486 | |
| 1487 | /** |
| 1488 | * Retrieve the number of un-scanned images from the ewwwio_queue table. |
| 1489 | * |
| 1490 | * @since 4.6.0 |
| 1491 | * |
| 1492 | * @param string $gallery The type of attachments to count from the queue. |
| 1493 | * @global object $wpdb |
| 1494 | */ |
| 1495 | function ewww_image_optimizer_count_unscanned_attachments( $gallery = 'media' ) { |
| 1496 | global $wpdb; |
| 1497 | $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->ewwwio_queue WHERE gallery = %s AND scanned = 0", $gallery ) ); |
| 1498 | return $count; |
| 1499 | } |
| 1500 | |
| 1501 | /** |
| 1502 | * Retrieve unscanned images from the ewwwio_queue table. |
| 1503 | * |
| 1504 | * @since 4.6.0 |
| 1505 | * |
| 1506 | * @param string $gallery The type of attachments for which to search. |
| 1507 | * @param int $limit The maximum number of unscanned attachments to retrieve. |
| 1508 | * @return array A list of unscanned attachments. Will always be an array of integers. |
| 1509 | * @global object $wpdb |
| 1510 | */ |
| 1511 | function ewww_image_optimizer_get_unscanned_attachments( $gallery, $limit = 1000 ) { |
| 1512 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1513 | global $wpdb; |
| 1514 | // Retrieve the attachment IDs that were pre-loaded in the database. |
| 1515 | $selected_ids = $wpdb->get_col( $wpdb->prepare( "SELECT attachment_id FROM $wpdb->ewwwio_queue WHERE gallery = %s AND scanned = 0 LIMIT %d", $gallery, $limit ) ); |
| 1516 | if ( empty( $selected_ids ) ) { |
| 1517 | ewwwio_debug_message( 'no attachments found for scanning' ); |
| 1518 | return array(); |
| 1519 | } |
| 1520 | array_walk( $selected_ids, 'intval' ); |
| 1521 | ewwwio_debug_message( 'selected items: ' . count( $selected_ids ) ); |
| 1522 | return $selected_ids; |
| 1523 | } |
| 1524 | |
| 1525 | /** |
| 1526 | * Check to see if an attachment has any more sizes that are pending. |
| 1527 | * |
| 1528 | * @param int $id The ID of the attachment/image. |
| 1529 | * @param string $gallery The type of image to look for. Optional, default is 'media'. |
| 1530 | * @return int The number of pending sizes in the database. |
| 1531 | * @global object $wpdb |
| 1532 | */ |
| 1533 | function ewww_image_optimizer_attachment_has_pending_sizes( $id, $gallery = 'media' ) { |
| 1534 | global $wpdb; |
| 1535 | $id = (int) $id; |
| 1536 | return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(id) FROM $wpdb->ewwwio_images WHERE attachment_id = %d AND gallery = %s AND pending = 1", $id, $gallery ) ); |
| 1537 | } |
| 1538 | |
| 1539 | /** |
| 1540 | * Check to see if an image is in the queue. |
| 1541 | * |
| 1542 | * @param int $id The ID of the attachment/image. |
| 1543 | * @param string $gallery The type of image to look for. Optional. |
| 1544 | * @return bool True if it's still in the queue. |
| 1545 | * @global object $wpdb |
| 1546 | */ |
| 1547 | function ewww_image_optimizer_image_is_pending( $id, $gallery = 'media' ) { |
| 1548 | global $wpdb; |
| 1549 | $id = (int) $id; |
| 1550 | return $wpdb->get_var( $wpdb->prepare( "SELECT attachment_id FROM $wpdb->ewwwio_queue WHERE attachment_id = %d AND gallery = %s LIMIT 1", $id, $gallery ) ); |
| 1551 | } |
| 1552 | |
| 1553 | /** |
| 1554 | * Count all the images (and PDFs) from the wp_posts table. |
| 1555 | * |
| 1556 | * @global object $wpdb |
| 1557 | * |
| 1558 | * @return int The number of image and PDF attachments in the posts table. |
| 1559 | */ |
| 1560 | function ewww_image_optimizer_count_all_attachments() { |
| 1561 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1562 | global $wpdb; |
| 1563 | return $wpdb->get_var( |
| 1564 | $wpdb->prepare( |
| 1565 | "SELECT count(ID) FROM $wpdb->posts WHERE post_type = 'attachment' AND (post_mime_type LIKE %s OR post_mime_type LIKE %s)", |
| 1566 | '%image%', |
| 1567 | '%pdf%' |
| 1568 | ) |
| 1569 | ); |
| 1570 | } |
| 1571 | |
| 1572 | /** |
| 1573 | * Retrieve all the images (and PDFs) from the wp_posts table. |
| 1574 | * |
| 1575 | * @global object $wpdb |
| 1576 | */ |
| 1577 | function ewww_image_optimizer_get_all_attachments() { |
| 1578 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1579 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 1580 | if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) { |
| 1581 | ewwwio_ob_clean(); |
| 1582 | die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); |
| 1583 | } |
| 1584 | $start_id = get_option( 'ewww_image_optimizer_delete_originals_resume', 0 ); |
| 1585 | global $wpdb; |
| 1586 | $attachments = $wpdb->get_col( |
| 1587 | $wpdb->prepare( |
| 1588 | "SELECT ID FROM $wpdb->posts WHERE ID > %d AND post_type = 'attachment' AND (post_mime_type LIKE %s OR post_mime_type LIKE %s) ORDER BY ID DESC", |
| 1589 | (int) $start_id, |
| 1590 | '%image%', |
| 1591 | '%pdf%' |
| 1592 | ) |
| 1593 | ); |
| 1594 | if ( empty( $attachments ) || ! is_countable( $attachments ) || 0 === count( $attachments ) ) { |
| 1595 | delete_option( 'ewww_image_optimizer_delete_originals_resume' ); |
| 1596 | die( wp_json_encode( array( 'error' => esc_html__( 'No media uploads found.', 'ewww-image-optimizer' ) ) ) ); |
| 1597 | } |
| 1598 | ewwwio_debug_message( gettype( $attachments ) ); |
| 1599 | die( wp_json_encode( $attachments ) ); |
| 1600 | } |
| 1601 | |
| 1602 | /** |
| 1603 | * Count all the image (and PDF) attachments that are remaining for WebP cleanup. |
| 1604 | * |
| 1605 | * @global object $wpdb |
| 1606 | */ |
| 1607 | function ewww_image_optimizer_webp_attachment_count() { |
| 1608 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1609 | $permissions = apply_filters( 'ewww_image_optimizer_admin_permissions', '' ); |
| 1610 | if ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-tools' ) || ! current_user_can( $permissions ) ) { |
| 1611 | ewwwio_ob_clean(); |
| 1612 | die( wp_json_encode( array( 'error' => esc_html__( 'Access token has expired, please reload the page.', 'ewww-image-optimizer' ) ) ) ); |
| 1613 | } |
| 1614 | $resume = get_option( 'ewww_image_optimizer_webp_clean_position' ); |
| 1615 | $start_id = is_array( $resume ) && ! empty( $resume['stage1'] ) ? (int) $resume['stage1'] : 0; |
| 1616 | |
| 1617 | global $wpdb; |
| 1618 | $total_attachments = (int) $wpdb->get_var( |
| 1619 | $wpdb->prepare( |
| 1620 | "SELECT count(ID) FROM $wpdb->posts WHERE ID > %d AND post_type = 'attachment' AND (post_mime_type LIKE %s OR post_mime_type LIKE %s)", |
| 1621 | (int) $start_id, |
| 1622 | '%image%', |
| 1623 | '%pdf%' |
| 1624 | ) |
| 1625 | ); |
| 1626 | die( wp_json_encode( array( 'total' => (int) $total_attachments ) ) ); |
| 1627 | } |
| 1628 | |
| 1629 | /** |
| 1630 | * Retrieve an image ID from the ewwwio_queue table. |
| 1631 | * |
| 1632 | * @since 4.6.0 |
| 1633 | * |
| 1634 | * @param string $gallery The type of attachment to find. |
| 1635 | * @param int $limit The maximum number of unscanned attachments to retrieve. |
| 1636 | * @return array The ID list for queued/scanned attachments. |
| 1637 | * @global object $wpdb |
| 1638 | */ |
| 1639 | function ewww_image_optimizer_get_queued_attachments( $gallery, $limit = 100 ) { |
| 1640 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1641 | global $wpdb; |
| 1642 | // Retrieve the attachment IDs that were pre-loaded in the database. |
| 1643 | $selected_ids = $wpdb->get_col( $wpdb->prepare( "SELECT attachment_id FROM $wpdb->ewwwio_queue WHERE gallery = %s AND scanned = 1 ORDER BY attachment_id DESC LIMIT %d", $gallery, $limit ) ); |
| 1644 | if ( empty( $selected_ids ) ) { |
| 1645 | ewwwio_debug_message( 'no attachments found in queue' ); |
| 1646 | return array( 0 ); |
| 1647 | } |
| 1648 | array_walk( $selected_ids, 'intval' ); |
| 1649 | ewwwio_debug_message( 'selected items: ' . count( $selected_ids ) ); |
| 1650 | return $selected_ids; |
| 1651 | } |
| 1652 | |
| 1653 | /** |
| 1654 | * Insert a batch of attachment IDs into the ewwwio_queue table. |
| 1655 | * |
| 1656 | * @since 4.6.0 |
| 1657 | * |
| 1658 | * @param array $ids The list of attachment IDs to insert. |
| 1659 | * @param string $gallery The type of attachments to insert. Defaults to media library. |
| 1660 | * @global object $wpdb |
| 1661 | */ |
| 1662 | function ewww_image_optimizer_insert_unscanned( $ids, $gallery = 'media' ) { |
| 1663 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1664 | global $wpdb; |
| 1665 | $images = array(); |
| 1666 | $id = array_shift( $ids ); |
| 1667 | while ( ! empty( $id ) ) { |
| 1668 | $images[] = array( |
| 1669 | 'attachment_id' => (int) $id, |
| 1670 | 'gallery' => $gallery, |
| 1671 | 'force_reopt' => (int) ewwwio()->force, |
| 1672 | 'force_smart' => (int) ewwwio()->force_smart, |
| 1673 | 'webp_only' => (int) ewwwio()->webp_only, |
| 1674 | ); |
| 1675 | $id = array_shift( $ids ); |
| 1676 | } |
| 1677 | if ( $images ) { |
| 1678 | $result = ewww_image_optimizer_mass_insert( $wpdb->ewwwio_queue, $images ); |
| 1679 | } |
| 1680 | } |
| 1681 | |
| 1682 | /** |
| 1683 | * Update an image in the queue after it has been scanned. |
| 1684 | * |
| 1685 | * @since 4.6.0 |
| 1686 | * |
| 1687 | * @param int $ids The attachment IDs to update. |
| 1688 | * @param string $gallery The type of attachment to update. Defaults to media library. |
| 1689 | * @global object $wpdb |
| 1690 | */ |
| 1691 | function ewww_image_optimizer_update_scanned_images( $ids, $gallery = 'media' ) { |
| 1692 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1693 | if ( ! ewww_image_optimizer_iterable( $ids ) ) { |
| 1694 | return; |
| 1695 | } |
| 1696 | global $wpdb; |
| 1697 | |
| 1698 | array_walk( $ids, 'intval' ); |
| 1699 | $ids_sql = '(' . implode( ',', $ids ) . ')'; |
| 1700 | |
| 1701 | $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->ewwwio_queue SET scanned = 1 WHERE gallery = %s AND attachment_id IN $ids_sql", $gallery ) ); // phpcs:ignore WordPress.DB.PreparedSQL |
| 1702 | } |
| 1703 | |
| 1704 | /** |
| 1705 | * Remove a batch of images from the ewwwio_queue table (usually when we are done with it). |
| 1706 | * |
| 1707 | * @since 4.6.0 |
| 1708 | * |
| 1709 | * @param int $ids The attachment IDs to remove. |
| 1710 | * @param string $gallery The type of attachment to remove. Defaults to media library. |
| 1711 | * @global object $wpdb |
| 1712 | */ |
| 1713 | function ewww_image_optimizer_delete_queued_images( $ids, $gallery = 'media' ) { |
| 1714 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1715 | if ( ! ewww_image_optimizer_iterable( $ids ) ) { |
| 1716 | return; |
| 1717 | } |
| 1718 | global $wpdb; |
| 1719 | |
| 1720 | array_walk( $ids, 'intval' ); |
| 1721 | $ids_sql = '(' . implode( ',', $ids ) . ')'; |
| 1722 | |
| 1723 | $wpdb->query( $wpdb->prepare( "DELETE from $wpdb->ewwwio_queue WHERE gallery = %s AND attachment_id IN $ids_sql", $gallery ) ); // phpcs:ignore WordPress.DB.PreparedSQL |
| 1724 | } |
| 1725 | |
| 1726 | /** |
| 1727 | * Remove all images from the ewwwio_queue table for the given 'gallery'. |
| 1728 | * |
| 1729 | * @since 4.6.0 |
| 1730 | * |
| 1731 | * @param string $gallery The type of attachments to clear from the queue. Default media library. |
| 1732 | * @global object $wpdb |
| 1733 | */ |
| 1734 | function ewww_image_optimizer_delete_queue_images( $gallery = 'media' ) { |
| 1735 | global $wpdb; |
| 1736 | $wpdb->query( $wpdb->prepare( "DELETE from $wpdb->ewwwio_queue WHERE gallery = %s", $gallery ) ); |
| 1737 | } |
| 1738 | |
| 1739 | /** |
| 1740 | * Searches for images to optimize in a specific folder. |
| 1741 | * |
| 1742 | * Scan a folder for images and mark unoptimized images in the database |
| 1743 | * (inserts new records as necessary). |
| 1744 | * |
| 1745 | * @global object $wpdb |
| 1746 | * @global array|string $optimized_list An associative array containing information from the images |
| 1747 | * table, or 'low_memory', 'large_list', 'small_scan'. |
| 1748 | * |
| 1749 | * @param string $dir The absolute path of the folder to be scanned for unoptimized images. |
| 1750 | * @param int $started Optional. The number of seconds since the overall scanning process started. Default 0. |
| 1751 | */ |
| 1752 | function ewww_image_optimizer_image_scan( $dir, $started = 0 ) { |
| 1753 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 1754 | if ( ! is_dir( $dir ) ) { |
| 1755 | ewwwio_debug_message( "$dir is not a directory, or unreadable" ); |
| 1756 | return; |
| 1757 | } |
| 1758 | $folders_completed = get_option( 'ewww_image_optimizer_aux_folders_completed' ); |
| 1759 | if ( ! is_array( $folders_completed ) ) { |
| 1760 | $folders_completed = array(); |
| 1761 | } |
| 1762 | if ( in_array( $dir, $folders_completed, true ) ) { |
| 1763 | ewwwio_debug_message( "$dir already completed" ); |
| 1764 | return; |
| 1765 | } |
| 1766 | global $wpdb; |
| 1767 | global $optimized_list; |
| 1768 | global $ewww_scan; |
| 1769 | $images = array(); |
| 1770 | $reset_images = array(); |
| 1771 | ewwwio_debug_message( "scanning folder for images: $dir" ); |
| 1772 | $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir ), RecursiveIteratorIterator::CHILD_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD ); |
| 1773 | $start = microtime( true ); |
| 1774 | if ( empty( $optimized_list ) || ! is_array( $optimized_list ) ) { |
| 1775 | ewww_image_optimizer_optimized_list(); |
| 1776 | } |
| 1777 | $file_counter = 0; // Used to track total files overall. |
| 1778 | $image_count = 0; // Used to track number of files since last queue update. |
| 1779 | if ( ewww_image_optimizer_stl_check() ) { |
| 1780 | set_time_limit( 0 ); |
| 1781 | } |
| 1782 | |
| 1783 | $supported_types = ewwwio()->get_supported_types(); |
| 1784 | $webp_types = ewwwio()->get_webp_types(); |
| 1785 | |
| 1786 | foreach ( $iterator as $file ) { |
| 1787 | if ( get_transient( 'ewww_image_optimizer_aux_iterator' ) && get_transient( 'ewww_image_optimizer_aux_iterator' ) > $file_counter ) { |
| 1788 | continue; |
| 1789 | } |
| 1790 | if ( |
| 1791 | $started && |
| 1792 | 'scheduled' !== $ewww_scan && |
| 1793 | 0 === $file_counter % 100 && |
| 1794 | microtime( true ) - $started > apply_filters( 'ewww_image_optimizer_timeout', 15 ) |
| 1795 | ) { |
| 1796 | ewww_image_optimizer_reset_images( $reset_images ); |
| 1797 | if ( ! empty( $images ) ) { |
| 1798 | ewww_image_optimizer_mass_insert( $wpdb->ewwwio_images, $images ); |
| 1799 | } |
| 1800 | set_transient( 'ewww_image_optimizer_aux_iterator', $file_counter - 20, 300 ); // Keep track of where we left off, minus 20 to be safe. |
| 1801 | $loading_image = plugins_url( '/images/wpspin.gif', __FILE__ ); |
| 1802 | ewwwio_ob_clean(); |
| 1803 | die( |
| 1804 | wp_json_encode( |
| 1805 | array( |
| 1806 | 'remaining' => esc_html__( 'Searching additional folders for images to optimize...', 'ewww-image-optimizer' ), |
| 1807 | 'notice' => '', |
| 1808 | ) |
| 1809 | ) |
| 1810 | ); |
| 1811 | } elseif ( |
| 1812 | $started && |
| 1813 | 'scheduled' === $ewww_scan && |
| 1814 | 0 === $file_counter % 100 && |
| 1815 | microtime( true ) - $started > apply_filters( 'ewww_image_optimizer_timeout', 15 ) |
| 1816 | ) { |
| 1817 | ewwwio_debug_message( 'ending current scan iteration, will fire off a new one shortly' ); |
| 1818 | ewww_image_optimizer_reset_images( $reset_images ); |
| 1819 | if ( ! empty( $images ) ) { |
| 1820 | ewww_image_optimizer_mass_insert( $wpdb->ewwwio_images, $images ); |
| 1821 | } |
| 1822 | set_transient( 'ewww_image_optimizer_aux_iterator', $file_counter - 20, 300 ); // Keep track of where we left off, minus 20 to be safe. |
| 1823 | ewwwio()->async_scan->data( |
| 1824 | array( |
| 1825 | 'ewww_scan' => 'scheduled', |
| 1826 | ) |
| 1827 | )->dispatch(); |
| 1828 | die(); |
| 1829 | } elseif ( 'scheduled' === $ewww_scan && get_option( 'ewwwio_stop_scheduled_scan' ) ) { |
| 1830 | ewwwio_debug_message( 'ending current scan iteration because of stop_scan' ); |
| 1831 | delete_option( 'ewwwio_stop_scheduled_scan' ); |
| 1832 | die(); |
| 1833 | } |
| 1834 | if ( $ewww_scan && 0 === $file_counter % 100 && ! ewwwio_check_memory_available( 2097000 ) ) { |
| 1835 | ewwwio_debug_message( 'ending current scan iteration because of memory constraints' ); |
| 1836 | if ( $file_counter < 100 ) { |
| 1837 | ewwwio_ob_clean(); |
| 1838 | die( |
| 1839 | wp_json_encode( |
| 1840 | array( |
| 1841 | 'error' => esc_html__( 'Image search unable to complete due to memory restrictions. Please increase the memory_limit setting for PHP and try again.', 'ewww-image-optimizer' ), |
| 1842 | ) |
| 1843 | ) |
| 1844 | ); |
| 1845 | } |
| 1846 | ewww_image_optimizer_reset_images( $reset_images ); |
| 1847 | if ( ! empty( $images ) ) { |
| 1848 | ewww_image_optimizer_mass_insert( $wpdb->ewwwio_images, $images ); |
| 1849 | } |
| 1850 | set_transient( 'ewww_image_optimizer_aux_iterator', $file_counter - 20, 300 ); // Keep track of where we left off, minus 20 to be safe. |
| 1851 | $loading_image = plugins_url( '/images/wpspin.gif', __FILE__ ); |
| 1852 | ewwwio_ob_clean(); |
| 1853 | die( |
| 1854 | wp_json_encode( |
| 1855 | array( |
| 1856 | 'remaining' => esc_html__( 'Searching additional folders for images to optimize...', 'ewww-image-optimizer' ), |
| 1857 | 'notice' => '', |
| 1858 | ) |
| 1859 | ) |
| 1860 | ); |
| 1861 | } |
| 1862 | ++$file_counter; |
| 1863 | if ( $file->isFile() ) { |
| 1864 | $path = $file->getPathname(); |
| 1865 | if ( preg_match( '/(\/|\\\\)\./', $path ) && apply_filters( 'ewww_image_optimizer_ignore_hidden_files', true ) ) { |
| 1866 | continue; |
| 1867 | } |
| 1868 | if ( defined( 'EWWW_IMAGE_OPTIMIZER_REAL_MIME' ) && EWWW_IMAGE_OPTIMIZER_REAL_MIME ) { |
| 1869 | $mime = ewww_image_optimizer_mimetype( $path, 'i' ); |
| 1870 | } else { |
| 1871 | $mime = ewww_image_optimizer_quick_mimetype( $path ); |
| 1872 | } |
| 1873 | if ( ! in_array( $mime, $supported_types, true ) ) { |
| 1874 | continue; |
| 1875 | } |
| 1876 | if ( ewwwio()->webp_only && ! in_array( $mime, $webp_types, true ) ) { |
| 1877 | continue; |
| 1878 | } |
| 1879 | if ( apply_filters( 'ewww_image_optimizer_bypass', false, $path ) === true ) { |
| 1880 | ewwwio_debug_message( "skipping $path as instructed" ); |
| 1881 | continue; |
| 1882 | } |
| 1883 | |
| 1884 | $already_optimized = false; |
| 1885 | if ( ! is_array( $optimized_list ) && is_string( $optimized_list ) ) { |
| 1886 | $already_optimized = ewww_image_optimizer_find_already_optimized( $path ); |
| 1887 | } elseif ( is_array( $optimized_list ) && isset( $optimized_list[ $path ] ) && ! empty( $optimized_list[ $path ] ) ) { |
| 1888 | $already_optimized = $optimized_list[ $path ]; |
| 1889 | } |
| 1890 | |
| 1891 | $should_resize = ewww_image_optimizer_should_resize( $path ); |
| 1892 | if ( is_array( $already_optimized ) && ! empty( $already_optimized ) ) { |
| 1893 | if ( ! empty( $already_optimized['pending'] ) ) { |
| 1894 | ewwwio_debug_message( "pending record for $path" ); |
| 1895 | continue; |
| 1896 | } |
| 1897 | $image_size = $file->getSize(); |
| 1898 | if ( $image_size < ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_size' ) ) { |
| 1899 | ewwwio_debug_message( "file skipped due to filesize: $path" ); |
| 1900 | continue; |
| 1901 | } |
| 1902 | if ( 'image/png' === $mime && ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_png_size' ) && $image_size > ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_png_size' ) ) { |
| 1903 | ewwwio_debug_message( "file skipped due to PNG filesize: $path" ); |
| 1904 | continue; |
| 1905 | } |
| 1906 | $compression_level = ewww_image_optimizer_get_level( $mime ); |
| 1907 | if ( ! empty( ewwwio()->force_smart ) && ewww_image_optimizer_level_mismatch( $already_optimized['level'], $compression_level ) ) { |
| 1908 | $reset_images[] = (int) $already_optimized['id']; |
| 1909 | ewwwio_debug_message( "smart re-opt found level mismatch for $path, db says " . $already_optimized['level'] . " vs. current $compression_level" ); |
| 1910 | } elseif ( $should_resize ) { |
| 1911 | $reset_images[] = (int) $already_optimized['id']; |
| 1912 | ewwwio_debug_message( "resize other existing found candidate for scaling: $path" ); |
| 1913 | } elseif ( (int) $already_optimized['image_size'] === $image_size && empty( ewwwio()->force ) ) { |
| 1914 | ewwwio_debug_message( "match found for $path" ); |
| 1915 | continue; |
| 1916 | } else { |
| 1917 | $reset_images[] = (int) $already_optimized['id']; |
| 1918 | ewwwio_debug_message( "mismatch found for $path, db says " . $already_optimized['image_size'] . " vs. current $image_size" ); |
| 1919 | } |
| 1920 | } else { |
| 1921 | $image_size = $file->getSize(); |
| 1922 | if ( $image_size < ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_size' ) ) { |
| 1923 | ewwwio_debug_message( "file skipped due to filesize: $path" ); |
| 1924 | continue; |
| 1925 | } |
| 1926 | if ( 'image/png' === $mime && ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_png_size' ) && $image_size > ewww_image_optimizer_get_option( 'ewww_image_optimizer_skip_png_size' ) ) { |
| 1927 | ewwwio_debug_message( "file skipped due to PNG filesize: $path" ); |
| 1928 | continue; |
| 1929 | } |
| 1930 | ewwwio_debug_message( "queuing $path" ); |
| 1931 | $path = ewww_image_optimizer_relativize_path( $path ); |
| 1932 | $utf8_file_path = ewwwio()->ensure_utf8_path( $path ); |
| 1933 | $images[] = array( |
| 1934 | 'path' => $utf8_file_path, |
| 1935 | 'orig_size' => $image_size, |
| 1936 | 'pending' => 1, |
| 1937 | ); |
| 1938 | ++$image_count; |
| 1939 | } // End if(). |
| 1940 | if ( false && $image_count > 1000 ) { // Disabled, should no longer be needed, as the mass_insert() function limits queries to 16k. |
| 1941 | // Let's dump what we have so far to the db. |
| 1942 | $image_count = 0; |
| 1943 | ewww_image_optimizer_mass_insert( $wpdb->ewwwio_images, $images ); |
| 1944 | $images = array(); |
| 1945 | } |
| 1946 | } // End if(). |
| 1947 | } // End foreach(). |
| 1948 | if ( ! empty( $images ) ) { |
| 1949 | ewww_image_optimizer_mass_insert( $wpdb->ewwwio_images, $images ); |
| 1950 | } |
| 1951 | set_transient( 'ewww_image_optimizer_aux_iterator', 0 ); |
| 1952 | ewww_image_optimizer_reset_images( $reset_images ); |
| 1953 | delete_transient( 'ewww_image_optimizer_aux_iterator' ); |
| 1954 | $end = microtime( true ) - $start; |
| 1955 | ewwwio_debug_message( "query time for $file_counter files (seconds): $end" ); |
| 1956 | clearstatcache(); |
| 1957 | ewwwio_memory( __FUNCTION__ ); |
| 1958 | $folders_completed[] = $dir; |
| 1959 | update_option( 'ewww_image_optimizer_aux_folders_completed', $folders_completed, false ); |
| 1960 | } |
| 1961 | |
| 1962 | /** |
| 1963 | * Convert all records in table to use filesize rather than md5sum. |
| 1964 | * |
| 1965 | * @global object $wpdb |
| 1966 | */ |
| 1967 | function ewww_image_optimizer_aux_images_convert() { |
| 1968 | global $wpdb; |
| 1969 | $old_records = $wpdb->get_results( "SELECT id,path,image_md5 FROM $wpdb->ewwwio_images", ARRAY_A ); |
| 1970 | foreach ( $old_records as $record ) { |
| 1971 | if ( empty( $record['image_md5'] ) ) { |
| 1972 | continue; |
| 1973 | } |
| 1974 | $record['path'] = ewww_image_optimizer_absolutize_path( $record['path'] ); |
| 1975 | if ( false !== strpos( $record['path'], 'phar://' ) ) { |
| 1976 | continue; |
| 1977 | } |
| 1978 | $image_md5 = md5_file( $record['path'] ); |
| 1979 | if ( $image_md5 === $record['image_md5'] ) { |
| 1980 | $filesize = ewww_image_optimizer_filesize( $record['path'] ); |
| 1981 | $wpdb->update( |
| 1982 | $wpdb->ewwwio_images, |
| 1983 | array( |
| 1984 | 'image_md5' => null, |
| 1985 | 'image_size' => $filesize, |
| 1986 | ), |
| 1987 | array( |
| 1988 | 'id' => $record['id'], |
| 1989 | ) |
| 1990 | ); |
| 1991 | } else { |
| 1992 | $wpdb->delete( |
| 1993 | $wpdb->ewwwio_images, |
| 1994 | array( |
| 1995 | 'id' => $record['id'], |
| 1996 | ) |
| 1997 | ); |
| 1998 | } |
| 1999 | } |
| 2000 | } |
| 2001 | |
| 2002 | /** |
| 2003 | * Searches for images to optimize. |
| 2004 | * |
| 2005 | * Scans all auxiliary folders, including some predefined ones, and those configured by the user. |
| 2006 | * Used for the main bulk tool, and the scheduled optimization. |
| 2007 | * |
| 2008 | * @param string $hook Optional. Indicates if scheduled optimization is running. |
| 2009 | * @global object $wpdb |
| 2010 | * @return int Number of images ready to optimize. |
| 2011 | */ |
| 2012 | function ewww_image_optimizer_aux_images_scan( $hook = '' ) { |
| 2013 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 2014 | session_write_close(); |
| 2015 | // Retrieve the time when the scan starts. |
| 2016 | $started = microtime( true ); |
| 2017 | if ( ! get_transient( 'ewww_image_optimizer_skip_aux' ) ) { |
| 2018 | update_option( 'ewww_image_optimizer_aux_resume', 'scanning' ); |
| 2019 | set_transient( 'ewww_image_optimizer_aux_lock', time(), 60 ); |
| 2020 | $scan_args = get_option( 'ewww_image_optimizer_scan_args' ); |
| 2021 | if ( is_array( $scan_args ) && ! empty( $scan_args ) ) { |
| 2022 | ewwwio_debug_message( 'scan args retrieved from db' ); |
| 2023 | if ( ! empty( $scan_args['force_reopt'] ) ) { |
| 2024 | ewwwio_debug_message( 'force re-opt enabled' ); |
| 2025 | ewwwio()->force = true; |
| 2026 | } |
| 2027 | if ( ! empty( $scan_args['force_smart'] ) ) { |
| 2028 | ewwwio_debug_message( 'smart re-opt enabled' ); |
| 2029 | ewwwio()->force_smart = true; |
| 2030 | } |
| 2031 | if ( ! empty( $scan_args['webp_only'] ) ) { |
| 2032 | ewwwio_debug_message( 'webp-only enabled' ); |
| 2033 | ewwwio()->webp_only = true; |
| 2034 | } |
| 2035 | } |
| 2036 | ewwwio_debug_message( 'getting fresh list of files to optimize' ); |
| 2037 | // Collect a list of images from the current theme (and parent theme if applicable). |
| 2038 | $child_path = get_stylesheet_directory(); |
| 2039 | $parent_path = get_template_directory(); |
| 2040 | ewww_image_optimizer_image_scan( $child_path, $started ); |
| 2041 | if ( $child_path !== $parent_path ) { |
| 2042 | ewww_image_optimizer_image_scan( $parent_path, $started ); |
| 2043 | } |
| 2044 | if ( ! function_exists( 'is_plugin_active' ) ) { |
| 2045 | // Need to include the plugin library for the is_plugin_active function. |
| 2046 | require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
| 2047 | } |
| 2048 | ewwwio_debug_message( 'checking for commonly-used folders' ); |
| 2049 | $upload_dir = wp_get_upload_dir(); |
| 2050 | ewww_image_optimizer_image_scan( $upload_dir['basedir'] . '/avatars', $started ); |
| 2051 | ewww_image_optimizer_image_scan( $upload_dir['basedir'] . '/group-avatars', $started ); |
| 2052 | ewww_image_optimizer_image_scan( $upload_dir['basedir'] . '/bpfb', $started ); |
| 2053 | ewww_image_optimizer_image_scan( $upload_dir['basedir'] . '/buddypress', $started ); |
| 2054 | ewww_image_optimizer_image_scan( WP_CONTENT_DIR . '/grand-media', $started ); |
| 2055 | if ( is_plugin_active( 'wp-symposium/wp-symposium.php' ) || is_plugin_active_for_network( 'wp-symposium/wp-symposium.php' ) ) { |
| 2056 | ewww_image_optimizer_image_scan( get_option( 'symposium_img_path' ), $started ); |
| 2057 | } |
| 2058 | if ( defined( 'WPS_CORE_PLUGINS' ) ) { |
| 2059 | ewww_image_optimizer_image_scan( WP_CONTENT_DIR . '/wps-pro-content', $started ); |
| 2060 | } |
| 2061 | if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) ) { |
| 2062 | ewww_image_optimizer_image_scan( WP_CONTENT_DIR . '/ewww/lazy/', $started ); |
| 2063 | } |
| 2064 | if ( is_plugin_active( 'ml-slider/ml-slider.php' ) || is_plugin_active_for_network( 'ml-slider/ml-slider.php' ) ) { |
| 2065 | global $wpdb; |
| 2066 | $slide_paths = array(); |
| 2067 | $slides = $wpdb->get_col( |
| 2068 | " |
| 2069 | SELECT wpposts.ID |
| 2070 | FROM $wpdb->posts wpposts |
| 2071 | INNER JOIN $wpdb->term_relationships term_relationships |
| 2072 | ON wpposts.ID = term_relationships.object_id |
| 2073 | INNER JOIN $wpdb->terms wpterms |
| 2074 | ON term_relationships.term_taxonomy_id = wpterms.term_id |
| 2075 | INNER JOIN $wpdb->term_taxonomy term_taxonomy |
| 2076 | ON wpterms.term_id = term_taxonomy.term_id |
| 2077 | WHERE term_taxonomy.taxonomy = 'ml-slider' |
| 2078 | AND wpposts.post_type = 'attachment' |
| 2079 | " |
| 2080 | ); |
| 2081 | if ( ewww_image_optimizer_iterable( $slides ) ) { |
| 2082 | foreach ( $slides as $slide ) { |
| 2083 | $type = get_post_meta( $slide, 'ml-slider_type', true ); |
| 2084 | $type = $type ? $type : 'image'; // For backwards compatibility, fall back to 'image'. |
| 2085 | if ( 'image' !== $type ) { |
| 2086 | continue; |
| 2087 | } |
| 2088 | $backup_sizes = get_post_meta( $slide, '_wp_attachment_backup_sizes', true ); |
| 2089 | if ( ewww_image_optimizer_iterable( $backup_sizes ) ) { |
| 2090 | foreach ( $backup_sizes as $backup_size => $meta ) { |
| 2091 | if ( preg_match( '/resized-/', $backup_size ) ) { |
| 2092 | $path = $meta['path']; |
| 2093 | if ( ! ewwwio_is_file( $path ) ) { |
| 2094 | continue; |
| 2095 | } |
| 2096 | $image_size = ewww_image_optimizer_filesize( $path ); |
| 2097 | if ( ! $image_size ) { |
| 2098 | continue; |
| 2099 | } |
| 2100 | $already_optimized = ewww_image_optimizer_find_already_optimized( $path ); |
| 2101 | // A pending record already present. |
| 2102 | if ( ! empty( $already_optimized ) && empty( $already_optimized['image_size'] ) ) { |
| 2103 | continue; |
| 2104 | } |
| 2105 | $mimetype = ewww_image_optimizer_mimetype( $path, 'i' ); |
| 2106 | // This is a brand new image. |
| 2107 | if ( preg_match( '/^image\/(jpeg|png|gif|svg\+xml)/', $mimetype ) && empty( $already_optimized ) ) { |
| 2108 | $slide_paths[] = array( |
| 2109 | 'path' => ewww_image_optimizer_relativize_path( $path ), |
| 2110 | 'orig_size' => $image_size, |
| 2111 | ); |
| 2112 | // This is a changed image. |
| 2113 | } elseif ( preg_match( '/^image\/(jpeg|png|gif|svg\+xml)/', $mimetype ) && ! empty( $already_optimized ) && (int) $already_optimized['image_size'] !== $image_size ) { |
| 2114 | $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->ewwwio_images SET pending = 1 WHERE id = %d", $already_optimized['id'] ) ); |
| 2115 | } |
| 2116 | } |
| 2117 | } |
| 2118 | } |
| 2119 | } |
| 2120 | } // End if(). |
| 2121 | if ( ! empty( $slide_paths ) ) { |
| 2122 | ewww_image_optimizer_mass_insert( $wpdb->ewwwio_images, $slide_paths ); |
| 2123 | } |
| 2124 | } // End if(). |
| 2125 | // Collect a list of images in auxiliary folders provided by user. |
| 2126 | $aux_paths = ewww_image_optimizer_get_option( 'ewww_image_optimizer_aux_paths' ); |
| 2127 | if ( $aux_paths ) { |
| 2128 | if ( ewww_image_optimizer_iterable( $aux_paths ) ) { |
| 2129 | foreach ( $aux_paths as $aux_path ) { |
| 2130 | ewww_image_optimizer_image_scan( $aux_path, $started ); |
| 2131 | } |
| 2132 | } |
| 2133 | } |
| 2134 | // Scan images in two most recent media library folders if the option is enabled, and this is a scheduled optimization. |
| 2135 | if ( 'ewww-image-optimizer-auto' === $hook && ewww_image_optimizer_get_option( 'ewww_image_optimizer_include_media_paths' ) ) { |
| 2136 | // Retrieve the location of the WordPress upload folder. |
| 2137 | $upload_dir = wp_get_upload_dir(); |
| 2138 | // Retrieve the path of the upload folder. |
| 2139 | $upload_path = $upload_dir['basedir']; |
| 2140 | $this_month = gmdate( 'm' ); |
| 2141 | $this_year = gmdate( 'Y' ); |
| 2142 | ewww_image_optimizer_image_scan( "$upload_path/$this_year/$this_month/", $started ); |
| 2143 | if ( class_exists( 'DateTime' ) ) { |
| 2144 | $date = new DateTime(); |
| 2145 | $date->sub( new DateInterval( 'P1M' ) ); |
| 2146 | $last_year = $date->format( 'Y' ); |
| 2147 | $last_month = $date->format( 'm' ); |
| 2148 | ewww_image_optimizer_image_scan( "$upload_path/$last_year/$last_month/", $started ); |
| 2149 | } |
| 2150 | } |
| 2151 | } else { |
| 2152 | ewwwio_debug_message( 'skipping scan because of skip_aux transient' ); |
| 2153 | } // End if(). |
| 2154 | $image_count = (int) ewww_image_optimizer_aux_images_table_count_pending(); |
| 2155 | ewwwio_debug_message( "found $image_count images to optimize while scanning" ); |
| 2156 | update_option( 'ewww_image_optimizer_aux_folders_completed', array(), false ); |
| 2157 | update_option( 'ewww_image_optimizer_scan_args', '' ); |
| 2158 | update_option( 'ewww_image_optimizer_aux_resume', '' ); |
| 2159 | update_option( 'ewww_image_optimizer_bulk_resume', '' ); |
| 2160 | update_option( 'ewww_image_optimizer_bulk_foreground', '' ); |
| 2161 | delete_transient( 'ewww_image_optimizer_aux_lock' ); |
| 2162 | delete_transient( 'ewww_image_optimizer_skip_aux' ); |
| 2163 | if ( wp_doing_ajax() && 'ewww-image-optimizer-auto' !== $hook && ( ! defined( 'WP_CLI' ) || ! WP_CLI ) ) { |
| 2164 | $verify_cloud = ewww_image_optimizer_cloud_verify( ewww_image_optimizer_get_option( 'ewww_image_optimizer_cloud_key' ), false ); |
| 2165 | $usage = false; |
| 2166 | if ( preg_match( '/great/', $verify_cloud ) ) { |
| 2167 | $usage = ewww_image_optimizer_cloud_quota( true ); |
| 2168 | } |
| 2169 | ewwwio_memory( __FUNCTION__ ); |
| 2170 | /* translators: %s: number of images */ |
| 2171 | $ready_msg = sprintf( esc_html( _n( 'There is %s image ready to optimize.', 'There are %s images ready to optimize.', $image_count, 'ewww-image-optimizer' ) ), '<span class="ready-to-optimize-count" style="font-weight:bold">' . number_format_i18n( $image_count ) . '</span>' ); |
| 2172 | if ( is_array( $usage ) && ! $usage['metered'] && ! $usage['unlimited'] ) { |
| 2173 | $credits_available = $usage['licensed'] - $usage['consumed']; |
| 2174 | if ( $credits_available < $image_count ) { |
| 2175 | $ready_msg .= ' ' . esc_html__( 'You do not appear to have enough image credits to complete this operation.', 'ewww-image-optimizer' ); |
| 2176 | } |
| 2177 | } |
| 2178 | if ( $image_count > 1000 ) { |
| 2179 | $ready_msg .= ' <a href="https://docs.ewww.io/article/20-why-do-i-have-so-many-images-on-my-site" target="_blank" data-beacon-article="58598744c697912ffd6c3eb4">' . esc_html__( 'Why are there so many images?', 'ewww-image-optimizer' ) . '</a>'; |
| 2180 | } |
| 2181 | |
| 2182 | $buttons = '<a class="ewww-queue-controls ewww-start-optimization button-secondary" href="#">' . esc_html__( 'Start optimizing', 'ewww-image-optimizer' ) . '</a>'; |
| 2183 | $buttons .= '<a class="ewww-queue-controls ewww-pause-optimization button-secondary" style="display:none" href="#">' . esc_html__( 'Pause Optimization', 'ewww-image-optimizer' ) . '</a>'; |
| 2184 | |
| 2185 | if ( empty( $image_count ) ) { |
| 2186 | $ready_msg = esc_html__( 'There are no images to optimize.', 'ewww-image-optimizer' ); |
| 2187 | } |
| 2188 | ewwwio_ob_clean(); |
| 2189 | die( |
| 2190 | wp_json_encode( |
| 2191 | array( |
| 2192 | 'ready' => $image_count, |
| 2193 | 'message' => $ready_msg, |
| 2194 | ) |
| 2195 | ) |
| 2196 | ); |
| 2197 | } elseif ( 'ewww-image-optimizer-auto' === $hook ) { |
| 2198 | ewwwio_debug_message( 'retrieving images for scheduled queue' ); |
| 2199 | global $wpdb; |
| 2200 | $images_queued = $wpdb->get_col( "SELECT id FROM $wpdb->ewwwio_images WHERE pending=1" ); |
| 2201 | if ( ewww_image_optimizer_iterable( $images_queued ) ) { |
| 2202 | foreach ( $images_queued as $id ) { |
| 2203 | ewwwio()->background_image->push_to_queue( |
| 2204 | array( |
| 2205 | 'id' => $id, |
| 2206 | 'new' => 0, |
| 2207 | ) |
| 2208 | ); |
| 2209 | } |
| 2210 | } |
| 2211 | ewwwio()->background_image->dispatch(); |
| 2212 | } |
| 2213 | ewwwio_memory( __FUNCTION__ ); |
| 2214 | return $image_count; |
| 2215 | } |
| 2216 | |
| 2217 | /** |
| 2218 | * Called by scheduled optimization to cleanup after ourselves. |
| 2219 | * |
| 2220 | * @param bool $auto Indicates whether or not the function is called from scheduled (auto) optimization mode. |
| 2221 | */ |
| 2222 | function ewww_image_optimizer_aux_images_cleanup( $auto = false ) { |
| 2223 | ewwwio_debug_message( '<b>' . __FUNCTION__ . '()</b>' ); |
| 2224 | // Verify that an authorized user has started the optimizer. |
| 2225 | $permissions = apply_filters( 'ewww_image_optimizer_bulk_permissions', '' ); |
| 2226 | if ( ! $auto && ( empty( $_REQUEST['ewww_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['ewww_wpnonce'] ), 'ewww-image-optimizer-bulk' ) || ! current_user_can( $permissions ) ) ) { |
| 2227 | ewwwio_ob_clean(); |
| 2228 | die( esc_html__( 'Access denied.', 'ewww-image-optimizer' ) ); |
| 2229 | } |
| 2230 | // All done, so we can update the bulk options with empty values. |
| 2231 | update_option( 'ewww_image_optimizer_aux_resume', '', false ); |
| 2232 | if ( ! $auto ) { |
| 2233 | ewwwio_ob_clean(); |
| 2234 | // And let the user know we are done. |
| 2235 | echo '<p><b>' . esc_html__( 'Finished', 'ewww-image-optimizer' ) . '</b></p>'; |
| 2236 | ewwwio_memory( __FUNCTION__ ); |
| 2237 | die(); |
| 2238 | } |
| 2239 | } |
| 2240 | |
| 2241 | add_action( 'wp_ajax_bulk_aux_images_table', 'ewww_image_optimizer_aux_images_table' ); |
| 2242 | add_action( 'wp_ajax_bulk_aux_images_table_count', 'ewww_image_optimizer_aux_images_table_count' ); |
| 2243 | add_action( 'wp_ajax_bulk_aux_images_table_clear', 'ewww_image_optimizer_aux_images_clear_all' ); |
| 2244 | add_action( 'wp_ajax_bulk_aux_images_exclude', 'ewww_image_optimizer_aux_images_exclude' ); |
| 2245 | add_action( 'wp_ajax_bulk_aux_images_remove', 'ewww_image_optimizer_aux_images_remove' ); |
| 2246 | add_action( 'wp_ajax_bulk_aux_images_restore_original', 'ewww_image_optimizer_bulk_restore_handler' ); |
| 2247 | add_action( 'wp_ajax_bulk_aux_images_count_converted', 'ewww_image_optimizer_aux_images_count_converted' ); |
| 2248 | add_action( 'wp_ajax_bulk_aux_images_converted_clean', 'ewww_image_optimizer_aux_images_converted_clean' ); |
| 2249 | add_action( 'wp_ajax_bulk_aux_images_table_clean', 'ewww_image_optimizer_aux_images_clean' ); |
| 2250 | add_action( 'wp_ajax_bulk_aux_images_meta_clean', 'ewww_image_optimizer_aux_meta_clean' ); |
| 2251 | add_action( 'wp_ajax_bulk_aux_images_webp_clean', 'ewww_image_optimizer_aux_images_webp_clean_handler' ); |
| 2252 | add_action( 'wp_ajax_bulk_aux_images_delete_webp', 'ewww_image_optimizer_delete_webp_handler' ); |
| 2253 | add_action( 'wp_ajax_bulk_aux_images_delete_original', 'ewww_image_optimizer_ajax_delete_original' ); |
| 2254 | add_action( 'wp_ajax_ewwwio_get_all_attachments', 'ewww_image_optimizer_get_all_attachments' ); |
| 2255 | add_action( 'wp_ajax_ewwwio_webp_attachment_count', 'ewww_image_optimizer_webp_attachment_count' ); |
| 2256 | // Non-AJAX handler(s) to reset tool resume option/placeholder. |
| 2257 | add_action( 'admin_action_ewww_image_optimizer_reset_bulk_restore', 'ewww_image_optimizer_reset_bulk_restore' ); |
| 2258 | add_action( 'admin_action_ewww_image_optimizer_reset_webp_clean', 'ewww_image_optimizer_reset_webp_clean' ); |
| 2259 |