' . 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 '
' . 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' );
}
?>
' . 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();
?>
bunny.net'
);
?>
' . 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,
)
);
}
}