PluginProbe
Image Optimizer – Compress Images and Convert to WebP or AVIF / 1.4.0
Image Optimizer – Compress Images and Convert to WebP or AVIF v1.4.0
1.7.7 1.7.6 1.7.5 1.7.4 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.3.0 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 All 33 releases
image-optimization / modules / optimization / components / media-control.php

media-control.php in Image Optimizer – Compress Images and Convert to WebP or AVIF 1.4.0, at modules/optimization/components/media-control.php

297 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ImageOptimization\Modules\Optimization\Components;
4
5 use ImageOptimization\Classes\Image\{
6 Exceptions\Invalid_Image_Exception,
7 Image,
8 Image_Meta,
9 Image_Optimization_Error_Type,
10 Image_Status
11 };
12 use ImageOptimization\Modules\Oauth\Components\{
13 Connect,
14 Exceptions\Auth_Error,
15 };
16 use ImageOptimization\Modules\Optimization\{
17 Classes\Exceptions\Image_Validation_Error,
18 Classes\Optimization_Error_Message,
19 Classes\Validate_Image,
20 Module,
21 };
22 use ImageOptimization\Classes\File_Utils;
23 use ImageOptimization\Modules\Oauth\Classes\Data;
24 use ImageOptimization\Modules\Settings\Classes\Settings;
25 use ImageOptimization\Modules\Stats\Classes\Optimization_Stats;
26
27 use Throwable;
28
29 use ImageOptimization\Plugin;
30
31 if ( ! defined( 'ABSPATH' ) ) {
32 exit; // Exit if accessed directly.
33 }
34
35 /**
36 * The class is responsible for rendering optimization control in all views.
37 */
38 class Media_Control {
39 const COLUMN_ID = 'image_optimization';
40 const META_BOX_ID = 'image_optimization_meta_box';
41 const DETAILS_MODAL_FIELD_ID = 'image_optimization_modal';
42
43 /**
44 * Adds a new optimization column to the library list view.
45 *
46 * @param array $columns
47 * @return array
48 */
49 public function add_optimization_column( array $columns ): array {
50 if ( empty( $columns ) ) {
51 return $columns;
52 }
53
54 $columns[ self::COLUMN_ID ] = esc_html__( 'Image optimization', 'image-optimization' );
55
56 return $columns;
57 }
58
59 /**
60 * Renders optimization controls in the library list view.
61 *
62 * @param string $column_name
63 * @param int $attachment_id
64 * @return void
65 */
66 public function render_optimization_column( string $column_name, int $attachment_id ) {
67 if ( self::COLUMN_ID !== $column_name ) {
68 return;
69 }
70
71 $this->render_optimization_control( 'list-view', $attachment_id );
72 }
73
74 /**
75 * Adds optimization control as media meta box.
76 *
77 * @return void
78 */
79 public function add_optimization_meta_box() {
80 add_meta_box(
81 self::META_BOX_ID,
82 __( 'Image optimization', 'image-optimization' ),
83 function( $post ) {
84 $this->render_optimization_control( 'meta-box', $post->ID );
85 },
86 'attachment',
87 'side',
88 );
89 }
90
91 /**
92 * Adds optimization control to media modals.
93 *
94 * @param array $form_fields
95 * @param \WP_Post $post
96 *
97 * @return array
98 */
99 public function add_media_modal_details( array $form_fields, \WP_Post $post ): array {
100 $form_fields[ self::DETAILS_MODAL_FIELD_ID ] = [
101 'label' => '',
102 'input' => 'hidden',
103 'value' => $this->get_optimization_control_html( 'details-view', $post->ID ),
104 'required' => false,
105 ];
106
107 return $form_fields;
108 }
109
110 /**
111 * Returns optimization control as an HTML string.
112 *
113 * @param string $context Control placement context. One of ['list-view', 'meta-box', 'details-view'].
114 * @param int $image_id Attachment id.
115 * @return false|string
116 */
117 public function get_optimization_control_html( string $context, int $image_id ) {
118 ob_start();
119
120 $this->render_optimization_control( $context, $image_id );
121
122 $html = ob_get_contents();
123 ob_end_clean();
124
125 return $html;
126 }
127
128 /**
129 * Renders the optimization control for the current image in the current context.
130 *
131 * @param string $context Control placement context. One of ['list-view', 'meta-box', 'details-view'].
132 * @param int $image_id Attachment id.
133 * @return void Renders the control.
134 */
135 public function render_optimization_control( string $context, int $image_id ) {
136 $global_context = [
137 'image_id' => $image_id,
138 'can_be_restored' => false,
139 ];
140
141 // @var ImageOptimizer/Modules/ConnectManager/Module
142 $module = Plugin::instance()->modules_manager->get_modules( 'connect-manager' );
143
144
145 try {
146 if ( ! $module->connect_instance->is_connected() || ! $module->connect_instance->is_activated() ) {
147 throw new Auth_Error( 'You have to activate your license to use Image Optimizer' );
148 }
149
150 Validate_Image::is_valid( $image_id );
151
152 $image = new Image( $image_id );
153 $meta = new Image_Meta( $image->get_id() );
154
155 if ( Image_Status::OPTIMIZED === $meta->get_status() ) {
156 $global_context['can_be_restored'] = $image->can_be_restored();
157 } else {
158 $path = $image->get_file_path( Image::SIZE_FULL );
159 $is_webp = strtolower( File_Utils::get_extension( $path ) ) === 'webp';
160 $backups_enabled = Settings::get( Settings::BACKUP_ORIGINAL_IMAGES_OPTION_NAME );
161 $webp_conversion_enabled = Settings::get( Settings::CONVERT_TO_WEBP_OPTION_NAME );
162
163 $global_context['can_be_restored'] = ( ! $is_webp && $webp_conversion_enabled ) || $backups_enabled;
164 }
165
166 switch ( $meta->get_status() ) {
167 case Image_Status::OPTIMIZATION_IN_PROGRESS:
168 Module::load_template( $context, 'loading', array_merge(
169 $global_context, [
170 'action' => 'optimize',
171 ]
172 ) );
173
174 break;
175
176 case Image_Status::REOPTIMIZING_IN_PROGRESS:
177 Module::load_template( $context, 'loading', array_merge(
178 $global_context, [
179 'action' => 'reoptimize',
180 ]
181 ) );
182
183 break;
184
185 case Image_Status::RESTORING_IN_PROGRESS:
186 Module::load_template( $context, 'loading', array_merge(
187 $global_context, [
188 'action' => 'restore',
189 ]
190 ) );
191
192 break;
193
194 case Image_Status::OPTIMIZED:
195 $stats = Optimization_Stats::get_image_stats( $image_id );
196 $saved = [
197 'relative' => max( 100 - round( $stats['current_image_size'] / $stats['initial_image_size'] * 100 ), 0 ),
198 'absolute' => $stats['initial_image_size'] - $stats['current_image_size'],
199 ];
200
201 $is_losseless_and_webp = Settings::get( Settings::CONVERT_TO_WEBP_OPTION_NAME )
202 && 'lossless' === Settings::get( Settings::COMPRESSION_LEVEL_OPTION_NAME );
203
204 Module::load_template( $context, 'optimized', array_merge(
205 $global_context, [
206 'sizes_optimized_count' => $stats['optimized_image_count'],
207 'saved' => $saved,
208 'is_losseless_and_webp' => $is_losseless_and_webp,
209 ]
210 ) );
211
212 break;
213
214 case Image_Status::OPTIMIZATION_FAILED:
215 $error_type = $meta->get_error_type() ?? Image_Optimization_Error_Type::GENERIC;
216 $error_message = Optimization_Error_Message::get_optimization_error_message( $error_type );
217 $images_left = $module->connect_instance->images_left();
218
219 Module::load_template( $context, 'error', array_merge(
220 $global_context, [
221 'message' => $error_message,
222 'optimization_error_type' => $error_type,
223 'images_left' => $images_left,
224 'allow_retry' => true,
225 'action' => 'optimize',
226 ]
227 ) );
228
229 break;
230
231 case Image_Status::REOPTIMIZING_FAILED:
232 $error_type = $meta->get_error_type() ?? Image_Optimization_Error_Type::GENERIC;
233 $error_message = Optimization_Error_Message::get_reoptimization_error_message( $error_type );
234 $images_left = $module->connect_instance->images_left();
235
236 Module::load_template( $context, 'error', array_merge(
237 $global_context, [
238 'message' => $error_message,
239 'optimization_error_type' => $error_type,
240 'images_left' => $images_left,
241 'allow_retry' => true,
242 'action' => 'reoptimize',
243 ]
244 ) );
245
246 break;
247
248 case Image_Status::RESTORING_FAILED:
249 Module::load_template( $context, 'error', array_merge(
250 $global_context, [
251 'message' => esc_html__( 'Image restoring error', 'image-optimization' ),
252 'allow_retry' => true,
253 'action' => 'restore',
254 ]
255 ) );
256
257 break;
258
259 default:
260 Module::load_template( $context, 'not-optimized', $global_context );
261 }
262 } catch ( Invalid_Image_Exception |Image_Validation_Error $iie ) {
263 Module::load_template( $context, 'error', array_merge(
264 $global_context, [
265 'action' => 'error',
266 'message' => $iie->getMessage(),
267 'allow_retry' => false,
268 ]
269 ) );
270 } catch ( Auth_Error $ae ) {
271 Module::load_template( $context, 'error', array_merge(
272 $global_context, [
273 'action' => 'error',
274 'message' => esc_html__( 'N/A', 'image-optimization' ),
275 'allow_retry' => false,
276 ]
277 ) );
278 } catch ( Throwable $t ) {
279 Module::load_template( $context, 'error', array_merge(
280 $global_context, [
281 'action' => 'error',
282 'message' => esc_html__( 'Internal server error', 'image-optimization' ),
283 'allow_retry' => false,
284 ]
285 ) );
286 }
287 }
288
289 public function __construct() {
290 add_filter( 'manage_upload_columns', [ $this, 'add_optimization_column' ] );
291 add_action( 'manage_media_custom_column', [ $this, 'render_optimization_column' ], 10, 2 );
292
293 add_action( 'add_meta_boxes_attachment', [ $this, 'add_optimization_meta_box' ] );
294 add_filter( 'attachment_fields_to_edit', [ $this, 'add_media_modal_details' ], 10, 2 );
295 }
296 }
297