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-settings.php

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

975 lines 28.1 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 the plugin settings.
6 *
7 * @since 1.7
8 */
9 class Imagify_Settings {
10
11 /**
12 * Class version.
13 *
14 * @since 1.7
15 * @var string
16 */
17 const VERSION = '1.0.1';
18
19 /**
20 * The settings group.
21 *
22 * @since 1.7
23 * @var string
24 */
25 protected $settings_group;
26
27 /**
28 * The option name.
29 *
30 * @since 1.7
31 * @var string
32 */
33 protected $option_name;
34
35 /**
36 * The options instance.
37 *
38 * @since 1.7
39 * @var object
40 */
41 protected $options;
42
43 /**
44 * The single instance of the class.
45 *
46 * @since 1.7
47 * @access protected
48 * @var object
49 */
50 protected static $_instance;
51
52 /**
53 * The constructor.
54 *
55 * @since 1.7
56 * @author Grégory Viguier
57 * @access protected
58 */
59 protected function __construct() {
60 $this->options = Imagify_Options::get_instance();
61 $this->option_name = $this->options->get_option_name();
62 $this->settings_group = IMAGIFY_SLUG;
63 }
64
65 /**
66 * Get the main Instance.
67 *
68 * @since 1.7
69 * @return object Main instance.
70 * @author Grégory Viguier
71 * @access public
72 */
73 public static function get_instance() {
74 if ( ! isset( self::$_instance ) ) {
75 self::$_instance = new self();
76 }
77
78 return self::$_instance;
79 }
80
81 /**
82 * Launch the hooks.
83 *
84 * @since 1.7
85 * @author Grégory Viguier
86 * @access public
87 */
88 public function init() {
89 add_filter( 'sanitize_option_' . $this->option_name, array( $this, 'populate_values_on_save' ), 5 );
90 add_action( 'admin_init', array( $this, 'register' ) );
91 add_filter( 'option_page_capability_' . $this->settings_group, array( $this, 'get_capability' ) );
92
93 if ( imagify_is_active_for_network() ) {
94 add_filter( 'pre_update_site_option_' . $this->option_name, array(
95 $this,
96 'maybe_set_redirection',
97 ), 10, 2 );
98 add_action( 'update_site_option_' . $this->option_name, array(
99 $this,
100 'after_save_network_options',
101 ), 10, 3 );
102 add_action( 'admin_post_update', array( $this, 'update_site_option_on_network' ) );
103 } else {
104 add_filter( 'pre_update_option_' . $this->option_name, array( $this, 'maybe_set_redirection' ), 10, 2 );
105 add_action( 'update_option_' . $this->option_name, array( $this, 'after_save_options' ), 10, 2 );
106 }
107 }
108
109
110 /** ----------------------------------------------------------------------------------------- */
111 /** VARIOUS HELPERS ========================================================================= */
112 /** ----------------------------------------------------------------------------------------- */
113
114 /**
115 * Get the name of the settings group.
116 *
117 * @since 1.7
118 * @return string
119 * @author Grégory Viguier
120 * @access public
121 */
122 public function get_settings_group() {
123 return $this->settings_group;
124 }
125
126 /**
127 * Get the URL to use as form action.
128 *
129 * @since 1.7
130 * @return string
131 * @author Grégory Viguier
132 * @access public
133 */
134 public function get_form_action() {
135 return imagify_is_active_for_network() ? admin_url( 'admin-post.php' ) : admin_url( 'options.php' );
136 }
137
138 /**
139 * Tell if we're submitting the settings form.
140 *
141 * @since 1.7
142 * @return bool
143 * @author Grégory Viguier
144 * @access public
145 */
146 public function is_form_submit() {
147 return filter_input( INPUT_POST, 'option_page', FILTER_SANITIZE_STRING ) === $this->settings_group && filter_input( INPUT_POST, 'action', FILTER_SANITIZE_STRING ) === 'update';
148 }
149
150
151 /** ----------------------------------------------------------------------------------------- */
152 /** ON FORM SUBMIT ========================================================================== */
153 /** ----------------------------------------------------------------------------------------- */
154
155 /**
156 * On form submit, handle some specific values.
157 * This must be hooked before Imagify_Options::sanitize_and_validate_on_update().
158 *
159 * @since 1.7
160 *
161 * @param array $values The option values.
162 *
163 * @return array
164 * @author Grégory Viguier
165 * @access public
166 */
167 public function populate_values_on_save( $values ) {
168 if ( ! $this->is_form_submit() ) {
169 return $values;
170 }
171
172 $values = is_array( $values ) ? $values : array();
173
174 /**
175 * Disabled thumbnail sizes.
176 */
177 $values = $this->populate_disallowed_sizes( $values );
178
179 /**
180 * Custom folders.
181 */
182 $values = $this->populate_custom_folders( $values );
183
184 /**
185 * Filter settings when saved via the settings page.
186 *
187 * @since 1.9
188 *
189 * @param array $values The option values.
190 *
191 * @author Grégory Viguier
192 */
193 $values = apply_filters( 'imagify_settings_on_save', $values );
194
195 return (array) $values;
196 }
197
198 /**
199 * On form submit, handle disallowed thumbnail sizes.
200 *
201 * @since 1.7
202 * @access protected
203 *
204 * @param array $values The option values.
205 *
206 * @return array
207 * @author Grégory Viguier
208 */
209 protected function populate_disallowed_sizes( $values ) {
210 $values['disallowed-sizes'] = array();
211
212 if ( isset( $values['disallowed-sizes-reversed'] ) && is_array( $values['disallowed-sizes-reversed'] ) ) {
213 $checked = ! empty( $values['disallowed-sizes-checked'] ) && is_array( $values['disallowed-sizes-checked'] ) ? array_flip( $values['disallowed-sizes-checked'] ) : array();
214
215 if ( ! empty( $values['disallowed-sizes-reversed'] ) ) {
216 foreach ( $values['disallowed-sizes-reversed'] as $size_key ) {
217 if ( ! isset( $checked[ $size_key ] ) ) {
218 // The checkbox is not checked: the size is disabled.
219 $values['disallowed-sizes'][ $size_key ] = 1;
220 }
221 }
222 }
223 }
224
225 unset( $values['disallowed-sizes-reversed'], $values['disallowed-sizes-checked'] );
226
227 return $values;
228 }
229
230 /**
231 * On form submit, handle the custom folders.
232 *
233 * @since 1.7
234 * @access protected
235 *
236 * @param array $values The option values.
237 *
238 * @return array
239 * @author Grégory Viguier
240 */
241 protected function populate_custom_folders( $values ) {
242 if ( ! imagify_can_optimize_custom_folders() ) {
243 // The databases are not ready or the user has not the permission.
244 unset( $values['custom_folders'] );
245
246 return $values;
247 }
248
249 if ( ! isset( $values['custom_folders'] ) ) {
250 // No selected folders: set them all inactive.
251 Imagify_Custom_Folders::deactivate_all_folders();
252 // Remove files that are in inactive folders and are not optimized.
253 Imagify_Custom_Folders::remove_unoptimized_files_from_inactive_folders();
254 // Remove empty inactive folders.
255 Imagify_Custom_Folders::remove_empty_inactive_folders();
256
257 return $values;
258 }
259
260 if ( ! is_array( $values['custom_folders'] ) ) {
261 // Invalid value.
262 unset( $values['custom_folders'] );
263
264 return $values;
265 }
266
267 $selected = array_filter( $values['custom_folders'] );
268 unset( $values['custom_folders'] );
269
270 if ( ! $selected ) {
271 // No selected folders: set them all inactive.
272 Imagify_Custom_Folders::deactivate_all_folders();
273 // Remove files that are in inactive folders and are not optimized.
274 Imagify_Custom_Folders::remove_unoptimized_files_from_inactive_folders();
275 // Remove empty inactive folders.
276 Imagify_Custom_Folders::remove_empty_inactive_folders();
277
278 return $values;
279 }
280
281 // Normalize the paths, remove duplicates, and remove sub-paths.
282 $selected = array_map( 'sanitize_text_field', $selected );
283 $selected = array_map( 'wp_normalize_path', $selected );
284 $selected = array_map( 'trailingslashit', $selected );
285 $selected = array_flip( array_flip( $selected ) );
286 $selected = Imagify_Custom_Folders::remove_sub_paths( $selected );
287
288 // Remove the active status from the folders that are not selected.
289 Imagify_Custom_Folders::deactivate_not_selected_folders( $selected );
290
291 // Add the active status to the folders that are selected (and already in the DB).
292 $selected = Imagify_Custom_Folders::activate_selected_folders( $selected );
293
294 // If we still have paths here, they need to be added to the DB with an active status.
295 Imagify_Custom_Folders::insert_folders( $selected );
296
297 // Remove files that are in inactive folders and are not optimized.
298 Imagify_Custom_Folders::remove_unoptimized_files_from_inactive_folders();
299
300 // Reassign files to active folders.
301 Imagify_Custom_Folders::reassign_inactive_files();
302
303 // Remove empty inactive folders.
304 Imagify_Custom_Folders::remove_empty_inactive_folders();
305
306 return $values;
307 }
308
309
310 /** ----------------------------------------------------------------------------------------- */
311 /** SETTINGS API ============================================================================ */
312 /** ----------------------------------------------------------------------------------------- */
313
314 /**
315 * Add Imagify' settings to the settings API whitelist.
316 *
317 * @since 1.7
318 * @author Grégory Viguier
319 * @access public
320 */
321 public function register() {
322 register_setting( $this->settings_group, $this->option_name );
323 }
324
325 /**
326 * Set the user capacity needed to save Imagify's main options from the settings page.
327 *
328 * @since 1.7
329 * @author Grégory Viguier
330 * @access public
331 */
332 public function get_capability() {
333 return imagify_get_context( 'wp' )->get_capacity( 'manage' );
334 }
335
336 /**
337 * If the user clicked the "Save & Go to Bulk Optimizer" button, set a redirection to the bulk optimizer.
338 * We use this hook because it can be triggered even if the option value hasn't changed.
339 *
340 * @since 1.7
341 *
342 * @param mixed $value The new, unserialized option value.
343 * @param mixed $old_value The old option value.
344 *
345 * @return mixed The option value.
346 * @author Grégory Viguier
347 * @access public
348 */
349 public function maybe_set_redirection( $value, $old_value ) {
350 if ( isset( $_POST['submit-goto-bulk'] ) ) { // WPCS: CSRF ok.
351 $_REQUEST['_wp_http_referer'] = esc_url_raw( get_admin_url( get_current_blog_id(), 'upload.php?page=imagify-bulk-optimization' ) );
352 }
353
354 return $value;
355 }
356
357 /**
358 * Used to launch some actions after saving the network options.
359 *
360 * @since 1.7
361 *
362 * @param string $option Name of the network option.
363 * @param mixed $value Current value of the network option.
364 * @param mixed $old_value Old value of the network option.
365 *
366 * @author Grégory Viguier
367 * @access public
368 */
369 public function after_save_network_options( $option, $value, $old_value ) {
370 $this->after_save_options( $old_value, $value );
371 }
372
373 /**
374 * Used to launch some actions after saving the options.
375 *
376 * @since 1.7
377 *
378 * @param mixed $old_value The old option value.
379 * @param mixed $value The new option value.
380 *
381 * @author Grégory Viguier
382 * @access public
383 */
384 public function after_save_options( $old_value, $value ) {
385 $old_key = isset( $old_value['api_key'] ) ? $old_value['api_key'] : '';
386 $new_key = isset( $value['api_key'] ) ? $value['api_key'] : '';
387
388 if ( $old_key === $new_key ) {
389 return;
390 }
391
392 // Handle API key validation cache and notices.
393 if ( Imagify_Requirements::is_api_key_valid( true ) ) {
394 Imagify_Notices::dismiss_notice( 'wrong-api-key' );
395 } else {
396 Imagify_Notices::renew_notice( 'wrong-api-key' );
397 }
398 }
399
400 /**
401 * `options.php` does not handle network options. Let's use `admin-post.php` for multisite installations.
402 *
403 * @since 1.9.11 deprecate 'whitelist_options' filter.
404 * @since 1.7
405 *
406 * @return void
407 */
408 public function update_site_option_on_network() {
409 global $wp_version;
410
411 if ( empty( $_POST['option_page'] ) || $_POST['option_page'] !== $this->settings_group ) { // WPCS: CSRF ok.
412 return;
413 }
414
415 /** This filter is documented in /wp-admin/options.php. */
416 $capability = apply_filters( 'option_page_capability_' . $this->settings_group, 'manage_network_options' );
417
418 if ( ! current_user_can( $capability ) ) {
419 imagify_die();
420
421 return;
422 }
423
424 if ( ! imagify_check_nonce( $this->settings_group . '-options' ) ) {
425 return;
426 }
427
428 if ( version_compare( $wp_version, '5.5', '>=' ) ) {
429 $allowed_options = apply_filters_deprecated(
430 'whitelist_options',
431 [ [] ],
432 '5.5.0',
433 'allowed_options',
434 __( 'Please consider writing more inclusive code.' )
435 );
436 } else {
437 $allowed_options = apply_filters( 'whitelist_options', [] );
438 }
439
440 $allowed_options = apply_filters( 'allowed_options', $allowed_options );
441
442 if ( ! isset( $allowed_options[ $this->settings_group ] ) ) {
443 imagify_die( __( '<strong>ERROR</strong>: options page not found.' ) );
444
445 return;
446 }
447
448 $options = $allowed_options[ $this->settings_group ];
449
450 if ( $options ) {
451 foreach ( $options as $option ) {
452 $option = trim( $option );
453 $value = null;
454
455 if ( isset( $_POST[ $option ] ) ) {
456 $value = wp_unslash( $_POST[ $option ] );
457 if ( ! is_array( $value ) ) {
458 $value = trim( $value );
459 }
460 $value = wp_unslash( $value );
461 }
462
463 update_site_option( $option, $value );
464 }
465 }
466
467 /**
468 * Redirect back to the settings page that was submitted.
469 */
470 imagify_maybe_redirect( false, array( 'settings-updated' => 'true' ) );
471 }
472
473
474 /** ----------------------------------------------------------------------------------------- */
475 /** FIELDS ================================================================================== */
476 /** ----------------------------------------------------------------------------------------- */
477
478 /**
479 * Display a single checkbox.
480 *
481 * @since 1.7
482 *
483 * @param array $args Arguments:
484 * {option_name} string The option name. E.g. 'disallowed-sizes'. Mandatory.
485 * {label} string The label to use.
486 * {info} string Text to display in an "Info box" after the field. A 'aria-describedby' attribute will automatically be created.
487 * {attributes} array A list of HTML attributes, as 'attribute' => 'value'.
488 * {current_value} int|bool USE ONLY WHEN DEALING WITH DATA THAT IS NOT SAVED IN THE PLUGIN OPTIONS. If not provided, the field will automatically get the value from the options.
489 *
490 * @author Grégory Viguier
491 * @access public
492 */
493 public function field_checkbox( $args ) {
494 $args = array_merge( [
495 'option_name' => '',
496 'label' => '',
497 'info' => '',
498 'attributes' => [],
499 // To not use the plugin settings: use an integer.
500 'current_value' => null,
501 ], $args );
502
503 if ( ! $args['option_name'] || ! $args['label'] ) {
504 return;
505 }
506
507 if ( is_numeric( $args['current_value'] ) || is_bool( $args['current_value'] ) ) {
508 // We don't use the plugin settings.
509 $current_value = (int) (bool) $args['current_value'];
510 } else {
511 // This is a normal plugin setting.
512 $current_value = $this->options->get( $args['option_name'] );
513 }
514
515 $option_name_class = sanitize_html_class( $args['option_name'] );
516 $attributes = [
517 'name' => $this->option_name . '[' . $args['option_name'] . ']',
518 'id' => 'imagify_' . $option_name_class,
519 ];
520
521 if ( $args['info'] && empty( $attributes['aria-describedby'] ) ) {
522 $attributes['aria-describedby'] = 'describe-' . $option_name_class;
523 }
524
525 $attributes = array_merge( $attributes, $args['attributes'] );
526 $args['attributes'] = self::build_attributes( $attributes );
527 ?>
528 <input type="checkbox" value="1" <?php
529 checked( $current_value, 1 );
530 ?><?php
531 echo $args['attributes'];
532 ?> />
533 <!-- Empty onclick attribute to make clickable labels on iTruc & Mac -->
534 <label for="<?php
535 echo $attributes['id'];
536 ?>" onclick=""><?php
537 echo $args['label'];
538 ?></label>
539 <?php
540 if ( ! $args['info'] ) {
541 return;
542 }
543 ?>
544 <span id="<?php
545 echo $attributes['aria-describedby'];
546 ?>" class="imagify-info">
547 <span class="dashicons dashicons-info"></span>
548 <?php
549 echo $args['info'];
550 ?>
551 </span>
552 <?php
553 }
554
555 /**
556 * Display a checkbox group.
557 *
558 * @since 1.7
559 *
560 * @param array $args Arguments:
561 * {option_name} string The option name. E.g. 'disallowed-sizes'. Mandatory.
562 * {legend} string Label to use for the <legend> tag.
563 * {values} array List of values to display, in the form of 'value' => 'Label'. Mandatory.
564 * {disabled_values} array Values to be disabled. Values are the array keys.
565 * {reverse_check} bool If true, the values that will be stored in the option are the ones that are unchecked. It requires special treatment when saving (detect what values are unchecked).
566 * {attributes} array A list of HTML attributes, as 'attribute' => 'value'.
567 * {current_values} array USE ONLY WHEN DEALING WITH DATA THAT IS NOT SAVED IN THE PLUGIN OPTIONS. If not provided, the field will automatically get the value from the options.
568 *
569 * @author Grégory Viguier
570 * @access public
571 */
572 public function field_checkbox_list( $args ) {
573 $args = array_merge( [
574 'option_name' => '',
575 'legend' => '',
576 'values' => [],
577 'disabled_values' => [],
578 'reverse_check' => false,
579 'attributes' => [],
580 // To not use the plugin settings: use an array.
581 'current_values' => false,
582 ], $args );
583
584 if ( ! $args['option_name'] || ! $args['values'] ) {
585 return;
586 }
587
588 if ( is_array( $args['current_values'] ) ) {
589 // We don't use the plugin settings.
590 $current_values = $args['current_values'];
591 } else {
592 // This is a normal plugin setting.
593 $current_values = $this->options->get( $args['option_name'] );
594 }
595
596 $option_name_class = sanitize_html_class( $args['option_name'] );
597 $attributes = array_merge( [
598 'name' => $this->option_name . '[' . $args['option_name'] . ( $args['reverse_check'] ? '-checked' : '' ) . '][]',
599 'id' => 'imagify_' . $option_name_class . '_%s',
600 'class' => 'imagify-row-check',
601 ], $args['attributes'] );
602
603 $id_attribute = $attributes['id'];
604 unset( $attributes['id'] );
605 $args['attributes'] = self::build_attributes( $attributes );
606
607 $current_values = array_diff_key( $current_values, $args['disabled_values'] );
608 $nb_of_values = count( $args['values'] );
609 $display_check_all = $nb_of_values > 3;
610 $nb_of_checked = 0;
611 ?>
612 <fieldset class="imagify-check-group<?php
613 echo $nb_of_values > 5 ? ' imagify-is-scrollable' : '';
614 ?>">
615 <?php
616 if ( $args['legend'] ) {
617 ?>
618 <legend class="screen-reader-text"><?php
619 echo $args['legend'];
620 ?></legend>
621 <?php
622 }
623
624 foreach ( $args['values'] as $value => $label ) {
625 $input_id = sprintf( $id_attribute, sanitize_html_class( $value ) );
626 $disabled = isset( $args['disabled_values'][ $value ] );
627
628 if ( $args['reverse_check'] ) {
629 $checked = ! $disabled && ! isset( $current_values[ $value ] );
630 } else {
631 $checked = ! $disabled && isset( $current_values[ $value ] );
632 }
633
634 $nb_of_checked = $checked ? $nb_of_checked + 1 : $nb_of_checked;
635
636 if ( $args['reverse_check'] ) {
637 echo '<input type="hidden" name="' . $this->option_name . '[' . $args['option_name'] . '-reversed][]" value="' . esc_attr( $value ) . '" />';
638 }
639 ?>
640 <p>
641 <input type="checkbox" value="<?php
642 echo esc_attr( $value );
643 ?>" id="<?php
644 echo $input_id;
645 ?>"<?php
646 echo $args['attributes'];
647 ?> <?php
648 checked( $checked );
649 ?> <?php
650 disabled( $disabled );
651 ?>/>
652 <label for="<?php
653 echo $input_id;
654 ?>" onclick=""><?php
655 echo $label;
656 ?></label>
657 </p>
658 <?php
659 }
660 ?>
661 </fieldset>
662 <?php
663 if ( $display_check_all ) {
664 if ( $args['reverse_check'] ) {
665 $all_checked = ! array_intersect_key( $args['values'], $current_values );
666 } else {
667 $all_checked = ! array_diff_key( $args['values'], $current_values );
668 }
669 ?>
670 <p class="hide-if-no-js imagify-select-all-buttons">
671 <button type="button" class="imagify-link-like imagify-select-all<?php
672 echo $all_checked ? ' imagify-is-inactive" aria-disabled="true' : '';
673 ?>" data-action="select"><?php
674 _e( 'Select All', 'imagify' );
675 ?></button>
676
677 <span class="imagify-pipe"></span>
678
679 <button type="button" class="imagify-link-like imagify-select-all<?php
680 echo $nb_of_checked ? '' : ' imagify-is-inactive" aria-disabled="true';
681 ?>" data-action="unselect"><?php
682 _e( 'Unselect All', 'imagify' );
683 ?></button>
684 </p>
685 <?php
686 }
687 }
688
689 /**
690 * Display a radio list group.
691 *
692 * @since 1.9
693 * @access public
694 *
695 * @param array $args {
696 * Arguments.
697 *
698 * @type string $option_name The option name. E.g. 'disallowed-sizes'. Mandatory.
699 * @type string $legend Label to use for the <legend> tag.
700 * @type string $info Text to display in an "Info box" after the field. A 'aria-describedby' attribute will automatically be created.
701 * @type array $values List of values to display, in the form of 'value' => 'Label'. Mandatory.
702 * @type array $attributes A list of HTML attributes, as 'attribute' => 'value'.
703 * @type array $current_value USE ONLY WHEN DEALING WITH DATA THAT IS NOT SAVED IN THE PLUGIN OPTIONS. If not provided, the field will automatically get the value from the options.
704 * }
705 * @author Grégory Viguier
706 */
707 public function field_radio_list( $args ) {
708 $args = array_merge( [
709 'option_name' => '',
710 'legend' => '',
711 'info' => '',
712 'values' => [],
713 'attributes' => [],
714 // To not use the plugin settings: use an array.
715 'current_value' => false,
716 ], $args );
717
718 if ( ! $args['option_name'] || ! $args['values'] ) {
719 return;
720 }
721
722 if ( is_array( $args['current_value'] ) ) {
723 // We don't use the plugin settings.
724 $current_value = $args['current_value'];
725 } else {
726 // This is a normal plugin setting.
727 $current_value = $this->options->get( $args['option_name'] );
728 }
729
730 $option_name_class = sanitize_html_class( $args['option_name'] );
731 $attributes = array_merge( [
732 'name' => $this->option_name . '[' . $args['option_name'] . ']',
733 'id' => 'imagify_' . $option_name_class . '_%s',
734 'class' => 'imagify-row-radio',
735 ], $args['attributes'] );
736
737 $id_attribute = $attributes['id'];
738 unset( $attributes['id'] );
739 $args['attributes'] = self::build_attributes( $attributes );
740 ?>
741 <fieldset class="imagify-radio-group">
742 <?php
743 if ( $args['legend'] ) {
744 ?>
745 <legend class="screen-reader-text"><?php
746 echo $args['legend'];
747 ?></legend>
748 <?php
749 }
750
751 foreach ( $args['values'] as $value => $label ) {
752 $input_id = sprintf( $id_attribute, sanitize_html_class( $value ) );
753 ?>
754 <input type="radio" value="<?php
755 echo esc_attr( $value );
756 ?>" id="<?php
757 echo $input_id;
758 ?>"<?php
759 echo $args['attributes'];
760 ?> <?php
761 checked( $current_value, $value );
762 ?>/>
763 <label for="<?php
764 echo $input_id;
765 ?>" onclick=""><?php
766 echo $label;
767 ?></label>
768 <br/>
769 <?php
770 }
771 ?>
772 </fieldset>
773 <?php
774 if ( ! $args['info'] ) {
775 return;
776 }
777 ?>
778 <span id="<?php
779 echo $attributes['aria-describedby'];
780 ?>" class="imagify-info">
781 <span class="dashicons dashicons-info"></span>
782 <?php
783 echo $args['info'];
784 ?>
785 </span>
786 <?php
787 }
788
789 /**
790 * Display a text box.
791 *
792 * @since 1.9.3
793 * @access public
794 *
795 * @param array $args Arguments:
796 * {option_name} string The option name. E.g. 'disallowed-sizes'. Mandatory.
797 * {label} string The label to use.
798 * {info} string Text to display in an "Info box" after the field. A 'aria-describedby' attribute will automatically be created.
799 * {attributes} array A list of HTML attributes, as 'attribute' => 'value'.
800 * {current_value} int|bool USE ONLY WHEN DEALING WITH DATA THAT IS NOT SAVED IN THE PLUGIN OPTIONS. If not provided, the field will automatically get the value from the options.
801 *
802 * @author Grégory Viguier
803 */
804 public function field_text_box( $args ) {
805 $args = array_merge( [
806 'option_name' => '',
807 'label' => '',
808 'info' => '',
809 'attributes' => [],
810 // To not use the plugin settings.
811 'current_value' => null,
812 ], $args );
813
814 if ( ! $args['option_name'] || ! $args['label'] ) {
815 return;
816 }
817
818 if ( is_numeric( $args['current_value'] ) || is_string( $args['current_value'] ) ) {
819 // We don't use the plugin settings.
820 $current_value = $args['current_value'];
821 } else {
822 // This is a normal plugin setting.
823 $current_value = $this->options->get( $args['option_name'] );
824 }
825
826 $option_name_class = sanitize_html_class( $args['option_name'] );
827 $attributes = [
828 'name' => $this->option_name . '[' . $args['option_name'] . ']',
829 'id' => 'imagify_' . $option_name_class,
830 ];
831
832 if ( $args['info'] && empty( $attributes['aria-describedby'] ) ) {
833 $attributes['aria-describedby'] = 'describe-' . $option_name_class;
834 }
835
836 $attributes = array_merge( $attributes, $args['attributes'] );
837 $args['attributes'] = self::build_attributes( $attributes );
838 ?>
839 <!-- Empty onclick attribute to make clickable labels on iTruc & Mac -->
840 <label for="<?php
841 echo $attributes['id'];
842 ?>" onclick=""><?php
843 echo $args['label'];
844 ?></label>
845 <input type="text" value="<?php
846 echo esc_attr( $current_value );
847 ?>"<?php
848 echo $args['attributes'];
849 ?> />
850 <?php
851 if ( ! $args['info'] ) {
852 return;
853 }
854 ?>
855 <span id="<?php
856 echo $attributes['aria-describedby'];
857 ?>" class="imagify-info">
858 <span class="dashicons dashicons-info"></span>
859 <?php
860 echo $args['info'];
861 ?>
862 </span>
863 <?php
864 }
865
866 /**
867 * Display a simple hidden input.
868 *
869 * @since 1.9.3
870 * @access public
871 *
872 * @param array $args Arguments:
873 * {option_name} string The option name. E.g. 'disallowed-sizes'. Mandatory.
874 * {attributes} array A list of HTML attributes, as 'attribute' => 'value'.
875 * {current_value} int|bool USE ONLY WHEN DEALING WITH DATA THAT IS NOT SAVED IN THE PLUGIN OPTIONS. If not provided, the field will automatically get the value from the options.
876 *
877 * @author Grégory Viguier
878 */
879 public function field_hidden( $args ) {
880 $args = array_merge( [
881 'option_name' => '',
882 'attributes' => [],
883 // To not use the plugin settings.
884 'current_value' => null,
885 ], $args );
886
887 if ( ! $args['option_name'] ) {
888 return;
889 }
890
891 if ( is_numeric( $args['current_value'] ) || is_string( $args['current_value'] ) ) {
892 // We don't use the plugin settings.
893 $current_value = $args['current_value'];
894 } else {
895 // This is a normal plugin setting.
896 $current_value = $this->options->get( $args['option_name'] );
897 }
898
899 $option_name_class = sanitize_html_class( $args['option_name'] );
900 $attributes = [
901 'name' => $this->option_name . '[' . $args['option_name'] . ']',
902 'id' => 'imagify_' . $option_name_class,
903 ];
904
905 $attributes = array_merge( $attributes, $args['attributes'] );
906 $args['attributes'] = self::build_attributes( $attributes );
907 ?>
908 <input type="hidden" value="<?php
909 echo esc_attr( $current_value );
910 ?>"<?php
911 echo $args['attributes'];
912 ?> />
913 <?php
914 }
915
916
917 /** ----------------------------------------------------------------------------------------- */
918 /** FIELD VALUES ============================================================================ */
919 /** ----------------------------------------------------------------------------------------- */
920
921 /**
922 * Get the thumbnail sizes.
923 *
924 * @since 1.7
925 * @return array A list of thumbnail sizes in the form of 'medium' => 'medium - 300 × 300'.
926 * @author Grégory Viguier
927 * @access public
928 */
929 public static function get_thumbnail_sizes() {
930 static $sizes;
931
932 if ( isset( $sizes ) ) {
933 return $sizes;
934 }
935
936 $sizes = get_imagify_thumbnail_sizes();
937
938 foreach ( $sizes as $size_key => $size_data ) {
939 $sizes[ $size_key ] = sprintf( '%s - %d &times; %d', esc_html( stripslashes( $size_data['name'] ) ), $size_data['width'], $size_data['height'] );
940 }
941
942 return $sizes;
943 }
944
945
946 /** ----------------------------------------------------------------------------------------- */
947 /** TOOLS =================================================================================== */
948 /** ----------------------------------------------------------------------------------------- */
949
950 /**
951 * Create HTML attributes from an array.
952 *
953 * @since 1.7
954 * @access public
955 *
956 * @param array $attributes A list of attribute pairs.
957 *
958 * @return string HTML attributes.
959 * @author Grégory Viguier
960 */
961 public static function build_attributes( $attributes ) {
962 if ( ! $attributes || ! is_array( $attributes ) ) {
963 return '';
964 }
965
966 $out = '';
967
968 foreach ( $attributes as $attribute => $value ) {
969 $out .= ' ' . $attribute . '="' . esc_attr( $value ) . '"';
970 }
971
972 return $out;
973 }
974 }
975