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

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