ny-compress-images' ), esc_html__( 'Bulk Optimization', 'tiny-compress-images' ), 'upload_files', 'tiny-bulk-optimization', $this->get_method( 'render_bulk_optimization_page' ) ); } public function add_plugin_links( $current_links ) { $additional = array( 'settings' => sprintf( '%s', esc_html__( 'Settings', 'tiny-compress-images' ) ), 'bulk' => sprintf( '%s', esc_html__( 'Bulk Optimization', 'tiny-compress-images' ) ), ); return array_merge( $additional, $current_links ); } public function tiny_compatibility() { if ( defined( 'ICL_SITEPRESS_VERSION' ) ) { $tiny_wpml_compatibility = new Tiny_WPML(); } } public function compress_original_retina_image( $attachment_id, $path ) { $tiny_image = new Tiny_Image( $this->settings, $attachment_id ); $tiny_image->compress_retina( 'original_wr2x', $path ); } public function compress_retina_image( $attachment_id, $path, $size_name ) { $tiny_image = new Tiny_Image( $this->settings, $attachment_id ); $tiny_image->compress_retina( $size_name . '_wr2x', $path ); } public function remove_retina_image( $attachment_id, $path ) { $tiny_image = new Tiny_Image( $this->settings, $attachment_id ); $tiny_image->remove_retina_metadata(); } public function enqueue_scripts( $hook ) { wp_enqueue_style( self::NAME . '_admin', plugins_url( '/css/admin.css', __FILE__ ), array(), self::version() ); wp_enqueue_style( self::NAME . '_chart', plugins_url( '/css/optimization-chart.css', __FILE__ ), array(), self::version() ); wp_register_script( self::NAME . '_admin', plugins_url( '/js/admin.js', __FILE__ ), array(), self::version(), true ); // WordPress < 3.3 does not handle multidimensional arrays wp_localize_script( self::NAME . '_admin', 'tinyCompress', array( 'nonce' => wp_create_nonce( 'tiny-compress' ), 'wpVersion' => self::wp_version(), 'pluginVersion' => self::version(), 'L10nAllDone' => __( 'All images are processed', 'tiny-compress-images' ), 'L10nNoActionTaken' => __( 'No action taken', 'tiny-compress-images' ), 'L10nBulkAction' => __( 'Compress Images', 'tiny-compress-images' ), 'L10nCancelled' => __( 'Cancelled', 'tiny-compress-images' ), 'L10nCompressing' => __( 'Compressing', 'tiny-compress-images' ), 'L10nCompressed' => __( 'compressed', 'tiny-compress-images' ), 'L10nFile' => __( 'File', 'tiny-compress-images' ), 'L10nSizesOptimized' => __( 'Sizes optimized', 'tiny-compress-images' ), 'L10nInitialSize' => __( 'Initial size', 'tiny-compress-images' ), 'L10nCurrentSize' => __( 'Current size', 'tiny-compress-images' ), 'L10nSavings' => __( 'Savings', 'tiny-compress-images' ), 'L10nStatus' => __( 'Status', 'tiny-compress-images' ), 'L10nShowMoreDetails' => __( 'Show more details', 'tiny-compress-images' ), 'L10nError' => __( 'Error', 'tiny-compress-images' ), 'L10nLatestError' => __( 'Latest error', 'tiny-compress-images' ), 'L10nInternalError' => __( 'Internal error', 'tiny-compress-images' ), 'L10nOutOf' => __( 'out of', 'tiny-compress-images' ), 'L10nWaiting' => __( 'Waiting', 'tiny-compress-images' ), )); wp_enqueue_script( self::NAME . '_admin' ); if ( 'media_page_tiny-bulk-optimization' == $hook ) { wp_enqueue_style( self::NAME . '_tiny_bulk_optimization', plugins_url( '/css/bulk-optimization.css', __FILE__ ), array(), self::version() ); wp_enqueue_style( self::NAME . '_chart', plugins_url( '/css/optimization-chart.css', __FILE__ ), array(), self::version() ); wp_register_script( self::NAME . '_tiny_bulk_optimization', plugins_url( '/js/bulk-optimization.js', __FILE__ ), array(), self::version(), true ); wp_enqueue_script( self::NAME . '_tiny_bulk_optimization' ); } } public function process_attachment( $metadata, $attachment_id ) { if ( $this->settings->auto_compress_enabled() ) { if ( $this->settings->background_compress_enabled() && ! $this->settings->remove_local_files_setting_enabled() ) { $this->async_compress_on_upload( $metadata, $attachment_id ); } else { return $this->blocking_compress_on_upload( $metadata, $attachment_id ); } } return $metadata; } public function blocking_compress_on_upload( $metadata, $attachment_id ) { if ( ! empty( $metadata ) ) { $tiny_image = new Tiny_Image( $this->settings, $attachment_id, $metadata ); $result = $tiny_image->compress(); return $tiny_image->get_wp_metadata(); } else { return $metadata; } } public function async_compress_on_upload( $metadata, $attachment_id ) { $context = 'wp'; $action = 'tiny_async_optimize_upload_new_media'; $_ajax_nonce = wp_create_nonce( 'new_media-' . $attachment_id ); $body = compact( 'action', '_ajax_nonce', 'metadata', 'attachment_id', 'context' ); $args = array( 'timeout' => 0.01, 'blocking' => false, 'body' => $body, 'cookies' => isset( $_COOKIE ) && is_array( $_COOKIE ) ? $_COOKIE : array(), 'sslverify' => apply_filters( 'https_local_ssl_verify', false ), ); if ( defined( 'XMLRPC_REQUEST' ) && get_current_user_id() ) { /* We generate a hash to be used for the transient we use to store the current user. */ $rpc_hash = md5( maybe_serialize( $body ) ); $args['body']['tiny_rpc_action'] = $args['body']['action']; /* We set a different action to make sure that all RPC requests are first validated. */ $args['body']['action'] = 'tiny_rpc'; $args['body']['tiny_rpc_hash'] = $rpc_hash; $args['body']['tiny_rpc_nonce'] = wp_create_nonce( 'tiny_rpc_' . $rpc_hash ); /* We can't use cookies here, so we save the user id in a transient so that we can retrieve it again when processing the RPC request. We should be able to use a relatively short timeout, as the request should be processed directly afterwards. */ set_transient( 'tiny_rpc_' . $rpc_hash, get_current_user_id(), 10 ); } if ( getenv( 'WORDPRESS_HOST' ) !== false ) { wp_remote_post( getenv( 'WORDPRESS_HOST' ) . '/wp-admin/admin-ajax.php', $args ); } else { wp_remote_post( admin_url( 'admin-ajax.php' ), $args ); } } public function process_rpc_request() { if ( empty( $_POST['tiny_rpc_action'] ) || empty( $_POST['tiny_rpc_hash'] ) || 32 !== strlen( $_POST['tiny_rpc_hash'] ) ) { exit(); } $rpc_hash = sanitize_key( $_POST['tiny_rpc_hash'] ); $user_id = absint( get_transient( 'tiny_rpc_' . $rpc_hash ) ); $user = $user_id ? get_userdata( $user_id ) : false; /* We no longer need the transient. */ delete_transient( 'tiny_rpc_' . $rpc_hash ); if ( ! $user || ! $user->exists() ) { exit(); } wp_set_current_user( $user_id ); if ( ! check_ajax_referer( 'tiny_rpc_' . $rpc_hash, 'tiny_rpc_nonce', false ) ) { exit(); } /* Now that everything is checked, perform the actual action. */ $action = $_POST['tiny_rpc_action']; unset( $_POST['action'], $_POST['tiny_rpc_action'], $_POST['tiny_rpc_id'], $_POST['tiny_rpc_nonce'] ); do_action( 'wp_ajax_' . $action ); } public function compress_on_upload() { if ( current_user_can( 'upload_files' ) ) { $attachment_id = intval( $_POST['attachment_id'] ); $metadata = $_POST['metadata']; if ( is_array( $metadata ) ) { $tiny_image = new Tiny_Image( $this->settings, $attachment_id, $metadata ); $result = $tiny_image->compress(); // The wp_update_attachment_metadata call is thrown because the // dimensions of the original image can change. This will then // trigger other plugins and can result in unexpected behaviour and // further changes to the image. This may require another approach. // Note that as of WP 5.3 it is advised to not hook into this filter // anymore, so other plugins are less likely to be triggered. wp_update_attachment_metadata( $attachment_id, $tiny_image->get_wp_metadata() ); } } exit(); } public function compress_image_from_library() { if ( ! $this->check_ajax_referer() ) { exit(); } if ( ! current_user_can( 'upload_files' ) ) { $message = esc_html__( "You don't have permission to upload files.", 'tiny-compress-images' ); echo $message; exit(); } if ( empty( $_POST['id'] ) ) { $message = esc_html__( 'Not a valid media file.', 'tiny-compress-images' ); echo $message; exit(); } $id = intval( $_POST['id'] ); $metadata = wp_get_attachment_metadata( $id ); if ( ! is_array( $metadata ) ) { $message = esc_html__( 'Could not find metadata of media file.', 'tiny-compress-images' ); echo $message; exit; } $tiny_image = new Tiny_Image( $this->settings, $id, $metadata ); $result = $tiny_image->compress(); // The wp_update_attachment_metadata call is thrown because the // dimensions of the original image can change. This will then // trigger other plugins and can result in unexpected behaviour and // further changes to the image. This may require another approach. // Note that as of WP 5.3 it is advised to not hook into this filter // anymore, so other plugins are less likely to be triggered. wp_update_attachment_metadata( $id, $tiny_image->get_wp_metadata() ); echo $this->render_compress_details( $tiny_image ); exit(); } public function compress_image_for_bulk() { if ( ! $this->check_ajax_referer() ) { exit(); } if ( ! current_user_can( 'upload_files' ) ) { $message = esc_html__( "You don't have permission to upload files.", 'tiny-compress-images' ); echo json_encode( array( 'error' => $message, ) ); exit(); } if ( empty( $_POST['id'] ) ) { $message = esc_html__( 'Not a valid media file.', 'tiny-compress-images' ); echo json_encode( array( 'error' => $message, ) ); exit(); } $id = intval( $_POST['id'] ); $metadata = wp_get_attachment_metadata( $id ); if ( ! is_array( $metadata ) ) { $message = esc_html__( 'Could not find metadata of media file.', 'tiny-compress-images' ); echo json_encode( array( 'error' => $message, ) ); exit; } $tiny_image_before = new Tiny_Image( $this->settings, $id, $metadata ); $image_statistics_before = $tiny_image_before->get_statistics( $this->settings->get_sizes(), $this->settings->get_active_tinify_sizes() ); $size_before = $image_statistics_before['optimized_total_size']; $tiny_image = new Tiny_Image( $this->settings, $id, $metadata ); $result = $tiny_image->compress(); $image_statistics = $tiny_image->get_statistics( $this->settings->get_sizes(), $this->settings->get_active_tinify_sizes() ); wp_update_attachment_metadata( $id, $tiny_image->get_wp_metadata() ); $current_library_size = intval( $_POST['current_size'] ); $size_after = $image_statistics['optimized_total_size']; $new_library_size = $current_library_size + $size_after - $size_before; $result['message'] = $tiny_image->get_latest_error(); $result['image_sizes_optimized'] = $image_statistics['image_sizes_optimized']; $result['initial_total_size'] = size_format( $image_statistics['initial_total_size'], 1 ); $result['optimized_total_size'] = size_format( $image_statistics['optimized_total_size'], 1 ); $result['savings'] = $tiny_image->get_savings( $image_statistics ); $result['status'] = $this->settings->get_status(); $result['thumbnail'] = wp_get_attachment_image( $id, array( '30', '30' ), true, array( 'class' => 'pinkynail', 'alt' => '', ) ); $result['size_change'] = $size_after - $size_before; $result['human_readable_library_size'] = size_format( $new_library_size, 2 ); echo json_encode( $result ); exit(); } public function ajax_optimization_statistics() { if ( $this->check_ajax_referer() && current_user_can( 'upload_files' ) ) { $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); echo json_encode( $stats ); } exit(); } public function ajax_compression_status() { if ( ! $this->check_ajax_referer() ) { exit(); } if ( ! current_user_can( 'upload_files' ) ) { exit(); } if ( empty( $_POST['id'] ) ) { $message = esc_html__( 'Not a valid media file.', 'tiny-compress-images' ); echo $message; exit(); } $id = intval( $_POST['id'] ); $metadata = wp_get_attachment_metadata( $id ); if ( ! is_array( $metadata ) ) { $message = esc_html__( 'Could not find metadata of media file.', 'tiny-compress-images' ); echo $message; exit; } $tiny_image = new Tiny_Image( $this->settings, $id, $metadata ); echo $this->render_compress_details( $tiny_image ); exit(); } public function media_library_bulk_action() { if ( empty( $_REQUEST['action'] ) || ( 'tiny_bulk_action' != $_REQUEST['action'] && 'tiny_bulk_action' != $_REQUEST['action2'] ) ) { return; } if ( empty( $_REQUEST['media'] ) || ( ! $_REQUEST['media'] ) ) { $_REQUEST['action'] = ''; return; } check_admin_referer( 'bulk-media' ); $ids = implode( '-', array_map( 'intval', $_REQUEST['media'] ) ); $location = 'upload.php?mode=list&ids=' . $ids; if ( ! empty( $_REQUEST['paged'] ) ) { $location = add_query_arg( 'paged', absint( $_REQUEST['paged'] ), $location ); } if ( ! empty( $_REQUEST['s'] ) ) { $location = add_query_arg( 's', $_REQUEST['s'], $location ); } if ( ! empty( $_REQUEST['m'] ) ) { $location = add_query_arg( 'm', $_REQUEST['m'], $location ); } wp_redirect( admin_url( $location ) ); exit(); } public function add_media_columns( $columns ) { $columns[ self::MEDIA_COLUMN ] = esc_html__( 'Compression', 'tiny-compress-images' ); return $columns; } public function render_media_column( $column, $id ) { if ( self::MEDIA_COLUMN === $column ) { $tiny_image = new Tiny_Image( $this->settings, $id ); if ( $tiny_image->file_type_allowed() ) { echo '