PluginProbe
Image Optimizer – Compress Images and Convert to WebP or AVIF / 1.6.1
Image Optimizer – Compress Images and Convert to WebP or AVIF v1.6.1
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.6.1, at modules/optimization/components/media-control.php

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