' . esc_html__( 'Open LeanPixel', 'lean-pixel' ) . ''; return array_merge( array( 'leanpixel' => $link ), (array) $actions ); } public static function action_links( $links ) { array_unshift( $links, '' . esc_html__( 'Settings', 'lean-pixel' ) . '', '' . esc_html__( 'Docs', 'lean-pixel' ) . '' ); return $links; } public static function register_settings() { register_setting( 'leanpixel', LeanPixel_Settings::OPTION, array( 'type' => 'array', 'sanitize_callback' => array( 'LeanPixel_Settings', 'sanitize' ), 'default' => LeanPixel_Settings::defaults(), ) ); } public static function assets( $hook ) { if ( ! in_array( $hook, array( 'media_page_' . self::PAGE, 'upload.php', 'post.php', 'post-new.php' ), true ) ) { return; } // The file's own date is part of the version, so a browser never shows a stale copy after an update. wp_enqueue_style( 'leanpixel-admin', LEANPIXEL_URL . 'assets/admin.css', array(), LEANPIXEL_VERSION . '.' . (int) filemtime( LEANPIXEL_DIR . 'assets/admin.css' ) ); wp_enqueue_script( 'leanpixel-admin', LEANPIXEL_URL . 'assets/admin.js', array( 'jquery' ), LEANPIXEL_VERSION . '.' . (int) filemtime( LEANPIXEL_DIR . 'assets/admin.js' ), true ); wp_localize_script( 'leanpixel-admin', 'LeanPixel', array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( self::NONCE ), 'i18n' => array( 'working' => __( 'Working…', 'lean-pixel' ), 'failed' => __( 'Something went wrong. Please try again.', 'lean-pixel' ), 'confirm' => __( 'Disconnect this site from LeanPixel? Images already optimized stay as they are.', 'lean-pixel' ), 'done' => __( 'All images are optimized.', 'lean-pixel' ), 'resuming' => __( 'This will continue automatically.', 'lean-pixel' ), 'confirmDel' => __( 'Delete all kept originals? This cannot be undone. Your optimized images stay exactly as they are, but you will no longer be able to restore them.', 'lean-pixel' ), 'deleting' => __( 'Deleting…', 'lean-pixel' ), 'checking' => __( 'Checking image sizes…', 'lean-pixel' ), 'noOversize' => __( 'No oversized images found.', 'lean-pixel' ), /* translators: %d: number of images */ 'left' => __( 'Optimizing… %d left. Keep this page open.', 'lean-pixel' ), 'optimizing' => __( 'Optimizing… you can leave this page; work continues in the background.', 'lean-pixel' ), ), ) ); } /* ------------------------------------------------------------ page */ public static function render_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } echo '
'; self::render_header(); settings_errors(); if ( LeanPixel_Settings::is_ready() ) { // The library on the left; the account beside it. echo '
'; self::render_bulk(); echo '
'; // In local mode nothing is sent anywhere, not even to read the account. if ( LeanPixel_Settings::is_local() ) { self::render_local(); } else { self::render_account(); } echo '
'; self::render_settings(); } elseif ( LeanPixel_Settings::is_pending() ) { echo '
'; self::render_confirm(); echo '
'; } else { echo '
'; self::render_connect(); echo '
'; } echo '
'; } private static function render_header() { ?>

<?php esc_attr_e( 'LeanPixel Image Optimizer', 'lean-pixel' ); ?>


' . esc_html( $host ) . '' ); ?>

' . esc_html( $email ) . '' ); } else { esc_html_e( 'We sent a 6-digit code to the email address for this key. Enter it here to switch it on.', 'lean-pixel' ); } ?>

·

get_error_message() ); ?>

0 ) : ?>

' . esc_html( $size ) . '', 'uploads/' . esc_html( LeanPixel_Optimizer::backup_folder() ) . '/' ); ?>

$label ) : ?>

>
' . esc_html__( 'AVIF versions are not part of your current plan, so only WebP versions are being created.', 'lean-pixel' ) . ' ' . esc_html__( 'See the plans', 'lean-pixel' ) . '

'; } private static function delivery_notice( array $settings ) { if ( empty( $settings['serve_nextgen'] ) ) { return; } if ( LeanPixel_Delivery::supports_htaccess() ) { if ( ! LeanPixel_Delivery::rules_active() ) { echo '

' . esc_html__( 'The rules could not be written to the .htaccess file in the main folder of your site. Check that the file is writable, then save these settings again.', 'lean-pixel' ) . '

'; } return; } echo '

' . esc_html__( 'Your web server does not use .htaccess files (it looks like nginx). Add these rules to the server configuration to serve the WebP/AVIF versions:', 'lean-pixel' ) . '

'; echo ''; } /** Set-up steps for a CDN, with Bunny as the worked example. */ private static function cdn_help( array $settings ) { $origin = LeanPixel_CDN::origin(); ?>
  1. bunny.net' ); ?>
  2. ' . esc_html( $origin ) . '' ); ?>

ID ) ) { $fields['leanpixel'] = array( 'label' => __( 'LeanPixel', 'lean-pixel' ), 'input' => 'html', 'html' => self::cell( $post->ID ), ); } return $fields; } /** * Status and action for one attachment. Returns escaped HTML. * * @param int $attachment_id Attachment ID. * @return string */ public static function cell( $attachment_id ) { $attachment_id = (int) $attachment_id; $inner = self::cell_inner( $attachment_id ); return '
' . $inner . '
'; } private static function cell_inner( $attachment_id ) { if ( ! LeanPixel_Optimizer::is_supported( $attachment_id ) ) { return ''; } if ( ! LeanPixel_Settings::is_ready() ) { return current_user_can( 'manage_options' ) ? '' . esc_html__( 'Set up LeanPixel', 'lean-pixel' ) . '' : ''; } $status = get_post_meta( $attachment_id, LeanPixel_Optimizer::STATUS, true ); $data = LeanPixel_Optimizer::data( $attachment_id ); $can = current_user_can( 'edit_post', $attachment_id ); $button = function ( $do, $label ) use ( $can ) { return $can ? '' : ''; }; $message = ''; switch ( $status ) { case 'optimized': $t = LeanPixel_Optimizer::totals( $data ); $html = ''; if ( $t['before'] > 0 && $t['after'] < $t['before'] ) { $html .= '' . esc_html( sprintf( /* translators: %s: percentage */ __( 'Saved %s%%', 'lean-pixel' ), number_format_i18n( 100 * ( $t['before'] - $t['after'] ) / $t['before'], 0 ) ) ) . '
'; // The image itself first, then the total with its thumbnail sizes, // so the second figure is not mistaken for the size of the upload. $main = wp_basename( (string) get_attached_file( $attachment_id ) ); if ( isset( $data['files'][ $main ]['before'], $data['files'][ $main ]['after'] ) && empty( $data['files'][ $main ]['skip'] ) && $t['files'] > 1 ) { $html .= '' . esc_html( sprintf( /* translators: 1: size before, 2: size after */ __( 'Image: %1$s → %2$s', 'lean-pixel' ), size_format( $data['files'][ $main ]['before'], 1 ), size_format( $data['files'][ $main ]['after'], 1 ) ) ) . '
'; } $html .= '' . esc_html( $t['files'] > 1 ? sprintf( /* translators: 1: size before, 2: size after, 3: number of thumbnail sizes */ _n( 'With its %3$s thumbnail size: %1$s → %2$s', 'With its %3$s thumbnail sizes: %1$s → %2$s', $t['files'] - 1, 'lean-pixel' ), size_format( $t['before'], 1 ), size_format( $t['after'], 1 ), number_format_i18n( $t['files'] - 1 ) ) : size_format( $t['before'], 1 ) . ' → ' . size_format( $t['after'], 1 ) ) . ''; } else { $html .= '' . esc_html__( 'Already as small as it gets', 'lean-pixel' ) . ''; } $extras = array(); if ( $t['webp'] ) { $extras[] = 'WebP'; } if ( $t['avif'] ) { $extras[] = 'AVIF'; } if ( $extras ) { /* translators: %s: format names, such as WebP */ $html .= '
' . esc_html( sprintf( __( '%s versions created', 'lean-pixel' ), implode( ' + ', $extras ) ) ) . ''; } if ( current_user_can( 'manage_options' ) && LeanPixel_Optimizer::can_restore( $attachment_id, $data ) ) { $html .= '
' . $button( 'restore', __( 'Restore original', 'lean-pixel' ) ); } return $html . $message; case 'excluded': return '' . esc_html__( 'Skipped by your exclude rules', 'lean-pixel' ) . ''; case 'queued': return '' . esc_html__( 'Waiting to be optimized…', 'lean-pixel' ) . '
' . $button( 'optimize', __( 'Optimize now', 'lean-pixel' ) ) . $message; case 'error': $error = isset( $data['error'] ) ? $data['error'] : __( 'Could not be optimized.', 'lean-pixel' ); return '' . esc_html( $error ) . '
' . $button( 'optimize', __( 'Try again', 'lean-pixel' ) ) . $message; } return $button( 'optimize', __( 'Optimize', 'lean-pixel' ) ) . $message; } /* ------------------------------------------------------------ ajax */ private static function require_cap( $capability ) { if ( ! current_user_can( $capability ) ) { wp_send_json_error( array( 'message' => __( 'You are not allowed to do that.', 'lean-pixel' ) ), 403 ); } } public static function ajax_connect() { check_ajax_referer( self::NONCE, 'nonce' ); self::require_cap( 'manage_options' ); $mode = isset( $_POST['mode'] ) ? sanitize_key( wp_unslash( $_POST['mode'] ) ) : ''; if ( 'register' === $mode ) { $email = isset( $_POST['value'] ) ? sanitize_email( wp_unslash( $_POST['value'] ) ) : ''; if ( ! is_email( $email ) ) { wp_send_json_error( array( 'message' => __( 'Please enter a valid email address.', 'lean-pixel' ) ) ); } $result = LeanPixel_API::register( $email ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } $key = LeanPixel_Settings::clean_key( isset( $result['api_key'] ) ? $result['api_key'] : '' ); if ( '' !== $key && ! empty( $result['pending'] ) ) { LeanPixel_Settings::update( array( 'api_key' => $key ) ); update_option( LeanPixel_Settings::PENDING, $email, false ); wp_send_json_success(); } } else { $key = LeanPixel_Settings::clean_key( isset( $_POST['value'] ) ? sanitize_text_field( wp_unslash( $_POST['value'] ) ) : '' ); if ( '' === $key ) { wp_send_json_error( array( 'message' => __( 'That does not look like a LeanPixel API key.', 'lean-pixel' ) ) ); } $result = LeanPixel_API::account( $key ); if ( is_wp_error( $result ) && 'email_unverified' === $result->get_error_code() ) { // A key whose email address has not been confirmed yet: ask for the code. LeanPixel_Settings::update( array( 'api_key' => $key ) ); update_option( LeanPixel_Settings::PENDING, '', false ); wp_send_json_success(); } if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } } if ( '' === $key ) { wp_send_json_error( array( 'message' => __( 'The service did not return a usable key.', 'lean-pixel' ) ) ); } LeanPixel_Settings::update( array( 'api_key' => $key ) ); delete_option( LeanPixel_Settings::PENDING ); if ( isset( $result['account'] ) && is_array( $result['account'] ) ) { LeanPixel_API::remember_account( $result['account'] ); } delete_option( LeanPixel_Queue::PAUSE ); wp_send_json_success(); } /** Chosen on the first screen: work on this server, without an account. */ public static function ajax_local() { check_ajax_referer( self::NONCE, 'nonce' ); self::require_cap( 'manage_options' ); if ( '' === LeanPixel_Local::capabilities()['engine'] ) { wp_send_json_error( array( 'message' => __( 'This server has no image library (Imagick or GD) available to PHP.', 'lean-pixel' ) ) ); } LeanPixel_Settings::update( array( 'local' => 1 ) ); wp_send_json_success(); } public static function ajax_disconnect() { check_ajax_referer( self::NONCE, 'nonce' ); self::require_cap( 'manage_options' ); LeanPixel_Queue::stop_bulk(); wp_clear_scheduled_hook( LeanPixel_Queue::HOOK ); LeanPixel_Settings::update( array( 'api_key' => '' ) ); delete_option( LeanPixel_Settings::ACCOUNT ); delete_option( LeanPixel_Settings::PENDING ); wp_send_json_success(); } public static function ajax_confirm() { check_ajax_referer( self::NONCE, 'nonce' ); self::require_cap( 'manage_options' ); $code = isset( $_POST['value'] ) ? preg_replace( '/\D/', '', sanitize_text_field( wp_unslash( $_POST['value'] ) ) ) : ''; $result = LeanPixel_API::confirm( $code ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } delete_option( LeanPixel_Settings::PENDING ); delete_option( LeanPixel_Queue::PAUSE ); wp_send_json_success(); } public static function ajax_resend() { check_ajax_referer( self::NONCE, 'nonce' ); self::require_cap( 'manage_options' ); $result = LeanPixel_API::resend(); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } wp_send_json_success( array( 'message' => __( 'A new code is on its way. Use the newest email.', 'lean-pixel' ) ) ); } public static function ajax_bulk() { check_ajax_referer( self::NONCE, 'nonce' ); self::require_cap( 'manage_options' ); $do = isset( $_POST['do'] ) ? sanitize_key( wp_unslash( $_POST['do'] ) ) : ''; $state = 'idle'; switch ( $do ) { case 'start': LeanPixel_Queue::start_bulk(); $state = 'working'; break; case 'stop': LeanPixel_Queue::stop_bulk(); break; case 'retry': LeanPixel_Queue::retry_failed(); LeanPixel_Queue::start_bulk(); $state = 'working'; break; case 'step': $state = LeanPixel_Queue::run( 12 ); break; case 'resize': $cursor = isset( $_POST['cursor'] ) ? absint( $_POST['cursor'] ) : 0; $resize = LeanPixel_Optimizer::requeue_oversized( $cursor, microtime( true ) + 8 ); if ( $resize['done'] ) { $counts = LeanPixel_Queue::counts(); if ( $counts['queued'] > 0 ) { LeanPixel_Queue::start_bulk(); $state = 'working'; } } $status = self::bulk_status( $state ); $status['resize'] = $resize; wp_send_json_success( $status ); } wp_send_json_success( self::bulk_status( $state ) ); } private static function bulk_status( $state ) { $counts = LeanPixel_Queue::counts(); $stats = LeanPixel_Settings::stats(); $pause = LeanPixel_Queue::pause_state(); $done = $counts['total'] - $counts['remaining']; $saved = ''; if ( $stats['before'] > $stats['after'] ) { $saved = sprintf( /* translators: 1: size saved, 2: percentage, 3: number of files */ __( 'Saved so far: %1$s (%2$s%%) across %3$s files (each image plus its thumbnail sizes).', 'lean-pixel' ), size_format( $stats['before'] - $stats['after'], 1 ), number_format_i18n( 100 * ( $stats['before'] - $stats['after'] ) / $stats['before'], 0 ), number_format_i18n( $stats['files'] ) ); } $nextgen = ''; if ( $stats['next_before'] > $stats['next_after'] ) { $nextgen = sprintf( /* translators: 1: format name(s), 2: size saved, 3: percentage */ __( '%1$s versions: %2$s (%3$s%%) smaller than the files as uploaded.', 'lean-pixel' ), LeanPixel_Settings::get( 'avif' ) ? 'WebP/AVIF' : 'WebP', size_format( $stats['next_before'] - $stats['next_after'], 1 ), number_format_i18n( 100 * ( $stats['next_before'] - $stats['next_after'] ) / $stats['next_before'], 0 ) ); } $numbers = sprintf( /* translators: 1: images done, 2: total images */ __( '%1$s of %2$s images done', 'lean-pixel' ), number_format_i18n( $done ), number_format_i18n( $counts['total'] ) ); if ( $counts['error'] ) { /* translators: %s: number of images */ $numbers .= ' · ' . sprintf( __( '%s could not be optimized', 'lean-pixel' ), number_format_i18n( $counts['error'] ) ); } if ( $counts['excluded'] ) { /* translators: %s: number of images */ $numbers .= ' · ' . sprintf( __( '%s skipped by your exclude rules', 'lean-pixel' ), number_format_i18n( $counts['excluded'] ) ); } return array( 'state' => $state, 'running' => LeanPixel_Queue::is_bulk_running(), 'percent' => $counts['total'] ? (int) floor( 100 * $done / $counts['total'] ) : 100, 'remaining' => $counts['remaining'], 'errors' => $counts['error'], 'numbers' => $numbers, 'saved' => $saved, 'nextgen' => $nextgen, 'bars' => array( 'before' => $stats['before'] > 0 ? size_format( $stats['before'], 1 ) : '', 'after' => $stats['before'] > 0 ? size_format( $stats['after'], 1 ) : '', 'after_pct' => $stats['before'] > 0 ? round( 100 * $stats['after'] / $stats['before'], 1 ) : 0, 'next_pct' => $stats['next_before'] > 0 ? round( 100 * $stats['next_after'] / $stats['next_before'], 1 ) : 0, 'next_name' => LeanPixel_Settings::get( 'avif' ) ? __( 'WebP/AVIF versions', 'lean-pixel' ) : __( 'WebP versions', 'lean-pixel' ), 'next_value' => $stats['next_before'] > 0 /* translators: %s: percentage */ ? sprintf( __( '%s%% smaller', 'lean-pixel' ), number_format_i18n( 100 * ( $stats['next_before'] - $stats['next_after'] ) / $stats['next_before'], 0 ) ) : '', ), 'pause' => $pause ? $pause['message'] : '', 'usage' => self::usage_text( LeanPixel_API::cached_account() ), 'review' => self::review_text( $stats, $counts ), ); } public static function ajax_delete_originals() { check_ajax_referer( self::NONCE, 'nonce' ); self::require_cap( 'manage_options' ); if ( LeanPixel_Queue::is_bulk_running() ) { wp_send_json_error( array( 'message' => __( 'Stop the bulk optimizer first, then delete the originals.', 'lean-pixel' ) ) ); } wp_send_json_success( LeanPixel_Optimizer::delete_backups( microtime( true ) + 8 ) ); } /* ------------------------------------- media library bulk actions */ public static function bulk_actions( $actions ) { if ( LeanPixel_Settings::is_ready() ) { $actions['leanpixel_optimize'] = __( 'Optimize with LeanPixel', 'lean-pixel' ); if ( current_user_can( 'manage_options' ) ) { $actions['leanpixel_restore'] = __( 'Restore originals (LeanPixel)', 'lean-pixel' ); } } return $actions; } /** * WordPress has already checked the nonce and the upload_files capability * before it calls this. * * @param string $redirect Where WordPress will send the browser next. * @param string $action The chosen bulk action. * @param int[] $ids Selected attachment IDs. * @return string */ public static function handle_bulk_action( $redirect, $action, $ids ) { if ( ! in_array( $action, array( 'leanpixel_optimize', 'leanpixel_restore' ), true ) || ! LeanPixel_Settings::is_ready() ) { return $redirect; } if ( 'leanpixel_restore' === $action && ! current_user_can( 'manage_options' ) ) { return $redirect; } $count = 0; foreach ( array_map( 'absint', (array) $ids ) as $id ) { if ( ! $id || ! current_user_can( 'edit_post', $id ) || ! LeanPixel_Optimizer::is_supported( $id ) ) { continue; } $status = get_post_meta( $id, LeanPixel_Optimizer::STATUS, true ); if ( 'leanpixel_restore' === $action ) { if ( 'optimized' === $status && true === LeanPixel_Optimizer::restore_attachment( $id ) ) { ++$count; } continue; } if ( 'optimized' === $status ) { continue; } if ( 'error' === $status ) { delete_post_meta( $id, LeanPixel_Optimizer::DATA ); // A fresh attempt. } LeanPixel_Queue::enqueue( $id ); ++$count; } return add_query_arg( array( 'leanpixel_done' => 'leanpixel_restore' === $action ? 'restored' : 'queued', 'leanpixel_count' => $count, ), $redirect ); } public static function removable_args( $args ) { $args[] = 'leanpixel_done'; $args[] = 'leanpixel_count'; return $args; } public static function bulk_notice() { $screen = get_current_screen(); // phpcs:disable WordPress.Security.NonceVerification.Recommended -- only shows a result message. if ( ! $screen || 'upload' !== $screen->id || ! isset( $_GET['leanpixel_done'], $_GET['leanpixel_count'] ) ) { return; } $done = sanitize_key( wp_unslash( $_GET['leanpixel_done'] ) ); $count = absint( $_GET['leanpixel_count'] ); // phpcs:enable if ( 'restored' === $done ) { /* translators: %s: number of images */ $text = sprintf( _n( '%s image restored to its original.', '%s images restored to their originals.', $count, 'lean-pixel' ), number_format_i18n( $count ) ); echo '

' . esc_html( $text ) . '

'; return; } if ( ! $count ) { echo '

' . esc_html__( 'Nothing to optimize: the selected images are already optimized or are not a supported type.', 'lean-pixel' ) . '

'; return; } /* translators: %s: number of images */ $text = sprintf( _n( '%s image queued for optimization.', '%s images queued for optimization.', $count, 'lean-pixel' ), number_format_i18n( $count ) ); echo '

' . esc_html( $text ) . '

'; } /** Works through queued images while the media library is open. */ const REVIEW_OPTION = 'leanpixel_review_done'; /** * Where reviews are left, or '' when there is nowhere to send people. * The address is only known once WordPress.org lists the plugin, which * shows in the update data WordPress already keeps. */ private static function review_url() { $url = ''; $updates = get_site_transient( 'update_plugins' ); $file = plugin_basename( LEANPIXEL_FILE ); foreach ( array( 'no_update', 'response' ) as $list ) { if ( is_object( $updates ) && isset( $updates->{$list}[ $file ]->slug ) ) { $url = 'https://wordpress.org/support/plugin/' . sanitize_key( $updates->{$list}[ $file ]->slug ) . '/reviews/#new-post'; break; } } /** * Filters the address of the plugin's review page. Return '' to never ask for a review. * * @param string $url Review page address, or '' if the plugin is not listed on WordPress.org. */ return (string) apply_filters( 'leanpixel_review_url', $url ); } /** * The one-time review request, shown once the whole library is done and a * worthwhile amount has been saved. '' when it should not be shown. * * @param array $stats Running totals. * @param array $counts Image counts. * @return string */ private static function review_text( array $stats, array $counts ) { $saved = $stats['before'] - $stats['after']; if ( $counts['remaining'] > 0 || $counts['optimized'] < 1 || $saved < MB_IN_BYTES || get_option( self::REVIEW_OPTION ) || ! current_user_can( 'manage_options' ) ) { return ''; } /* translators: %s: amount of disk space */ return sprintf( __( 'All done: your images are %s lighter.', 'lean-pixel' ), size_format( $saved, 1 ) ); } /** The request is shown until it is answered either way, then never again. */ public static function ajax_review() { check_ajax_referer( self::NONCE, 'nonce' ); self::require_cap( 'manage_options' ); update_option( self::REVIEW_OPTION, 1, false ); wp_send_json_success(); } public static function ajax_drive() { check_ajax_referer( self::NONCE, 'nonce' ); self::require_cap( 'upload_files' ); $state = LeanPixel_Queue::run( 12 ); $counts = LeanPixel_Queue::counts(); $pause = LeanPixel_Queue::pause_state(); wp_send_json_success( array( 'state' => $state, 'queued' => $counts['queued'], 'pause' => $pause ? $pause['message'] : '', ) ); } public static function ajax_item() { check_ajax_referer( self::NONCE, 'nonce' ); self::require_cap( 'upload_files' ); $id = isset( $_POST['id'] ) ? absint( $_POST['id'] ) : 0; $do = isset( $_POST['do'] ) ? sanitize_key( wp_unslash( $_POST['do'] ) ) : ''; if ( ! $id || 'attachment' !== get_post_type( $id ) || ! current_user_can( 'edit_post', $id ) ) { wp_send_json_error( array( 'message' => __( 'You are not allowed to do that.', 'lean-pixel' ) ), 403 ); } if ( 'restore' === $do ) { // Restoring lets an image be optimized again, which uses the site's allowance or its own server time. self::require_cap( 'manage_options' ); $result = LeanPixel_Optimizer::restore_attachment( $id ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } wp_send_json_success( array( 'html' => self::cell( $id ), 'done' => true, ) ); } if ( ! LeanPixel_Settings::is_ready() ) { wp_send_json_error( array( 'message' => __( 'LeanPixel is not set up yet. Finish connecting on the Media → LeanPixel screen.', 'lean-pixel' ) ) ); } // Clear an earlier failure so the image gets a fresh attempt. if ( 'error' === get_post_meta( $id, LeanPixel_Optimizer::STATUS, true ) ) { delete_post_meta( $id, LeanPixel_Optimizer::DATA ); } $result = LeanPixel_Optimizer::optimize_attachment( $id, microtime( true ) + 12 ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } if ( 'locked' === $result ) { wp_send_json_error( array( 'message' => __( 'This image is being processed right now. Please try again in a moment.', 'lean-pixel' ) ) ); } wp_send_json_success( array( 'html' => self::cell( $id ), 'done' => true === $result, ) ); } }