api
2 days ago
background
2 days ago
backups
2 days ago
bulk
2 days ago
cache
2 days ago
cli
2 days ago
external
2 days ago
frontend
2 days ago
integrations
2 days ago
lazy-load
2 days ago
media
2 days ago
media-library
2 days ago
membership
2 days ago
modules
2 days ago
parser
2 days ago
photon
2 days ago
png2jpg
2 days ago
product-analytics
2 days ago
rating-notification
2 days ago
resize
2 days ago
security
2 days ago
smush
2 days ago
srcset
2 days ago
stats
2 days ago
threads
2 days ago
transform
2 days ago
class-abstract-settings-dto.php
2 days ago
class-activity-log-controller.php
2 days ago
class-animated-status-controller.php
2 days ago
class-array-utils.php
2 days ago
class-attachment-id-list.php
2 days ago
class-backup-size.php
2 days ago
class-configs.php
2 days ago
class-controller.php
2 days ago
class-core.php
2 days ago
class-cron-controller.php
2 days ago
class-deprecated-hooks.php
2 days ago
class-error-handler.php
2 days ago
class-file-system.php
2 days ago
class-file-utils.php
2 days ago
class-format-utils.php
2 days ago
class-helper.php
2 days ago
class-hub-connector.php
2 days ago
class-installer.php
2 days ago
class-keyword-exclusions.php
2 days ago
class-modules.php
2 days ago
class-multisite-utils.php
2 days ago
class-optimization-controller.php
2 days ago
class-optimizer.php
2 days ago
class-plugin-settings-watcher.php
2 days ago
class-rest.php
2 days ago
class-server-utils.php
2 days ago
class-settings-controller.php
2 days ago
class-settings-dto.php
2 days ago
class-settings-sanitizer.php
2 days ago
class-settings.php
2 days ago
class-shim.php
2 days ago
class-smush-file.php
2 days ago
class-stats.php
2 days ago
class-string-utils.php
2 days ago
class-time-utils.php
2 days ago
class-timer.php
2 days ago
class-upload-dir.php
2 days ago
class-url-utils.php
2 days ago
class-urls-exclusions.php
2 days ago
class-wp-query-utils.php
2 days ago
wp-compat.php
2 days ago
class-optimization-controller.php
248 lines
| 1 | <?php |
| 2 | |
| 3 | namespace Smush\Core; |
| 4 | |
| 5 | use Smush\Core\Media\Media_Item_Cache; |
| 6 | use Smush\Core\Media\Media_Item_Optimizer; |
| 7 | use Smush\Core\Media_Library\Media_Library_Row; |
| 8 | use Smush\Core\Membership\Membership; |
| 9 | use Smush\Core\Smush\Smush_Optimization; |
| 10 | use Smush\Core\Smush\Smusher; |
| 11 | use Smush\Core\Smush\Smusher_Options_Provider; |
| 12 | use Smush\Core\Stats\Global_Stats; |
| 13 | |
| 14 | /** |
| 15 | * // TODO: [WPMUDEV SMUSH UI] create tests |
| 16 | */ |
| 17 | class Optimization_Controller extends Controller { |
| 18 | |
| 19 | /** |
| 20 | * @var Optimization_Controller |
| 21 | */ |
| 22 | private static $instance; |
| 23 | /** |
| 24 | * @var Global_Stats |
| 25 | */ |
| 26 | private $global_stats; |
| 27 | |
| 28 | private $membership; |
| 29 | /** |
| 30 | * @var Settings |
| 31 | */ |
| 32 | private $settings; |
| 33 | private $media_item_cache; |
| 34 | private $optimizer; |
| 35 | |
| 36 | private function __construct() { |
| 37 | $this->global_stats = Global_Stats::get(); |
| 38 | $this->membership = Membership::get_instance(); |
| 39 | $this->settings = Settings::get_instance(); |
| 40 | $this->media_item_cache = Media_Item_Cache::get_instance(); |
| 41 | $this->optimizer = Optimizer::get_instance(); |
| 42 | |
| 43 | $this->register_action( 'wp_smush_image_sizes_changed', array( $this, 'mark_global_stats_as_outdated' ) ); |
| 44 | $this->register_action( 'wp_smush_settings_updated', array( |
| 45 | $this, |
| 46 | 'maybe_mark_global_stats_as_outdated', |
| 47 | ), 10, 2 ); |
| 48 | |
| 49 | $this->register_action( 'wp_ajax_optimize_attachment', array( $this, 'optimize_attachment' ) ); |
| 50 | $this->register_action( 'wp_async_wp_generate_attachment_metadata', array( |
| 51 | $this, |
| 52 | 'auto_optimize_attachment_async', |
| 53 | ) ); |
| 54 | $this->register_filter( |
| 55 | 'wp_generate_attachment_metadata', |
| 56 | array( $this, 'maybe_auto_optimize_attachment_sync' ), 15, 2 |
| 57 | ); |
| 58 | $this->register_action( 'wp_async_wp_save_image_editor_file', array( $this, 'handle_editor_upload_async' ), '', 2 ); |
| 59 | // Fix SSL CA certificates issue. |
| 60 | $this->register_action( 'wp_smush_before_smush_file', array( $this, 'fix_ssl_ca_certificate_error' ) ); |
| 61 | } |
| 62 | |
| 63 | public static function get_instance() { |
| 64 | if ( empty( self::$instance ) ) { |
| 65 | self::$instance = new self(); |
| 66 | } |
| 67 | |
| 68 | return self::$instance; |
| 69 | } |
| 70 | |
| 71 | public function mark_global_stats_as_outdated() { |
| 72 | $this->global_stats->mark_as_outdated(); |
| 73 | } |
| 74 | |
| 75 | public function maybe_mark_global_stats_as_outdated( $old_settings, $settings ) { |
| 76 | $old_original = ! empty( $old_settings['original'] ); |
| 77 | $new_original = ! empty( $settings['original'] ); |
| 78 | $original_status_changed = $old_original !== $new_original; |
| 79 | if ( $original_status_changed ) { |
| 80 | $this->mark_global_stats_as_outdated(); |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | public function optimize_attachment() { |
| 85 | if ( ! isset( $_REQUEST['attachment_id'] ) ) { |
| 86 | wp_send_json_error( |
| 87 | array( 'error_msg' => esc_html__( 'No attachment ID was provided.', 'wp-smushit' ) ) |
| 88 | ); |
| 89 | } |
| 90 | |
| 91 | if ( ! check_ajax_referer( 'wp-smush-ajax', '_nonce', false ) ) { |
| 92 | wp_send_json_error( |
| 93 | array( 'error_msg' => esc_html__( 'Nonce verification failed', 'wp-smushit' ) ) |
| 94 | ); |
| 95 | } |
| 96 | |
| 97 | if ( ! Helper::is_user_allowed( 'upload_files' ) ) { |
| 98 | wp_send_json_error( |
| 99 | array( 'error_msg' => esc_html__( "You don't have permission to work with uploaded files.", 'wp-smushit' ) ) |
| 100 | ); |
| 101 | } |
| 102 | |
| 103 | if ( $this->membership->is_api_hub_access_required() ) { |
| 104 | wp_send_json_error( |
| 105 | array( 'error_msg' => esc_html__( 'A WPMU DEV Hub connection is required to optimize images.', 'wp-smushit' ) ) |
| 106 | ); |
| 107 | } |
| 108 | |
| 109 | $attachment_id = (int) $_REQUEST['attachment_id']; |
| 110 | $optimizer = $this->optimizer; |
| 111 | $is_optimized = $optimizer->optimize( $attachment_id ); |
| 112 | $media_lib_item = Media_Library_Row::get_instance( $attachment_id ); |
| 113 | $markup = $media_lib_item->generate_markup(); |
| 114 | |
| 115 | if ( $is_optimized ) { |
| 116 | wp_send_json_success( $markup ); |
| 117 | } else { |
| 118 | $errors = $optimizer->get_errors(); |
| 119 | |
| 120 | wp_send_json_error( array( |
| 121 | 'error' => $errors->get_error_code(), |
| 122 | 'error_msg' => $errors->get_error_message(), |
| 123 | 'html_stats' => $markup, |
| 124 | 'show_warning' => $this->membership->should_show_premium_status_warning( $attachment_id ), |
| 125 | ) ); |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | public function auto_optimize_attachment_async( $id ) { |
| 130 | // If we don't have image id or auto Smush is disabled, return. |
| 131 | if ( empty( $id ) || ! $this->optimizer->should_auto_optimize( $id ) ) { |
| 132 | return; |
| 133 | } |
| 134 | |
| 135 | $this->optimizer->optimize( $id ); |
| 136 | } |
| 137 | |
| 138 | public function maybe_auto_optimize_attachment_sync( $meta, $id ) { |
| 139 | // We need to check if this call originated from Gutenberg and allow only media. |
| 140 | if ( Helper::is_non_rest_media() ) { |
| 141 | // If not - return image metadata. |
| 142 | return $meta; |
| 143 | } |
| 144 | |
| 145 | $upload_attachment = filter_input( INPUT_POST, 'action', FILTER_SANITIZE_SPECIAL_CHARS ); |
| 146 | $is_upload_attachment = 'upload-attachment' === $upload_attachment || isset( $_POST['post_id'] ); |
| 147 | |
| 148 | // Our async task runs when action is upload-attachment and post_id found. So do not run on these conditions. |
| 149 | if ( $is_upload_attachment && defined( 'WP_SMUSH_ASYNC' ) && WP_SMUSH_ASYNC ) { |
| 150 | return $meta; |
| 151 | } |
| 152 | |
| 153 | $generating_metadata = doing_filter( 'wp_generate_attachment_metadata' ); |
| 154 | if ( $generating_metadata && ! $this->optimizer->should_auto_optimize( $id ) ) { |
| 155 | return $meta; |
| 156 | } |
| 157 | |
| 158 | $this->optimizer->optimize( $id ); |
| 159 | |
| 160 | return $meta; |
| 161 | } |
| 162 | |
| 163 | /** |
| 164 | * This method runs when a media item is edited. |
| 165 | * |
| 166 | * TODO: this method has been replicated from another method but there are unanswered questions: |
| 167 | * - Can't we optimize the full media item instead of just the full size? |
| 168 | * - We should probably not do anything if the media item was not previously optimized, because in that case we can just treat it as the other unoptimized items and take care of it during bulk smush. |
| 169 | */ |
| 170 | public function handle_editor_upload_async( $id, $post_data ) { |
| 171 | if ( ! $this->optimizer->should_auto_optimize( $id ) ) { |
| 172 | return; |
| 173 | } |
| 174 | |
| 175 | $filepath = empty( $post_data['filepath'] ) ? '' : $post_data['filepath']; |
| 176 | if ( ! $filepath || ! file_exists( $filepath ) ) { |
| 177 | return; |
| 178 | } |
| 179 | |
| 180 | // Get before stats |
| 181 | $before_file_size = filesize( $filepath ); |
| 182 | |
| 183 | $smusher_options = ( new Smusher_Options_Provider() )->get_options(); |
| 184 | $smusher = new Smusher( $smusher_options ); |
| 185 | $smusher->smush( array( $filepath ) ); |
| 186 | if ( $smusher->has_errors() ) { |
| 187 | return; |
| 188 | } |
| 189 | |
| 190 | $media_item = Media_Item_Cache::get_instance()->get( $id ); |
| 191 | $attached_file = $media_item->get_attached_file(); |
| 192 | if ( $attached_file !== $filepath ) { |
| 193 | return; |
| 194 | } |
| 195 | |
| 196 | $after_file_size = filesize( $filepath ); |
| 197 | $media_item_optimizer = new Media_Item_Optimizer( $media_item ); |
| 198 | $smush_optimization = $media_item_optimizer->get_optimization( Smush_Optimization::get_key() ); |
| 199 | $smush_optimization_total_stats = $media_item_optimizer->get_stats( Smush_Optimization::get_key() ); |
| 200 | $smush_optimization_full_size_stats = $media_item_optimizer->get_size_stats( |
| 201 | Smush_Optimization::get_key(), |
| 202 | $media_item->get_main_size()->get_key() |
| 203 | ); |
| 204 | |
| 205 | if ( $smush_optimization->is_optimized() ) { |
| 206 | $smush_optimization_total_stats->set_size_before( |
| 207 | $smush_optimization_total_stats->get_size_before() |
| 208 | - $smush_optimization_full_size_stats->get_size_before() |
| 209 | + $before_file_size |
| 210 | ); |
| 211 | $smush_optimization_total_stats->set_size_after( |
| 212 | $smush_optimization_total_stats->get_size_after() |
| 213 | - $smush_optimization_full_size_stats->get_size_after() |
| 214 | + $after_file_size |
| 215 | ); |
| 216 | $smush_optimization_full_size_stats->set_size_before( $before_file_size ); |
| 217 | $smush_optimization_full_size_stats->set_size_after( $after_file_size ); |
| 218 | $smush_optimization->save(); |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | /** |
| 223 | * Fix SSL CA Certificate issue. |
| 224 | * |
| 225 | * @since 3.9.6 |
| 226 | * |
| 227 | * Check for use of http url (Hostgator mostly) - got it from smush_image. |
| 228 | */ |
| 229 | public function fix_ssl_ca_certificate_error() { |
| 230 | // Return if the member defined it. |
| 231 | if ( defined( 'WP_SMUSH_API_HTTP' ) ) { |
| 232 | return; |
| 233 | } |
| 234 | static $use_http; |
| 235 | /** |
| 236 | * Fix for Hostgator. |
| 237 | * Check for use of http url (Hostgator mostly). |
| 238 | */ |
| 239 | if ( is_null( $use_http ) ) { |
| 240 | $use_http = $this->settings->get_setting( 'wp-smush-use_http' ); |
| 241 | } |
| 242 | |
| 243 | if ( $use_http ) { |
| 244 | define( 'WP_SMUSH_API_HTTP', 'http://smushpro.wpmudev.com/1.0/' ); |
| 245 | } |
| 246 | } |
| 247 | } |
| 248 |