PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 1.9.13
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v1.9.13
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 / classes / class-imagify-views.php

class-imagify-views.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 1.9.13, at inc/classes/class-imagify-views.php

745 lines 19.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
3
4 /**
5 * Class that handles templates and menus.
6 *
7 * @since 1.7
8 * @author Grégory Viguier
9 */
10 class Imagify_Views {
11
12 /**
13 * Class version.
14 *
15 * @var string
16 * @since 1.7
17 */
18 const VERSION = '1.1';
19
20 /**
21 * Slug used for the settings page URL.
22 *
23 * @var string
24 * @since 1.7
25 * @access protected
26 */
27 protected $slug_settings;
28
29 /**
30 * Slug used for the bulk optimization page URL.
31 *
32 * @var string
33 * @since 1.7
34 * @access protected
35 */
36 protected $slug_bulk;
37
38 /**
39 * Slug used for the "custom folders" page URL.
40 *
41 * @var string
42 * @since 1.7
43 * @access protected
44 */
45 protected $slug_files;
46
47 /**
48 * A list of JS templates to print at the end of the page.
49 *
50 * @var array
51 * @since 1.9
52 * @access protected
53 */
54 protected $templates_in_footer = [];
55
56 /**
57 * Stores the "custom folders" files list instance.
58 *
59 * @var object Imagify_Files_List_Table
60 * @since 1.7
61 * @access protected
62 */
63 protected $list_table;
64
65 /**
66 * Filesystem object.
67 *
68 * @var object Imagify_Filesystem
69 * @since 1.7.1
70 * @access protected
71 * @author Grégory Viguier
72 */
73 protected $filesystem;
74
75 /**
76 * The single instance of the class.
77 *
78 * @var object
79 * @since 1.7
80 * @access protected
81 */
82 protected static $_instance;
83
84
85 /** ----------------------------------------------------------------------------------------- */
86 /** INSTANCE/INIT =========================================================================== */
87 /** ----------------------------------------------------------------------------------------- */
88
89 /**
90 * The constructor.
91 *
92 * @since 1.7
93 * @author Grégory Viguier
94 * @access protected
95 */
96 protected function __construct() {
97 $this->slug_settings = IMAGIFY_SLUG;
98 $this->slug_bulk = IMAGIFY_SLUG . '-bulk-optimization';
99 $this->slug_files = IMAGIFY_SLUG . '-files';
100 $this->filesystem = Imagify_Filesystem::get_instance();
101 }
102
103 /**
104 * Get the main Instance.
105 *
106 * @since 1.7
107 * @author Grégory Viguier
108 * @access public
109 *
110 * @return object Main instance.
111 */
112 public static function get_instance() {
113 if ( ! isset( self::$_instance ) ) {
114 self::$_instance = new self();
115 }
116
117 return self::$_instance;
118 }
119
120 /**
121 * Launch the hooks.
122 *
123 * @since 1.7
124 * @author Grégory Viguier
125 * @access public
126 */
127 public function init() {
128 // Menu items.
129 add_action( 'admin_menu', [ $this, 'add_site_menus' ] );
130
131 if ( imagify_is_active_for_network() ) {
132 add_action( 'network_admin_menu', [ $this, 'add_network_menus' ] );
133 }
134
135 // Action links in plugins list.
136 $basename = plugin_basename( IMAGIFY_FILE );
137 add_filter( 'plugin_action_links_' . $basename, [ $this, 'plugin_action_links' ] );
138 add_filter( 'network_admin_plugin_action_links_' . $basename, [ $this, 'plugin_action_links' ] );
139
140 // Save the "per page" option value from the files list screen.
141 add_filter( 'set-screen-option', [ 'Imagify_Files_List_Table', 'save_screen_options' ], 10, 3 );
142
143 // JS templates in footer.
144 add_action( 'admin_print_footer_scripts', [ $this, 'print_js_templates' ] );
145 }
146
147
148 /** ----------------------------------------------------------------------------------------- */
149 /** MENU ITEMS ============================================================================== */
150 /** ----------------------------------------------------------------------------------------- */
151
152 /**
153 * Add sub-menus for all sites.
154 *
155 * @since 1.7
156 * @author Grégory Viguier
157 * @access public
158 */
159 public function add_site_menus() {
160 $wp_context = imagify_get_context( 'wp' );
161
162 // Sub-menu item: bulk optimization.
163 add_media_page( __( 'Bulk Optimization', 'imagify' ), __( 'Bulk Optimization', 'imagify' ), $wp_context->get_capacity( 'bulk-optimize' ), $this->get_bulk_page_slug(), [ $this, 'display_bulk_page' ] );
164
165 if ( imagify_is_active_for_network() ) {
166 return;
167 }
168
169 /**
170 * Plugin is not network activated.
171 */
172 if ( imagify_can_optimize_custom_folders() ) {
173 // Sub-menu item: custom folders list.
174 $cf_context = imagify_get_context( 'custom-folders' );
175 $screen_id = add_media_page( __( 'Other Media optimized by Imagify', 'imagify' ), __( 'Other Media', 'imagify' ), $cf_context->get_capacity( 'optimize' ), $this->get_files_page_slug(), [ $this, 'display_files_list' ] );
176
177 if ( $screen_id ) {
178 // Load the data for this page.
179 add_action( 'load-' . $screen_id, [ $this, 'load_files_list' ] );
180 }
181 }
182
183 // Sub-menu item: settings.
184 add_options_page( 'Imagify', 'Imagify', $wp_context->get_capacity( 'manage' ), $this->get_settings_page_slug(), [ $this, 'display_settings_page' ] );
185 }
186
187 /**
188 * Add menu and sub-menus in the network admin when Imagify is network-activated.
189 *
190 * @since 1.7
191 * @author Grégory Viguier
192 * @access public
193 */
194 public function add_network_menus() {
195 global $submenu;
196
197 $wp_context = imagify_get_context( 'wp' );
198
199 if ( ! imagify_can_optimize_custom_folders() ) {
200 // Main item: settings (edge case).
201 add_menu_page( 'Imagify', 'Imagify', $wp_context->get_capacity( 'manage' ), $this->get_settings_page_slug(), array( $this, 'display_settings_page' ) );
202 return;
203 }
204
205 $cf_context = imagify_get_context( 'custom-folders' );
206
207 // Main item: bulk optimization (custom folders).
208 add_menu_page( __( 'Bulk Optimization', 'imagify' ), 'Imagify', $cf_context->current_user_can( 'bulk-optimize' ), $this->get_bulk_page_slug(), array( $this, 'display_bulk_page' ) );
209
210 // Sub-menu item: custom folders list.
211 $screen_id = add_submenu_page( $this->get_bulk_page_slug(), __( 'Other Media optimized by Imagify', 'imagify' ), __( 'Other Media', 'imagify' ), $cf_context->current_user_can( 'bulk-optimize' ), $this->get_files_page_slug(), array( $this, 'display_files_list' ) );
212
213 // Sub-menu item: settings.
214 add_submenu_page( $this->get_bulk_page_slug(), 'Imagify', __( 'Settings', 'imagify' ), $wp_context->get_capacity( 'manage' ), $this->get_settings_page_slug(), array( $this, 'display_settings_page' ) );
215
216 // Change the sub-menu label.
217 if ( ! empty( $submenu[ $this->get_bulk_page_slug() ] ) ) {
218 $submenu[ $this->get_bulk_page_slug() ][0][0] = __( 'Bulk Optimization', 'imagify' ); // WPCS: override ok.
219 }
220
221 if ( $screen_id ) {
222 // On the "Other Media optimized by Imagify" page, load the data.
223 add_action( 'load-' . $screen_id, array( $this, 'load_files_list' ) );
224 }
225 }
226
227
228 /** ----------------------------------------------------------------------------------------- */
229 /** PLUGIN ACTION LINKS ===================================================================== */
230 /** ----------------------------------------------------------------------------------------- */
231
232 /**
233 * Add links to the plugin row in the plugins list.
234 *
235 * @since 1.7
236 * @author Grégory Viguier
237 * @access public
238 *
239 * @param array $actions An array of action links.
240 * @return array
241 */
242 public function plugin_action_links( $actions ) {
243 array_unshift( $actions, sprintf( '<a href="%s" target="_blank">%s</a>', esc_url( imagify_get_external_url( 'documentation' ) ), __( 'Documentation', 'imagify' ) ) );
244 array_unshift( $actions, sprintf( '<a href="%s">%s</a>', esc_url( get_imagify_admin_url( 'bulk-optimization' ) ), __( 'Bulk Optimization', 'imagify' ) ) );
245 array_unshift( $actions, sprintf( '<a href="%s">%s</a>', esc_url( get_imagify_admin_url() ), __( 'Settings', 'imagify' ) ) );
246 return $actions;
247 }
248
249
250 /** ----------------------------------------------------------------------------------------- */
251 /** MAIN PAGE TEMPLATES ===================================================================== */
252 /** ----------------------------------------------------------------------------------------- */
253
254 /**
255 * The main settings page.
256 *
257 * @since 1.7
258 * @author Grégory Viguier
259 * @access public
260 */
261 public function display_settings_page() {
262 $this->print_template( 'page-settings' );
263 }
264
265 /**
266 * The bulk optimization page.
267 *
268 * @since 1.7
269 * @author Grégory Viguier
270 * @access public
271 */
272 public function display_bulk_page() {
273 $types = array();
274 $data = array(
275 // Limits.
276 'unoptimized_attachment_limit' => 0,
277 // What to optimize.
278 'icon' => 'images-alt2',
279 'title' => __( 'Optimize your media files', 'imagify' ),
280 'groups' => array(),
281 );
282
283 if ( imagify_is_screen( 'bulk' ) ) {
284 if ( ! is_network_admin() ) {
285 /**
286 * Library: in each site.
287 */
288 $types['library|wp'] = 1;
289 }
290
291 if ( imagify_can_optimize_custom_folders() && ( imagify_is_active_for_network() && is_network_admin() || ! imagify_is_active_for_network() ) ) {
292 /**
293 * Custom folders: in network admin only if network activated, in each site otherwise.
294 */
295 $types['custom-folders|custom-folders'] = 1;
296 }
297 }
298
299 /**
300 * Filter the types to display in the bulk optimization page.
301 *
302 * @since 1.7.1
303 * @author Grégory Viguier
304 *
305 * @param array $types The folder types displayed on the page. If a folder type is "library", the context should be suffixed after a pipe character. They are passed as array keys.
306 */
307 $types = apply_filters( 'imagify_bulk_page_types', $types );
308 $types = array_filter( (array) $types );
309
310 if ( isset( $types['library|wp'] ) ) {
311 // Limits.
312 $data['unoptimized_attachment_limit'] += imagify_get_unoptimized_attachment_limit();
313 // Group.
314 $data['groups']['library'] = array(
315 /**
316 * The group_id corresponds to the file names like 'part-bulk-optimization-results-row-{$group_id}'.
317 * It is also used in get_imagify_localize_script_translations().
318 */
319 'group_id' => 'library',
320 'context' => 'wp',
321 'title' => __( 'Media Library', 'imagify' ),
322 /* translators: 1 is the opening of a link, 2 is the closing of this link. */
323 'footer' => sprintf( __( 'You can also re-optimize your media files from your %1$sMedia Library%2$s screen.', 'imagify' ), '<a href="' . esc_url( admin_url( 'upload.php' ) ) . '">', '</a>' ),
324 );
325 }
326
327 if ( isset( $types['custom-folders|custom-folders'] ) ) {
328 if ( ! Imagify_Folders_DB::get_instance()->has_items() ) {
329 // New Feature!
330 $data['no-custom-folders'] = true;
331 } elseif ( Imagify_Folders_DB::get_instance()->has_active_folders() ) {
332 // Group.
333 $data['groups']['custom-folders'] = array(
334 'group_id' => 'custom-folders',
335 'context' => 'custom-folders',
336 'title' => __( 'Custom folders', 'imagify' ),
337 /* translators: 1 is the opening of a link, 2 is the closing of this link. */
338 'footer' => sprintf( __( 'You can re-optimize your media files more finely directly in the %1$smedia management%2$s.', 'imagify' ), '<a href="' . esc_url( get_imagify_admin_url( 'files-list' ) ) . '">', '</a>' ),
339 );
340 }
341 }
342
343 // Add generic stats.
344 $data = array_merge( $data, imagify_get_bulk_stats( $types, array(
345 'fullset' => true,
346 ) ) );
347
348 /**
349 * Filter the data to use on the bulk optimization page.
350 *
351 * @since 1.7
352 * @since 1.7.1 Added the $types parameter.
353 * @author Grégory Viguier
354 *
355 * @param array $data The data to use.
356 * @param array $types The folder types displayed on the page. They are passed as array keys.
357 */
358 $data = apply_filters( 'imagify_bulk_page_data', $data, $types );
359
360 $this->print_template( 'page-bulk', $data );
361 }
362
363 /**
364 * The page displaying the "custom folders" files.
365 *
366 * @since 1.7
367 * @author Grégory Viguier
368 * @access public
369 */
370 public function display_files_list() {
371 $this->print_template( 'page-files-list' );
372 }
373
374 /**
375 * Initiate the "custom folders" list table data.
376 *
377 * @since 1.7
378 * @author Grégory Viguier
379 * @access public
380 */
381 public function load_files_list() {
382 // Instantiate the list.
383 $this->list_table = new Imagify_Files_List_Table( array(
384 'screen' => 'imagify-files',
385 ) );
386
387 // Query the Items.
388 $this->list_table->prepare_items();
389 }
390
391
392 /** ----------------------------------------------------------------------------------------- */
393 /** GETTERS ================================================================================= */
394 /** ----------------------------------------------------------------------------------------- */
395
396 /**
397 * Get the settings page slug.
398 *
399 * @since 1.7
400 * @author Grégory Viguier
401 * @access public
402 *
403 * @return string
404 */
405 public function get_settings_page_slug() {
406 return $this->slug_settings;
407 }
408
409 /**
410 * Get the bulk optimization page slug.
411 *
412 * @since 1.7
413 * @author Grégory Viguier
414 * @access public
415 *
416 * @return string
417 */
418 public function get_bulk_page_slug() {
419 return $this->slug_bulk;
420 }
421
422 /**
423 * Get the "custom folders" files page slug.
424 *
425 * @since 1.7
426 * @author Grégory Viguier
427 * @access public
428 *
429 * @return string
430 */
431 public function get_files_page_slug() {
432 return $this->slug_files;
433 }
434
435
436 /** ----------------------------------------------------------------------------------------- */
437 /** PAGE TESTS ============================================================================== */
438 /** ----------------------------------------------------------------------------------------- */
439
440 /**
441 * Tell if we’re displaying the settings page.
442 *
443 * @since 1.9
444 * @author Grégory Viguier
445 * @access public
446 *
447 * @return bool
448 */
449 public function is_settings_page() {
450 global $pagenow;
451
452 $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
453
454 if ( $this->get_settings_page_slug() !== $page ) {
455 return false;
456 }
457
458 if ( imagify_is_active_for_network() ) {
459 return 'admin.php' === $pagenow;
460 }
461
462 return 'options-general.php' === $pagenow;
463 }
464
465 /**
466 * Tell if we’re displaying the bulk optimization page.
467 *
468 * @since 1.9
469 * @author Grégory Viguier
470 * @access public
471 *
472 * @return bool
473 */
474 public function is_bulk_page() {
475 global $pagenow;
476
477 $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
478
479 return 'upload.php' === $pagenow && $this->get_bulk_page_slug() === $page;
480 }
481
482 /**
483 * Tell if we’re displaying the custom files list page.
484 *
485 * @since 1.9
486 * @author Grégory Viguier
487 * @access public
488 *
489 * @return bool
490 */
491 public function is_files_page() {
492 global $pagenow;
493
494 $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
495
496 return 'upload.php' === $pagenow && $this->get_files_page_slug() === $page;
497 }
498
499 /**
500 * Tell if we’re displaying the WP media library page.
501 *
502 * @since 1.9
503 * @author Grégory Viguier
504 * @access public
505 *
506 * @return bool
507 */
508 public function is_wp_library_page() {
509 global $pagenow;
510
511 $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
512
513 return 'upload.php' === $pagenow && ! $page;
514 }
515
516 /**
517 * Tell if we’re displaying a media page.
518 *
519 * @since 1.9
520 * @author Grégory Viguier
521 * @access public
522 *
523 * @return bool
524 */
525 public function is_media_page() {
526 global $pagenow, $typenow;
527
528 return 'post.php' === $pagenow && 'attachment' === $typenow;
529 }
530
531
532 /** ----------------------------------------------------------------------------------------- */
533 /** QUOTA =================================================================================== */
534 /** ----------------------------------------------------------------------------------------- */
535
536 /**
537 * Get the remaining quota in percent.
538 *
539 * @since 1.8.1
540 * @author Grégory Viguier
541 * @access public
542 *
543 * @return int
544 */
545 public function get_quota_percent() {
546 static $quota;
547
548 if ( isset( $quota ) ) {
549 return $quota;
550 }
551
552 $user = new Imagify_User();
553 $quota = $user->get_percent_unconsumed_quota();
554
555 return $quota;
556 }
557
558 /**
559 * Get the HTML class used for the quota (to change the color when out of quota for example).
560 *
561 * @since 1.8.1
562 * @author Grégory Viguier
563 * @access public
564 *
565 * @return string
566 */
567 public function get_quota_class() {
568 static $class;
569
570 if ( isset( $class ) ) {
571 return $class;
572 }
573
574 $quota = $this->get_quota_percent();
575 $class = 'imagify-bar-';
576
577 if ( $quota <= 20 ) {
578 $class .= 'negative';
579 } elseif ( $quota <= 50 ) {
580 $class .= 'neutral';
581 } else {
582 $class .= 'positive';
583 }
584
585 return $class;
586 }
587
588 /**
589 * Get the HTML tag used for the quota (the weather-like icon).
590 *
591 * @since 1.8.1
592 * @author Grégory Viguier
593 * @access public
594 *
595 * @return string
596 */
597 public function get_quota_icon() {
598 static $icon;
599
600 if ( isset( $icon ) ) {
601 return $icon;
602 }
603
604 $quota = $this->get_quota_percent();
605
606 if ( $quota <= 20 ) {
607 $icon = '<img src="' . IMAGIFY_ASSETS_IMG_URL . 'stormy.svg" width="64" height="63" alt="" />';
608 } elseif ( $quota <= 50 ) {
609 $icon = '<img src="' . IMAGIFY_ASSETS_IMG_URL . 'cloudy-sun.svg" width="63" height="64" alt="" />';
610 } else {
611 $icon = '<img src="' . IMAGIFY_ASSETS_IMG_URL . 'sun.svg" width="63" height="64" alt="" />';
612 }
613
614 return $icon;
615 }
616
617
618 /** ----------------------------------------------------------------------------------------- */
619 /** GENERIC TEMPLATE TOOLS ================================================================== */
620 /** ----------------------------------------------------------------------------------------- */
621
622 /**
623 * Get a template contents.
624 *
625 * @since 1.7
626 * @author Grégory Viguier
627 * @access public
628 *
629 * @param string $template The template name.
630 * @param mixed $data Some data to pass to the template.
631 * @return string|bool The page contents. False if the template doesn't exist.
632 */
633 public function get_template( $template, $data = array() ) {
634 $path = str_replace( '_', '-', $template );
635 $path = IMAGIFY_PATH . 'views/' . $template . '.php';
636
637 if ( ! $this->filesystem->exists( $path ) ) {
638 return false;
639 }
640
641 ob_start();
642 include $path;
643 $contents = ob_get_clean();
644
645 return trim( (string) $contents );
646 }
647
648 /**
649 * Print a template.
650 *
651 * @since 1.7
652 * @author Grégory Viguier
653 * @access public
654 *
655 * @param string $template The template name.
656 * @param mixed $data Some data to pass to the template.
657 */
658 public function print_template( $template, $data = array() ) {
659 echo $this->get_template( $template, $data );
660 }
661
662 /**
663 * Add a template to the list of JS templates to print at the end of the page.
664 *
665 * @since 1.7
666 * @author Grégory Viguier
667 * @access public
668 *
669 * @param string $template The template name.
670 */
671 public function print_js_template_in_footer( $template ) {
672 if ( isset( $this->templates_in_footer[ $template ] ) ) {
673 return;
674 }
675
676 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
677 return;
678 }
679
680 switch ( $template ) {
681 case 'button/processing':
682 $data = [ 'label' => '{{ data.label }}' ];
683 break;
684 default:
685 $data = [];
686 }
687
688 $this->templates_in_footer[ $template ] = $data;
689 }
690
691 /**
692 * Print the JS templates that have been added to the "queue".
693 *
694 * @since 1.9
695 * @author Grégory Viguier
696 * @access public
697 */
698 public function print_js_templates() {
699 if ( ! $this->templates_in_footer ) {
700 return;
701 }
702
703 foreach ( $this->templates_in_footer as $template => $data ) {
704 $template_id = str_replace( [ '/', '_' ], '-', $template );
705
706 echo '<script type="text/html" id="tmpl-imagify-' . $template_id . '">';
707 $this->print_template( $template, $data );
708 echo '</script>';
709 }
710 }
711
712
713 /** ----------------------------------------------------------------------------------------- */
714 /** TOOLS =================================================================================== */
715 /** ----------------------------------------------------------------------------------------- */
716
717 /**
718 * Create HTML attributes from an array.
719 *
720 * @since 1.9
721 * @access public
722 * @author Grégory Viguier
723 *
724 * @param array $attributes A list of attribute pairs.
725 * @return string HTML attributes.
726 */
727 public function build_attributes( $attributes ) {
728 if ( ! $attributes || ! is_array( $attributes ) ) {
729 return '';
730 }
731
732 $out = '';
733
734 foreach ( $attributes as $attribute => $value ) {
735 if ( '' === $value ) {
736 continue;
737 }
738
739 $out .= ' ' . $attribute . '="' . esc_attr( $value ) . '"';
740 }
741
742 return $out;
743 }
744 }
745