PluginProbe
Image Optimization – Compress Images and Convert to WebP or AVIF / 1.6.8
Image Optimization – Compress Images and Convert to WebP or AVIF v1.6.8
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 1.6.6 All 32 releases
image-optimization / modules / optimization / components / media-control.php

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

303 lines 8.6 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 'sizes_total' => $stats['total_image_count'],
213 'saved' => $saved,
214 'is_losseless_and_webp' => $is_losseless_and_webp,
215 ]
216 ) );
217
218 break;
219
220 case Image_Status::OPTIMIZATION_FAILED:
221 $error_type = $meta->get_error_type() ?? Image_Optimization_Error_Type::GENERIC;
222 $error_message = Optimization_Error_Message::get_optimization_error_message( $error_type );
223 $images_left = $module->connect_instance->images_left();
224
225 Module::load_template( $context, 'error', array_merge(
226 $global_context, [
227 'message' => $error_message,
228 'optimization_error_type' => $error_type,
229 'images_left' => $images_left,
230 'allow_retry' => true,
231 'action' => 'optimize',
232 ]
233 ) );
234
235 break;
236
237 case Image_Status::REOPTIMIZING_FAILED:
238 $error_type = $meta->get_error_type() ?? Image_Optimization_Error_Type::GENERIC;
239 $error_message = Optimization_Error_Message::get_reoptimization_error_message( $error_type );
240 $images_left = $module->connect_instance->images_left();
241
242 Module::load_template( $context, 'error', array_merge(
243 $global_context, [
244 'message' => $error_message,
245 'optimization_error_type' => $error_type,
246 'images_left' => $images_left,
247 'allow_retry' => true,
248 'action' => 'reoptimize',
249 ]
250 ) );
251
252 break;
253
254 case Image_Status::RESTORING_FAILED:
255 Module::load_template( $context, 'error', array_merge(
256 $global_context, [
257 'message' => esc_html__( 'Image restoring error', 'image-optimization' ),
258 'allow_retry' => true,
259 'action' => 'restore',
260 ]
261 ) );
262
263 break;
264
265 default:
266 Module::load_template( $context, 'not-optimized', $global_context );
267 }
268 } catch ( Invalid_Image_Exception |Image_Validation_Error $iie ) {
269 Module::load_template( $context, 'error', array_merge(
270 $global_context, [
271 'action' => 'error',
272 'message' => $iie->getMessage(),
273 'allow_retry' => false,
274 ]
275 ) );
276 } catch ( Auth_Error $ae ) {
277 Module::load_template( $context, 'error', array_merge(
278 $global_context, [
279 'action' => 'error',
280 'message' => esc_html__( 'N/A', 'image-optimization' ),
281 'allow_retry' => false,
282 ]
283 ) );
284 } catch ( Throwable $t ) {
285 Module::load_template( $context, 'error', array_merge(
286 $global_context, [
287 'action' => 'error',
288 'message' => esc_html__( 'Internal server error', 'image-optimization' ),
289 'allow_retry' => false,
290 ]
291 ) );
292 }
293 }
294
295 public function __construct() {
296 add_filter( 'manage_upload_columns', [ $this, 'add_optimization_column' ] );
297 add_action( 'manage_media_custom_column', [ $this, 'render_optimization_column' ], 10, 2 );
298
299 add_action( 'add_meta_boxes_attachment', [ $this, 'add_optimization_meta_box' ] );
300 add_filter( 'attachment_fields_to_edit', [ $this, 'add_media_modal_details' ], 10, 2 );
301 }
302 }
303