core = $core;
$this->array_utils = new Array_Utils();
}
/**
* Init functionality that is related to the UI.
*/
public function init_ui() {
if ( Membership::get_instance()->is_api_hub_access_required() ) {
add_action( 'all_admin_notices', array( $this, 'smush_media_hub_connect_notice' ), 5 );
return false;
}
// Media library columns.
add_filter( 'manage_media_columns', array( $this, 'columns' ) );
add_filter( 'manage_upload_sortable_columns', array( $this, 'sortable_column' ) );
add_action( 'manage_media_custom_column', array( $this, 'custom_column' ), 10, 2 );
// Manage column sorting.
add_action( 'pre_get_posts', array( $this, 'smushit_orderby' ) );
// Smush image filter from Media Library.
add_filter( 'ajax_query_attachments_args', array( $this, 'filter_media_query' ) );
// Smush image filter from Media Library (list view).
add_action( 'restrict_manage_posts', array( $this, 'add_filter_dropdown' ) );
// Add pre WordPress 5.0 compatibility.
add_filter( 'wp_kses_allowed_html', array( $this, 'filter_html_attributes' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'extend_media_modal' ), 15 );
add_filter( 'wp_prepare_attachment_for_js', array( $this, 'smush_send_status' ), 99, 3 );
// Add bulk restore action.
add_filter( 'bulk_actions-upload', array( $this, 'add_bulk_restore_action' ) );
add_filter( 'handle_bulk_actions-upload', array( $this, 'bulk_restore_media' ), 10, 3 );
add_action( 'all_admin_notices', array( $this, 'show_bulk_restore_notice' ) );
}
/**
* Add bulk restore action to media lib page.
*
* @param array $actions List actions.
* @return array
*/
public function add_bulk_restore_action( $actions ) {
$actions['smush-bulk-restore'] = esc_html__( 'Smush restore', 'wp-smushit' );
return $actions;
}
/**
* Bulk restore images.
*
* @param string $sendback The redirect URL.
* @param string $doaction Bulk action name.
* @param array $attachment_ids List image ids.
*
* @return string
*/
public function bulk_restore_media( $sendback, $doaction, $attachment_ids ) {
// If there is not bulk restore images, return.
if ( 'smush-bulk-restore' !== $doaction || empty( $attachment_ids ) ) {
return $sendback;
}
$bulk_restore = new Bulk_Restore( $attachment_ids );
$bulk_restore->bulk_restore();
$restored_count = $bulk_restore->get_restored_count();
$total_count = $bulk_restore->get_total_count();
$missing_backup_count = $bulk_restore->get_error_count( 'missing_backup' );
$error_copy_count = $bulk_restore->get_error_count( 'copy_failed' );
$sendback = add_query_arg(
array(
'smush_total' => $total_count,
'smush_restored' => $restored_count,
'smush_missing_backup_count' => $missing_backup_count,
'smush_copy_failed_count' => $error_copy_count,
),
$sendback
);
// Return original location.
return $sendback;
}
/**
* Show bulk restore notice.
*
* @return void
*/
public function show_bulk_restore_notice() {
if ( ! isset( $_GET['smush_restored'], $_GET['smush_total'] ) ) {
return;
}
$total = (int) $this->array_utils->get_array_value( $_GET, 'smush_total', 0 );
$restored = (int) $this->array_utils->get_array_value( $_GET, 'smush_restored', 0 );
$missing_backup_count = (int) $this->array_utils->get_array_value( $_GET, 'smush_missing_backup_count', 0 );
$error_copy_count = (int) $this->array_utils->get_array_value( $_GET, 'smush_copy_failed_count', 0 );
$failed = $total - $restored;
if ( $total <= 0 || $restored > $total ) {
return;
}
$classes = array(
'notice',
'is-dismissible',
);
if ( $failed > 0 ) {
$classes[] = 'notice-warning';
} else {
$classes[] = 'notice-success';
}
?>
get_bulk_restore_message(
$restored,
$total,
$missing_backup_count,
$error_copy_count
)
);
?>
';
$backup_link_close = '';
if ( $missing_backup_count > 0 && $error_copy_count > 0 ) {
// Mixed message.
/* translators: %1$d: restored count, %2$d: total count, %3$d: no backup count, %4$d: copy error count, %5$s: link start tag, %6$s: link end tag */
return sprintf(
esc_html__(
'%1$s%2$d/%3$d images were restored successfully%4$s. %5$d couldn\'t be restored as no backup exists, and %6$d due to a backup copy error. Ensure %7$sBackup original images%8$s is enabled to keep copies of your originals.',
'wp-smushit'
),
'',
(int) $restored,
(int) $total,
'',
(int) $missing_backup_count,
(int) $error_copy_count,
$backup_link,
$backup_link_close
);
} elseif ( $missing_backup_count > 0 ) {
/* translators: %1$d: restored count, %2$d: total count, %3$d: failed count, %4$s: link start tag, %5$s: link end tag */
return sprintf(
esc_html__(
'%1$s%2$d/%3$d images were restored successfully%4$s. %5$d couldn\'t be restored as no backup exists. Ensure %6$sBackup original images%7$s is enabled to keep copies of your originals.',
'wp-smushit'
),
'',
(int) $restored,
(int) $total,
'',
(int) $missing_backup_count,
$backup_link,
$backup_link_close
);
} elseif ( $error_copy_count > 0 ) {
/* translators: %1$d: restored count, %2$d: total count, %3$d: failed count, %4$s: link start tag, %5$s: link end tag */
return sprintf(
esc_html__(
'%1$s%2$d/%3$d images were restored successfully%4$s. %5$d couldn\'t be restored due to a backup copy error. Ensure %6$sBackup original images%7$s is enabled to keep copies of your originals.',
'wp-smushit'
),
'',
(int) $restored,
(int) $total,
'',
(int) $error_copy_count,
$backup_link,
$backup_link_close
);
}
return sprintf(
/* translators: %1$d: restored count, %2$d: total count */
esc_html__( 'All selected images were restored successfully (%1$d/%2$d).', 'wp-smushit' ),
(int) $restored,
(int) $total
);
}
/**
* Print column header for Smush results in the media library using the `manage_media_columns` hook.
*
* @param array $defaults Defaults array.
*
* @return array
*/
public function columns( $defaults ) {
$defaults['smushit'] = 'Smush';
return $defaults;
}
/**
* Add the Smushit Column to sortable list
*
* @param array $columns Columns array.
*
* @return array
*/
public function sortable_column( $columns ) {
$columns['smushit'] = 'smushit';
return $columns;
}
/**
* Print column data for Smush results in the media library using
* the `manage_media_custom_column` hook.
*
* @param string $column_name Column name.
* @param int $id Attachment ID.
*/
public function custom_column( $column_name, $id ) {
if ( 'smushit' === $column_name ) {
$escaped_text = wp_kses_post( $this->generate_markup( $id ) );
if ( $this->is_failed_processing_page() ) {
$escaped_text = sprintf( '%s
', $escaped_text );
}
echo $escaped_text;
}
}
/**
* Detect failed processing page.
*
* @since 3.12.0
*
* @return boolean
*/
private function is_failed_processing_page() {
static $is_failed_processing_page;
if ( null === $is_failed_processing_page ) {
$filter = filter_input( INPUT_GET, 'smush-filter', FILTER_SANITIZE_SPECIAL_CHARS );
$is_failed_processing_page = 'failed_processing' === $filter;
}
return $is_failed_processing_page;
}
/**
* Order by query for smush columns.
*
* @param WP_Query $query Query.
*
* @return WP_Query
*/
public function smushit_orderby( $query ) {
global $current_screen;
// Filter only media screen.
if (
! is_admin()
|| ( ! empty( $current_screen ) && 'upload' !== $current_screen->base )
|| 'attachment' !== $query->get( 'post_type' )
) {
return $query;
}
$filter = filter_input( INPUT_GET, 'smush-filter', FILTER_SANITIZE_SPECIAL_CHARS );
// Ignored.
if ( 'ignored' === $filter ) {
$query->set( 'meta_query', $this->query_ignored() );
return $query;
} elseif ( 'unsmushed' === $filter ) {
// Not processed.
$query->set( 'meta_query', $this->query_unsmushed() );
return $query;
} elseif ( 'failed_processing' === $filter ) {
// Failed processing.
$query->set( 'meta_query', $this->query_failed_processing() );
return $query;
}
// TODO: do we need this?
$orderby = $query->get( 'orderby' );
if ( isset( $orderby ) && 'smushit' === $orderby ) {
$query->set(
'meta_query',
array(
'relation' => 'OR',
array(
'key' => Smush::$smushed_meta_key,
'compare' => 'EXISTS',
),
array(
'key' => Smush::$smushed_meta_key,
'compare' => 'NOT EXISTS',
),
)
);
$query->set( 'orderby', 'meta_value_num' );
}
return $query;
}
/**
* Add our filter to the media query filter in Media Library.
*
* @since 2.9.0
*
* @see wp_ajax_query_attachments()
*
* @param array $query Query.
*
* @return mixed
*/
public function filter_media_query( $query ) {
$post_query = filter_input( INPUT_POST, 'query', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_REQUIRE_ARRAY );
if ( ! isset( $post_query['stats'] ) ) {
return $query;
}
$filter_name = $post_query['stats'];
// Excluded.
if ( 'excluded' === $filter_name ) {
$query['meta_query'] = $this->query_ignored();
} elseif ( 'unsmushed' === $filter_name ) {
// Unsmushed.
$query['meta_query'] = $this->query_unsmushed();
} elseif ( 'failed_processing' === $filter_name ) {
// Failed processing.
$query['meta_query'] = $this->query_failed_processing();
}
return $query;
}
/**
* Meta query for images skipped from bulk smush.
*
* @return array
*/
private function query_failed_processing() {
// Custom query to add error items.
add_filter( 'posts_where_request', array( $this, 'filter_query_to_add_media_item_errors' ) );
// Custom query for failed on optimization.
$meta_query = array(
'relation' => 'AND',
array(
'key' => Media_Item_Optimizer::get_error_meta_key(),
'compare' => 'EXISTS',
),
array(
'key' => Media_Item::get_ignored_meta_key(),
'compare' => 'NOT EXISTS',
),
);
return $meta_query;
}
public function filter_query_to_add_media_item_errors( $where ) {
global $wpdb;
remove_filter( 'posts_where_request', array( $this, 'filter_query_to_add_media_item_errors' ) );
$media_error_ids = Global_Stats::get()->get_error_list()->get_ids();
if ( empty( $media_error_ids ) ) {
return $where;
}
$where .= sprintf( " OR {$wpdb->posts}.ID IN (%s)", join( ',', $media_error_ids ) );
return $where;
}
/**
* Meta query for images skipped from bulk smush.
*
* @return array
*/
private function query_ignored() {
return array(
array(
'key' => Media_Item::get_ignored_meta_key(),
'compare' => 'EXISTS',
),
);
}
/**
* Meta query for uncompressed images.
*
* @return array
*/
private function query_unsmushed() {
return Core::get_unsmushed_meta_query();
}
/**
* Adds a search dropdown in Media Library list view to filter out images that have been
* ignored with bulk Smush.
*
* @since 3.2.0
*/
public function add_filter_dropdown() {
$scr = get_current_screen();
if ( 'upload' !== $scr->base ) {
return;
}
$ignored = filter_input( INPUT_GET, 'smush-filter', FILTER_SANITIZE_SPECIAL_CHARS );
?>
elements on WordPress before 5.0.0.
* Add backward compatibility.
*
* @since 3.5.0
* @see https://github.com/WordPress/WordPress/commit/a0309e80b6a4d805e4f230649be07b4bfb1a56a5#diff-a0e0d196dd71dde453474b0f791828fe
* @param array $context Context.
*
* @return mixed
*/
public function filter_html_attributes( $context ) {
global $wp_version;
if ( version_compare( '5.0.0', $wp_version, '<' ) ) {
return $context;
}
$context['a']['data-tooltip'] = true;
$context['a']['data-id'] = true;
$context['a']['data-nonce'] = true;
return $context;
}
/**
* Load media assets.
*
* Localization also used in Gutenberg integration.
*/
public function extend_media_modal() {
// Get current screen.
$current_screen = get_current_screen();
// Only run on required pages.
if ( ! empty( $current_screen ) && ! in_array( $current_screen->id, Core::$external_pages, true ) && empty( $current_screen->is_block_editor ) ) {
return;
}
if ( wp_script_is( 'smush-backbone-extension', 'enqueued' ) ) {
return;
}
wp_enqueue_script(
'smush-backbone-extension',
WP_SMUSH_URL . 'app/assets/js/smush-media.min.js',
array(
'jquery',
'media-editor', // Used in image filters.
'media-views',
'media-grid',
'wp-util',
'wp-api',
),
WP_SMUSH_VERSION,
true
);
wp_localize_script(
'smush-backbone-extension',
'smush_vars',
array(
'strings' => array(
'stats_label' => esc_html__( 'Smush', 'wp-smushit' ),
'filter_all' => esc_html__( 'Smush: All images', 'wp-smushit' ),
'filter_not_processed' => esc_html__( 'Smush: Not processed', 'wp-smushit' ),
'filter_excl' => esc_html__( 'Smush: Bulk ignored', 'wp-smushit' ),
'filter_failed' => esc_html__( 'Smush: Failed Processing', 'wp-smushit' ),
'gb' => array(
'stats' => esc_html__( 'Smush Stats', 'wp-smushit' ),
'select_image' => esc_html__( 'Select an image to view Smush stats.', 'wp-smushit' ),
'size' => esc_html__( 'Image size', 'wp-smushit' ),
'savings' => esc_html__( 'Savings', 'wp-smushit' ),
),
),
)
);
}
/**
* Send smush status for attachment.
*
* @param array $response Response array.
* @param WP_Post $attachment Attachment object.
*
* @return mixed
*/
public function smush_send_status( $response, $attachment ) {
if ( ! isset( $attachment->ID ) ) {
return $response;
}
// Validate nonce.
$status = $this->smush_status( $attachment->ID );
$response['smush'] = $status;
return $response;
}
/**
* Get the smush button text for attachment.
*
* @param int $id Attachment ID for which the Status has to be set.
*
* @return string
*/
private function smush_status( $id ) {
$action = filter_input( INPUT_POST, 'action', FILTER_SANITIZE_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
// Show Temporary Status, For Async Optimisation, No Good workaround.
if ( ! get_transient( 'wp-smush-restore-' . $id ) && 'upload-attachment' === $action && $this->settings->get( 'auto' ) ) {
$status_txt = '' . __( 'Smushing in progress...', 'wp-smushit' ) . '
';
$button_txt = __( 'Smush Now!', 'wp-smushit' );
return $this->column_html( $id, $status_txt, $button_txt, false );
}
// Else return the normal status.
return trim( $this->generate_markup( $id ) );
}
/**
* Display the Smush Hub Connect notice in Media Library.
*
* Callback for the 'admin_notices' action.
*
* @return void
*/
public function smush_media_hub_connect_notice() {
if ( ! $this->should_display_media_notice() ) {
return;
}
$notice_hidden = WP_Smush::get_instance()->admin()->is_notice_dismissed( 'media-hub-connect-notice' );
if ( $notice_hidden ) {
return;
}
$hub_connect_url = Hub_Connector::get_connect_site_url( 'smush-bulk', 'smush_wpadmin_media_library' );
if ( is_multisite() ) {
$hub_connect_url = str_replace( '/wp-admin/', '/wp-admin/network/', $hub_connect_url );
}
?>
$smush_orgnl_txt,
'size_limit' => esc_html__( "Image couldn't be smushed as it exceeded the 5Mb size limit, Pro users can smush images without any size restriction.", 'wp-smushit' ),
);
$skip_rsn = '';
if ( ! empty( $skip_msg[ $msg_id ] ) ) {
$skip_rsn = '
' . esc_html__( 'PRO', 'wp-smushit' ) . '';
}
return $skip_rsn;
}
/**
* Generate HTML for image status on the media library page.
*
* @since 3.5.0 Refactored from set_status().
*
* @param int $id Attachment ID.
*
* @return string HTML content or array of results.
*/
public function generate_markup( $id ) {
$media_lib_item = Media_Library_Row::get_instance( $id );
return $media_lib_item->generate_markup();
}
/**
* Print the column html.
*
* @param string $id Media id.
* @param string $html Status text.
* @param string $button_txt Button label.
* @param boolean $show_button Whether to shoe the button.
*
* @return string
*/
private function column_html( $id, $html = '', $button_txt = '', $show_button = true ) {
// Don't proceed if attachment is not image, or if image is not a jpg, png or gif, or if is not found.
$is_smushable = Helper::is_smushable( $id );
if ( ! $is_smushable ) {
return false === $is_smushable ? esc_html__( 'Image not found!', 'wp-smushit' ) : esc_html__( 'Not processed', 'wp-smushit' );
}
// If we aren't showing the button.
if ( ! $show_button ) {
return $html;
}
if ( 'Super-Smush' === $button_txt ) {
$html .= ' | ';
}
$html .= "{$button_txt}";
if ( get_post_meta( $id, 'wp-smush-ignore-bulk', true ) ) {
$nonce = wp_create_nonce( 'wp-smush-remove-skipped' );
$html .= " | " . esc_html__( 'Show in bulk Smush', 'wp-smushit' ) . '';
} else {
$html .= " | " . esc_html__( 'Ignore', 'wp-smushit' ) . '';
}
$html .= self::progress_bar();
return $html;
}
/**
* Check whether the Smush media notice should be displayed.
*
* @return bool
*/
private function should_display_media_notice() {
if( ! Helper::is_user_allowed( 'manage_options' ) || ( is_multisite() && ! Helper::is_user_allowed( 'manage_network' ) ) ){
return false;
}
if ( ! function_exists( 'get_current_screen' ) ) {
return false;
}
$current_screen = get_current_screen();
// Show only on Media Library (upload) page.
if ( false === strpos( $current_screen->id, 'upload' ) ) {
return false;
}
return true;
}
/**
* Returns the HTML for progress bar
*
* @return string
*/
public static function progress_bar() {
return '';
}
}