PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 2.2.9
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v2.2.9
2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.9 2.2.8 trunk 1.10 1.3.3 1.3.4 1.3.5 1.3.5.1 1.3.5.2 1.3.6 1.3.6.1 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.5 All 103 releases
imagify / inc / functions / common.php

common.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 2.2.9, at inc/functions/common.php

640 lines 15.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined( 'ABSPATH' ) || exit;
3
4 /**
5 * Get the list of the names of the Imagify context currently in use.
6 *
7 * @since 1.9
8 * @author Grégory Viguier
9 *
10 * @return array An array of strings.
11 */
12 function imagify_get_context_names() {
13 static $contexts;
14
15 if ( isset( $contexts ) ) {
16 return $contexts;
17 }
18
19 /**
20 * Register new contexts.
21 *
22 * @since 1.9
23 * @author Grégory Viguier
24 *
25 * @param array $contexts An array of context names.
26 */
27 $contexts = (array) apply_filters( 'imagify_register_context', [] );
28
29 $contexts = array_filter(
30 $contexts,
31 function ( $context ) {
32 return $context && is_string( $context );
33 }
34 );
35 $contexts = array_merge( [ 'wp', 'custom-folders' ], $contexts );
36
37 sort( $contexts );
38
39 return $contexts;
40 }
41
42 /**
43 * Sanitize an optimization context.
44 *
45 * @since 1.6.11
46 * @author Grégory Viguier
47 *
48 * @param string $context The context.
49 * @return string
50 */
51 function imagify_sanitize_context( $context ) {
52 return sanitize_key( $context );
53 }
54
55 /**
56 * Get the Imagify context instance.
57 *
58 * @since 1.9
59 * @author Grégory Viguier
60 *
61 * @param string $context The context name. Default values are 'wp' and 'custom-folders'.
62 * @return \Imagify\Context\ContextInterface The context instance.
63 */
64 function imagify_get_context( $context ) {
65 $class_name = imagify_get_context_class_name( $context );
66 return $class_name::get_instance();
67 }
68
69 /**
70 * Get the Imagify context class name.
71 *
72 * @since 1.9
73 * @author Grégory Viguier
74 *
75 * @param string $context The context name. Default values are 'wp' and 'custom-folders'.
76 * @return string The context class name.
77 */
78 function imagify_get_context_class_name( $context ) {
79 $context = imagify_sanitize_context( $context );
80
81 switch ( $context ) {
82 case 'wp':
83 $class_name = '\\Imagify\\Context\\WP';
84 break;
85
86 case 'custom-folders':
87 $class_name = '\\Imagify\\Context\\CustomFolders';
88 break;
89
90 default:
91 $class_name = '\\Imagify\\Context\\Noop';
92 }
93
94 /**
95 * Filter the name of the class to use to define a context.
96 *
97 * @since 1.9
98 * @author Grégory Viguier
99 *
100 * @param int $class_name The class name.
101 * @param string $context The context name.
102 */
103 $class_name = apply_filters( 'imagify_context_class_name', $class_name, $context );
104
105 return '\\' . ltrim( $class_name, '\\' );
106 }
107
108 /**
109 * Get the Imagify process instance depending on a context.
110 *
111 * @since 1.9
112 * @author Grégory Viguier
113 *
114 * @param int $media_id The media ID.
115 * @param string $context The context name. Default values are 'wp' and 'custom-folders'.
116 * @return \Imagify\Optimization\Process\ProcessInterface The optimization process instance.
117 */
118 function imagify_get_optimization_process( $media_id, $context ) {
119 $class_name = imagify_get_optimization_process_class_name( $context );
120 return new $class_name( $media_id );
121 }
122
123 /**
124 * Get the Imagify process class name depending on a context.
125 *
126 * @since 1.9
127 * @author Grégory Viguier
128 *
129 * @param string $context The context name. Default values are 'wp' and 'custom-folders'.
130 * @return string The optimization process class name.
131 */
132 function imagify_get_optimization_process_class_name( $context ) {
133 $context = imagify_sanitize_context( $context );
134
135 switch ( $context ) {
136 case 'wp':
137 $class_name = '\\Imagify\\Optimization\\Process\\WP';
138 break;
139
140 case 'custom-folders':
141 $class_name = '\\Imagify\\Optimization\\Process\\CustomFolders';
142 break;
143
144 default:
145 $class_name = '\\Imagify\\Optimization\\Process\\Noop';
146 }
147
148 /**
149 * Filter the name of the class to use for the optimization.
150 *
151 * @since 1.9
152 * @author Grégory Viguier
153 *
154 * @param int $class_name The class name.
155 * @param string $context The context name.
156 */
157 $class_name = apply_filters( 'imagify_process_class_name', $class_name, $context );
158
159 return '\\' . ltrim( $class_name, '\\' );
160 }
161
162 /**
163 * Get WP Direct filesystem object. Also define chmod constants if not done yet.
164 *
165 * @since 1.6.5
166 * @author Grégory Viguier
167 *
168 * @return object A Imagify_Filesystem object.
169 */
170 function imagify_get_filesystem() {
171 return Imagify_Filesystem::get_instance();
172 }
173
174 /**
175 * Convert a path (or URL) to its WebP version.
176 * To keep the function simple:
177 * - Not tested if it's an image.
178 * - File existance is not tested.
179 * - If an URL is given, make sure it doesn't contain query args.
180 *
181 * @since 1.9
182 * @author Grégory Viguier
183 *
184 * @param string $path A file path or URL.
185 * @return string
186 */
187 function imagify_path_to_webp( $path ) {
188 return $path . '.webp';
189 }
190
191 /**
192 * Convert a path (or URL) to its next-gen version.
193 * To keep the function simple:
194 * - Not tested if it's an image.
195 * - File existance is not tested.
196 * - If an URL is given, make sure it doesn't contain query args.
197 *
198 * @since 2.2
199 *
200 * @param string $path A file path or URL.
201 * @param string $format format we are targeting.
202 * @return string
203 */
204 function imagify_path_to_nextgen( $path, string $format ) {
205 switch ( $format ) {
206 case 'webp':
207 $path = $path . '.webp';
208 break;
209 case 'avif':
210 $path = $path . '.avif';
211 break;
212 }
213
214 return $path;
215 }
216
217 /**
218 * Tell if the current user can optimize custom folders.
219 *
220 * @since 1.7
221 * @author Grégory Viguier
222 *
223 * @return bool
224 */
225 function imagify_can_optimize_custom_folders() {
226 static $can;
227
228 if ( isset( $can ) ) {
229 return $can;
230 }
231
232 // Check if the DB tables are ready.
233 if ( ! Imagify_Folders_DB::get_instance()->can_operate() || ! Imagify_Files_DB::get_instance()->can_operate() ) {
234 $can = false;
235 return $can;
236 }
237
238 // Check for user capacity.
239 $can = imagify_get_context( 'custom-folders' )->current_user_can( 'optimize' );
240
241 return $can;
242 }
243
244 /**
245 * Simple helper to get some external URLs, like to the documentation.
246 *
247 * @since 1.6.12
248 * @author Grégory Viguier
249 *
250 * @param string $target What we want.
251 * @param array $query_args An array of query arguments.
252 * @return string The URL.
253 */
254 function imagify_get_external_url( $target, $query_args = [] ) {
255 $site_url = IMAGIFY_SITE_DOMAIN . '/';
256 $app_url = IMAGIFY_APP_DOMAIN . '/#/';
257
258 switch ( $target ) {
259 case 'plugin':
260 /* translators: Plugin URI of the plugin/theme */
261 $url = __( 'https://wordpress.org/plugins/imagify/', 'imagify' );
262 break;
263
264 case 'rate':
265 $url = 'https://wordpress.org/support/view/plugin-reviews/imagify?rate=5#postform';
266 break;
267
268 case 'contact':
269 $lang = imagify_get_current_lang_in( 'fr' );
270 $paths = [
271 'en' => 'contact',
272 'fr' => 'fr/contact',
273 ];
274
275 $url = $site_url . $paths[ $lang ] . '/';
276 break;
277
278 case 'documentation':
279 $url = $site_url . 'documentation/';
280 break;
281
282 case 'documentation-imagick-gd':
283 $url = $site_url . 'documentation/solve-imagemagick-gd-required/';
284 break;
285
286 case 'register':
287 $partner = imagify_get_partner();
288
289 if ( $partner ) {
290 $query_args['partner'] = $partner;
291 }
292
293 $url = $app_url . 'register';
294 break;
295
296 case 'subscription':
297 $url = $app_url . 'subscription';
298 break;
299
300 case 'get-api-key':
301 $url = $app_url . 'api';
302 break;
303
304 case 'payment':
305 // Don't remove the trailing slash.
306 $url = $app_url . 'plugin/';
307 break;
308
309 default:
310 return '';
311 }
312
313 if ( $query_args ) {
314 $url = add_query_arg( $query_args, $url );
315 }
316
317 return $url;
318 }
319
320 /**
321 * Get the current lang ('fr', 'en', 'de'...), limited to a given list.
322 *
323 * @since 1.6.14
324 * @author Grégory Viguier
325 *
326 * @param array $langs An array of langs, like array( 'de', 'es', 'fr', 'it' ).
327 * @return string The current lang. Default is 'en'.
328 */
329 function imagify_get_current_lang_in( $langs ) {
330 static $locale;
331
332 if ( ! isset( $locale ) ) {
333 $locale = imagify_get_locale();
334 $locale = explode( '_', strtolower( $locale . '_' ) ); // Trailing underscore is to make sure $locale[1] is set.
335 }
336
337 foreach ( (array) $langs as $lang ) {
338 if ( $lang === $locale[0] || $lang === $locale[1] ) {
339 return $lang;
340 }
341 }
342
343 return 'en';
344 }
345
346 /**
347 * Get the current locale.
348 *
349 * @since 1.6.14
350 * @author Grégory Viguier
351 *
352 * @return string The current locale.
353 */
354 function imagify_get_locale() {
355 $locale = function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale();
356 /**
357 * Filter the locale used by Imagify.
358 *
359 * @since 1.6.14
360 * @author Grégory Viguier
361 *
362 * @param string $locale The current locale.
363 */
364 return apply_filters( 'imagify_locale', $locale );
365 }
366
367 /**
368 * Get the label corresponding to the given optimization label.
369 *
370 * @since 1.7
371 * @author Grégory Viguier
372 *
373 * @param int|bool $level Optimization level (between 0 and 2). False if no level.
374 * @param string $format Format to display the label. Use %ICON% for the icon and %s for the label.
375 * @return string The label.
376 */
377 function imagify_get_optimization_level_label( $level, $format = '%s' ) {
378 if ( ! is_numeric( $level ) ) {
379 return '';
380 }
381
382 if ( strpos( $format, '%ICON%' ) !== false ) {
383 $icon = '<svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><g fill="#40B1D0" fill-rule="evenodd">';
384
385 switch ( $level ) {
386 case 2:
387 case 1:
388 $icon .= '<polygon points="11.6054688 11.6054688 8.7890625 11.6054688 8.7890625 0.39453125 11.6054688 0.39453125"/><polygon points="7.39453125 11.6054688 4.60546875 11.6054688 4.60546875 3.89453125 7.39453125 3.89453125"/><polygon points="3.2109375 11.6054688 0.39453125 11.6054688 0.39453125 6 3.2109375 6"/>';
389 break;
390 case 0:
391 $icon .= '<polygon fill="#CCD1D6" points="11.6054688 11.6054688 8.7890625 11.6054688 8.7890625 0.39453125 11.6054688 0.39453125"/><polygon fill="#CCD1D6" points="7.39453125 11.6054688 4.60546875 11.6054688 4.60546875 3.89453125 7.39453125 3.89453125"/><polygon points="3.2109375 11.6054688 0.39453125 11.6054688 0.39453125 6 3.2109375 6"/>';
392 }
393
394 $icon .= '</g></svg>';
395
396 $format = str_replace( '%ICON%', $icon, $format );
397 }
398
399 switch ( $level ) {
400 case 2:
401 case 1:
402 return sprintf( $format, __( 'Smart', 'imagify' ) );
403 case 0:
404 return sprintf( $format, __( 'Lossless', 'imagify' ) );
405 }
406
407 return '';
408 }
409
410 /**
411 * `array_merge()` + `array_intersect_key()`.
412 *
413 * @since 1.7
414 * @author Grégory Viguier
415 *
416 * @param array $values The array we're interested in.
417 * @param array $default_values The array we use as boundaries.
418 * @return array
419 */
420 function imagify_merge_intersect( $values, $default_values ) {
421 $values = array_merge( $default_values, (array) $values );
422 return array_intersect_key( $values, $default_values );
423 }
424
425 /**
426 * Returns true.
427 * Useful for returning true to filters easily.
428 * Similar to WP's __return_true() function, it allows to remove it from a filter without removing another one added by another plugin.
429 *
430 * @since 1.9
431 * @author Grégory Viguier
432 *
433 * @return bool True.
434 */
435 function imagify_return_true() {
436 return true;
437 }
438
439 /**
440 * Returns false.
441 * Useful for returning false to filters easily.
442 * Similar to WP's __return_false() function, it allows to remove it from a filter without removing another one added by another plugin.
443 *
444 * @since 1.9
445 * @author Grégory Viguier
446 *
447 * @return bool False.
448 */
449 function imagify_return_false() {
450 return false;
451 }
452
453 /**
454 * Marks a class as deprecated and informs when it has been used.
455 * Similar to _deprecated_constructor(), but with different strings.
456 * The current behavior is to trigger a user error if `WP_DEBUG` is true.
457 *
458 * @since 1.9
459 * @author Grégory Viguier
460 *
461 * @param string $class_name The class containing the deprecated constructor.
462 * @param string $version The version of WordPress that deprecated the function.
463 * @param string $replacement Optional. The function that should have been called. Default null.
464 * @param string $parent_class Optional. The parent class calling the deprecated constructor. Default empty string.
465 */
466 function imagify_deprecated_class( $class_name, $version, $replacement = null, $parent_class = '' ) {
467
468 /**
469 * Fires when a deprecated class is called.
470 *
471 * @since 1.9
472 * @author Grégory Viguier
473 *
474 * @param string $class_name The class containing the deprecated constructor.
475 * @param string $version The version of WordPress that deprecated the function.
476 * @param string $replacement Optional. The function that should have been called.
477 * @param string $parent_class The parent class calling the deprecated constructor.
478 */
479 do_action( 'imagify_deprecated_class_run', $class_name, $version, $replacement, $parent_class );
480
481 if ( ! WP_DEBUG ) {
482 return;
483 }
484
485 /**
486 * Filters whether to trigger an error for deprecated classes.
487 *
488 * `WP_DEBUG` must be true in addition to the filter evaluating to true.
489 *
490 * @since 1.9
491 * @author Grégory Viguier
492 *
493 * @param bool $trigger Whether to trigger the error for deprecated classes. Default true.
494 */
495 if ( ! apply_filters( 'imagify_deprecated_class_trigger_error', true ) ) {
496 return;
497 }
498
499 if ( function_exists( '__' ) ) {
500 if ( ! empty( $parent_class ) ) {
501 /**
502 * With parent class.
503 */
504 if ( ! empty( $replacement ) ) {
505 /**
506 * With replacement.
507 */
508 call_user_func(
509 'trigger_error',
510 sprintf(
511 /* translators: 1: PHP class name, 2: PHP parent class name, 3: version number, 4: replacement class name. */
512 __( 'The called class %1$s extending %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.', 'imagify' ),
513 '<code>' . $class_name . '</code>',
514 '<code>' . $parent_class . '</code>',
515 '<strong>' . $version . '</strong>',
516 '<code>' . $replacement . '</code>'
517 )
518 );
519 return;
520 }
521
522 /**
523 * Without replacement.
524 */
525 call_user_func(
526 'trigger_error',
527 sprintf(
528 /* translators: 1: PHP class name, 2: PHP parent class name, 3: version number. */
529 __( 'The called class %1$s extending %2$s is <strong>deprecated</strong> since version %3$s!', 'imagify' ),
530 '<code>' . $class_name . '</code>',
531 '<code>' . $parent_class . '</code>',
532 '<strong>' . $version . '</strong>'
533 )
534 );
535 return;
536 }
537
538 /**
539 * Without parent class.
540 */
541 if ( ! empty( $replacement ) ) {
542 /**
543 * With replacement.
544 */
545 call_user_func(
546 'trigger_error',
547 sprintf(
548 /* translators: 1: PHP class name, 2: version number, 3: replacement class name. */
549 __( 'The called class %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', 'imagify' ),
550 '<code>' . $class_name . '</code>',
551 '<strong>' . $version . '</strong>',
552 '<code>' . $replacement . '</code>'
553 )
554 );
555 return;
556 }
557
558 /**
559 * Without replacement.
560 */
561 call_user_func(
562 'trigger_error',
563 sprintf(
564 /* translators: 1: PHP class name, 2: version number. */
565 __( 'The called class %1$s is <strong>deprecated</strong> since version %2$s!', 'imagify' ),
566 '<code>' . $class_name . '</code>',
567 '<strong>' . $version . '</strong>'
568 )
569 );
570 return;
571 }
572
573 if ( ! empty( $parent_class ) ) {
574 /**
575 * With parent class.
576 */
577 if ( ! empty( $replacement ) ) {
578 /**
579 * With replacement.
580 */
581 call_user_func(
582 'trigger_error',
583 sprintf(
584 'The called class %1$s extending %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.',
585 '<code>' . $class_name . '</code>',
586 '<code>' . $parent_class . '</code>',
587 '<strong>' . $version . '</strong>',
588 '<code>' . $replacement . '</code>'
589 )
590 );
591 return;
592 }
593
594 /**
595 * Without replacement.
596 */
597 call_user_func(
598 'trigger_error',
599 sprintf(
600 'The called class %1$s extending %2$s is <strong>deprecated</strong> since version %3$s!',
601 '<code>' . $class_name . '</code>',
602 '<code>' . $parent_class . '</code>',
603 '<strong>' . $version . '</strong>'
604 )
605 );
606 return;
607 }
608
609 /**
610 * Without parent class.
611 */
612 if ( ! empty( $replacement ) ) {
613 /**
614 * With replacement.
615 */
616 call_user_func(
617 'trigger_error',
618 sprintf(
619 'The called class %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
620 '<code>' . $class_name . '</code>',
621 '<strong>' . $version . '</strong>',
622 '<code>' . $replacement . '</code>'
623 )
624 );
625 return;
626 }
627
628 /**
629 * Without replacement.
630 */
631 call_user_func(
632 'trigger_error',
633 sprintf(
634 'The called class %1$s is <strong>deprecated</strong> since version %2$s!',
635 '<code>' . $class_name . '</code>',
636 '<strong>' . $version . '</strong>'
637 )
638 );
639 }
640