wp_back/wp-content/plugins/wp-smushit/app/class-media-library.php
2024-05-20 15:37:46 +03:00

531 lines
15 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Media library class.
*
* Responsible for displaying a UI (stats + action links) in the media library and the editor.
*
* @since 3.4.0
* @package Smush\App
*/
namespace Smush\App;
use Smush\Core\Core;
use Smush\Core\Helper;
use Smush\Core\Media\Media_Item;
use Smush\Core\Media\Media_Item_Optimizer;
use Smush\Core\Media_Library\Media_Library_Row;
use Smush\Core\Modules\Abstract_Module;
use Smush\Core\Modules\Smush;
use Smush\Core\Stats\Global_Stats;
use WP_Post;
use WP_Query;
/**
* Class Media_Library
*/
class Media_Library extends Abstract_Module {
/**
* Core instance.
*
* @var Core $core
*/
private $core;
private $allowed_image_sizes;
/**
* Media_Library constructor.
*
* @param Core $core Core instance.
*/
public function __construct( Core $core ) {
parent::__construct();
$this->core = $core;
}
/**
* Init functionality that is related to the UI.
*/
public function init_ui() {
// 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 );
}
/**
* 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( '<div class="smush-failed-processing">%s</div>', $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::ERROR_META_KEY,
'compare' => 'EXISTS',
),
array(
'key' => Media_Item::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::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 );
?>
<label for="smush_filter" class="screen-reader-text">
<?php esc_html_e( 'Filter by Smush status', 'wp-smushit' ); ?>
</label>
<select class="smush-filters" name="smush-filter" id="smush_filter">
<option value="" <?php selected( $ignored, '' ); ?>><?php esc_html_e( 'Smush: All images', 'wp-smushit' ); ?></option>
<option value="unsmushed" <?php selected( $ignored, 'unsmushed' ); ?>><?php esc_html_e( 'Smush: Not processed', 'wp-smushit' ); ?></option>
<option value="ignored" <?php selected( $ignored, 'ignored' ); ?>><?php esc_html_e( 'Smush: Bulk ignored', 'wp-smushit' ); ?></option>
<option value="failed_processing" <?php selected( $ignored, 'failed_processing' ); ?>><?php esc_html_e( 'Smush: Failed Processing', 'wp-smushit' ); ?></option>
</select>
<?php
}
/**
* Data attributes are not allowed on <a> 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 = '<p class="smush-status">' . __( 'Smushing in progress...', 'wp-smushit' ) . '</p>';
$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 ) );
}
/**
* Skip messages respective to their IDs.
*
* @param string $msg_id Message ID.
*
* TODO: Remove this method as no longer need.
*
* @return bool
*/
public function skip_reason( $msg_id ) {
$count = count( get_intermediate_image_sizes() );
$smush_orgnl_txt = sprintf(
/* translators: %s: number of thumbnails */
esc_html__( 'When you upload an image to WordPress it automatically creates %s thumbnail sizes that are commonly used in your pages. WordPress also stores the original full-size image, but because these are not usually embedded on your site we dont Smush them. Pro users can override this.', 'wp-smushit' ),
$count
);
$skip_msg = array(
'large_size' => $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 = '<a href="https://wpmudev.com/project/wp-smush-pro/?utm_source=smush&utm_medium=plugin&utm_campaign=smush_medialibrary_savings" target="_blank">
<span class="sui-tooltip sui-tooltip-left sui-tooltip-constrained sui-tooltip-top-right-mobile" data-tooltip="' . $skip_msg[ $msg_id ] . '">
<span class="sui-tag sui-tag-purple sui-tag-sm">' . esc_html__( 'PRO', 'wp-smushit' ) . '</span></span></a>';
}
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 = new Media_Library_Row( $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 .= "<a href='#' class='wp-smush-send' data-id='{$id}'>{$button_txt}</a>";
if ( get_post_meta( $id, 'wp-smush-ignore-bulk', true ) ) {
$nonce = wp_create_nonce( 'wp-smush-remove-skipped' );
$html .= " | <a href='#' class='wp-smush-remove-skipped' data-id={$id} data-nonce={$nonce}>" . esc_html__( 'Show in bulk Smush', 'wp-smushit' ) . '</a>';
} else {
$html .= " | <a href='#' class='smush-ignore-image' data-id='{$id}'>" . esc_html__( 'Ignore', 'wp-smushit' ) . '</a>';
}
$html .= self::progress_bar();
return $html;
}
/**
* Returns the HTML for progress bar
*
* @return string
*/
public static function progress_bar() {
return '<span class="spinner wp-smush-progress"></span>';
}
}