PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / trunk
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF vtrunk
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
← All changes | inc/classes/class-imagify-settings.php +280 -260 1.10 → trunk View file →
@@ -1,6 +1,7 @@
1 1 <?php
2 -defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
2 +use Imagify\Notices\Notices;
3 +use Imagify\Traits\InstanceGetterTrait;
3 4
4 5 /**
5 6 * Class that handles the plugin settings.
6 7 *
@@ -6,14 +7,15 @@
6 7 *
7 8 * @since 1.7
8 9 */
9 10 class Imagify_Settings {
11 + use InstanceGetterTrait;
10 12
11 13 /**
12 14 * Class version.
13 15 *
14 16 * @since 1.7
15 - * @var string
17 + * @var string
16 18 */
17 19 const VERSION = '1.0.1';
18 20
19 21 /**
@@ -19,9 +21,9 @@
19 21 /**
20 22 * The settings group.
21 23 *
22 24 * @since 1.7
23 - * @var string
25 + * @var string
24 26 */
25 27 protected $settings_group;
26 28
27 29 /**
@@ -27,9 +29,9 @@
27 29 /**
28 30 * The option name.
29 31 *
30 32 * @since 1.7
31 - * @var string
33 + * @var string
32 34 */
33 35 protected $option_name;
34 36
35 37 /**
@@ -35,27 +37,16 @@
35 37 /**
36 38 * The options instance.
37 39 *
38 40 * @since 1.7
39 - * @var object
41 + * @var object
40 42 */
41 43 protected $options;
42 44
43 45 /**
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 46 * The constructor.
54 47 *
55 - * @since 1.7
56 - * @author Grégory Viguier
57 - * @access protected
48 + * @since 1.7
58 49 */
59 50 protected function __construct() {
60 51 $this->options = Imagify_Options::get_instance();
61 52 $this->option_name = $this->options->get_option_name();
@@ -62,48 +53,24 @@
62 53 $this->settings_group = IMAGIFY_SLUG;
63 54 }
64 55
65 56 /**
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 57 * Launch the hooks.
83 58 *
84 - * @since 1.7
85 - * @author Grégory Viguier
86 - * @access public
59 + * @since 1.7
87 60 */
88 61 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' ) );
62 + add_filter( 'sanitize_option_' . $this->option_name, [ $this, 'populate_values_on_save' ], 5 );
63 + add_action( 'admin_init', [ $this, 'register' ] );
64 + add_filter( 'option_page_capability_' . $this->settings_group, [ $this, 'get_capability' ] );
92 65
93 66 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' ) );
67 + add_filter( 'pre_update_site_option_' . $this->option_name, [ $this, 'maybe_set_redirection' ], 10, 2 );
68 + add_action( 'update_site_option_' . $this->option_name, [ $this, 'after_save_network_options' ], 10, 3 );
69 + add_action( 'admin_post_update', [ $this, 'update_site_option_on_network' ] );
103 70 } 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 );
71 + add_filter( 'pre_update_option_' . $this->option_name, [ $this, 'maybe_set_redirection' ], 10, 2 );
72 + add_action( 'update_option_' . $this->option_name, [ $this, 'after_save_options' ], 10, 2 );
106 73 }
107 74 }
108 75
109 76
@@ -113,12 +80,10 @@
113 80
114 81 /**
115 82 * Get the name of the settings group.
116 83 *
117 - * @since 1.7
84 + * @since 1.7
118 85 * @return string
119 - * @author Grégory Viguier
120 - * @access public
121 86 */
122 87 public function get_settings_group() {
123 88 return $this->settings_group;
124 89 }
@@ -125,12 +90,10 @@
125 90
126 91 /**
127 92 * Get the URL to use as form action.
128 93 *
129 - * @since 1.7
94 + * @since 1.7
130 95 * @return string
131 - * @author Grégory Viguier
132 - * @access public
133 96 */
134 97 public function get_form_action() {
135 98 return imagify_is_active_for_network() ? admin_url( 'admin-post.php' ) : admin_url( 'options.php' );
136 99 }
@@ -137,18 +100,19 @@
137 100
138 101 /**
139 102 * Tell if we're submitting the settings form.
140 103 *
141 - * @since 1.7
104 + * @since 1.7
142 105 * @return bool
143 - * @author Grégory Viguier
144 - * @access public
145 106 */
146 107 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';
108 + if ( ! isset( $_POST['option_page'], $_POST['action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
109 + return false;
110 + }
111 +
112 + return sanitize_text_field( wp_unslash( $_POST['option_page'] ) ) === $this->settings_group && sanitize_text_field( wp_unslash( $_POST['action'] ) ) === 'update'; // phpcs:ignore WordPress.Security.NonceVerification.Missing
148 113 }
149 114
150 -
151 115 /** ----------------------------------------------------------------------------------------- */
152 116 /** ON FORM SUBMIT ========================================================================== */
153 117 /** ----------------------------------------------------------------------------------------- */
154 118
@@ -155,15 +119,13 @@
155 119 /**
156 120 * On form submit, handle some specific values.
157 121 * This must be hooked before Imagify_Options::sanitize_and_validate_on_update().
158 122 *
159 - * @since 1.7
123 + * @since 1.7
160 124 *
161 125 * @param array $values The option values.
162 126 *
163 127 * @return array
164 - * @author Grégory Viguier
165 - * @access public
166 128 */
167 129 public function populate_values_on_save( $values ) {
168 130 if ( ! $this->is_form_submit() ) {
169 131 return $values;
@@ -168,9 +130,9 @@
168 130 if ( ! $this->is_form_submit() ) {
169 131 return $values;
170 132 }
171 133
172 - $values = is_array( $values ) ? $values : array();
134 + $values = is_array( $values ) ? $values : [];
173 135
174 136 /**
175 137 * Disabled thumbnail sizes.
176 138 */
@@ -183,13 +145,11 @@
183 145
184 146 /**
185 147 * Filter settings when saved via the settings page.
186 148 *
187 - * @since 1.9
149 + * @since 1.9
188 150 *
189 151 * @param array $values The option values.
190 - *
191 - * @author Grégory Viguier
192 152 */
193 153 $values = apply_filters( 'imagify_settings_on_save', $values );
194 154
195 155 return (array) $values;
@@ -197,21 +157,19 @@
197 157
198 158 /**
199 159 * On form submit, handle disallowed thumbnail sizes.
200 160 *
201 - * @since 1.7
202 - * @access protected
161 + * @since 1.7
203 162 *
204 163 * @param array $values The option values.
205 164 *
206 165 * @return array
207 - * @author Grégory Viguier
208 166 */
209 167 protected function populate_disallowed_sizes( $values ) {
210 - $values['disallowed-sizes'] = array();
168 + $values['disallowed-sizes'] = [];
211 169
212 170 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();
171 + $checked = ! empty( $values['disallowed-sizes-checked'] ) && is_array( $values['disallowed-sizes-checked'] ) ? array_flip( $values['disallowed-sizes-checked'] ) : [];
214 172
215 173 if ( ! empty( $values['disallowed-sizes-reversed'] ) ) {
216 174 foreach ( $values['disallowed-sizes-reversed'] as $size_key ) {
217 175 if ( ! isset( $checked[ $size_key ] ) ) {
@@ -229,15 +187,13 @@
229 187
230 188 /**
231 189 * On form submit, handle the custom folders.
232 190 *
233 - * @since 1.7
234 - * @access protected
191 + * @since 1.7
235 192 *
236 193 * @param array $values The option values.
237 194 *
238 195 * @return array
239 - * @author Grégory Viguier
240 196 */
241 197 protected function populate_custom_folders( $values ) {
242 198 if ( ! imagify_can_optimize_custom_folders() ) {
243 199 // The databases are not ready or the user has not the permission.
@@ -313,11 +269,9 @@
313 269
314 270 /**
315 271 * Add Imagify' settings to the settings API whitelist.
316 272 *
317 - * @since 1.7
318 - * @author Grégory Viguier
319 - * @access public
273 + * @since 1.7
320 274 */
321 275 public function register() {
322 276 register_setting( $this->settings_group, $this->option_name );
323 277 }
@@ -324,11 +278,9 @@
324 278
325 279 /**
326 280 * Set the user capacity needed to save Imagify's main options from the settings page.
327 281 *
328 - * @since 1.7
329 - * @author Grégory Viguier
330 - * @access public
282 + * @since 1.7
331 283 */
332 284 public function get_capability() {
333 285 return imagify_get_context( 'wp' )->get_capacity( 'manage' );
334 286 }
@@ -342,12 +294,10 @@
342 294 * @param mixed $value The new, unserialized option value.
343 295 * @param mixed $old_value The old option value.
344 296 *
345 297 * @return mixed The option value.
346 - * @author Grégory Viguier
347 - * @access public
348 298 */
349 - public function maybe_set_redirection( $value, $old_value ) {
299 + public function maybe_set_redirection( $value, $old_value ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
350 300 if ( isset( $_POST['submit-goto-bulk'] ) ) { // WPCS: CSRF ok.
351 301 $_REQUEST['_wp_http_referer'] = esc_url_raw( get_admin_url( get_current_blog_id(), 'upload.php?page=imagify-bulk-optimization' ) );
352 302 }
353 303
@@ -361,11 +311,8 @@
361 311 *
362 312 * @param string $option Name of the network option.
363 313 * @param mixed $value Current value of the network option.
364 314 * @param mixed $old_value Old value of the network option.
365 - *
366 - * @author Grégory Viguier
367 - * @access public
368 315 */
369 316 public function after_save_network_options( $option, $value, $old_value ) {
370 317 $this->after_save_options( $old_value, $value );
371 318 }
@@ -376,11 +323,8 @@
376 323 * @since 1.7
377 324 *
378 325 * @param mixed $old_value The old option value.
379 326 * @param mixed $value The new option value.
380 - *
381 - * @author Grégory Viguier
382 - * @access public
383 327 */
384 328 public function after_save_options( $old_value, $value ) {
385 329 $old_key = isset( $old_value['api_key'] ) ? $old_value['api_key'] : '';
386 330 $new_key = isset( $value['api_key'] ) ? $value['api_key'] : '';
@@ -388,13 +332,15 @@
388 332 if ( $old_key === $new_key ) {
389 333 return;
390 334 }
391 335
336 + delete_transient( 'imagify_user_cache' );
337 +
392 338 // Handle API key validation cache and notices.
393 339 if ( Imagify_Requirements::is_api_key_valid( true ) ) {
394 - Imagify_Notices::dismiss_notice( 'wrong-api-key' );
340 + Notices::dismiss_notice( 'wrong-api-key' );
395 341 } else {
396 - Imagify_Notices::renew_notice( 'wrong-api-key' );
342 + Notices::renew_notice( 'wrong-api-key' );
397 343 }
398 344 }
399 345
400 346 /**
@@ -452,9 +398,9 @@
452 398 $option = trim( $option );
453 399 $value = null;
454 400
455 401 if ( isset( $_POST[ $option ] ) ) {
456 - $value = wp_unslash( $_POST[ $option ] );
402 + $value = wp_unslash( $_POST[ $option ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
457 403 if ( ! is_array( $value ) ) {
458 404 $value = trim( $value );
459 405 }
460 406 $value = wp_unslash( $value );
@@ -464,11 +410,25 @@
464 410 }
465 411 }
466 412
467 413 /**
414 + * `options.php` is what registers the "Settings saved." notice and stores it in the
415 + * `settings_errors` transient. We bypass it on network installations, so do it here.
416 + *
417 + * The guard mirrors core: a success notice is only queued when nothing else has
418 + * reported a problem during this request, so a real error from another plugin is
419 + * never contradicted by a "Settings saved." underneath it.
420 + */
421 + if ( ! count( get_settings_errors() ) ) {
422 + add_settings_error( 'general', 'settings_updated', __( 'Settings saved.' ), 'success' );
423 + }
424 +
425 + set_transient( 'settings_errors', get_settings_errors(), 30 );
426 +
427 + /**
468 428 * Redirect back to the settings page that was submitted.
469 429 */
470 - imagify_maybe_redirect( false, array( 'settings-updated' => 'true' ) );
430 + imagify_maybe_redirect( false, [ 'settings-updated' => 'true' ] );
471 431 }
472 432
473 433
474 434 /** ----------------------------------------------------------------------------------------- */
@@ -485,21 +445,21 @@
485 445 * {label} string The label to use.
486 446 * {info} string Text to display in an "Info box" after the field. A 'aria-describedby' attribute will automatically be created.
487 447 * {attributes} array A list of HTML attributes, as 'attribute' => 'value'.
488 448 * {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 449 */
493 450 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 );
451 + $args = array_merge(
452 + [
453 + 'option_name' => '',
454 + 'label' => '',
455 + 'info' => '',
456 + 'attributes' => [],
457 + // To not use the plugin settings: use an integer.
458 + 'current_value' => null,
459 + ],
460 + $args
461 + );
502 462
503 463 if ( ! $args['option_name'] || ! $args['label'] ) {
504 464 return;
505 465 }
@@ -524,31 +484,21 @@
524 484
525 485 $attributes = array_merge( $attributes, $args['attributes'] );
526 486 $args['attributes'] = self::build_attributes( $attributes );
527 487 ?>
528 - <input type="checkbox" value="1" <?php
529 - checked( $current_value, 1 );
530 - ?><?php
531 - echo $args['attributes'];
532 -?> />
488 + <input type="checkbox" value="1" <?php checked( $current_value, 1 ); ?> <?php echo $args['attributes']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> />
533 489 <!-- 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>
490 + <label for="<?php echo esc_attr( $attributes['id'] ); ?>" onclick="">
491 + <?php self::print_text( $args['label'] ); ?>
492 + </label>
539 493 <?php
540 494 if ( ! $args['info'] ) {
541 495 return;
542 496 }
543 497 ?>
544 - <span id="<?php
545 - echo $attributes['aria-describedby'];
546 - ?>" class="imagify-info">
498 + <span id="<?php echo esc_attr( $attributes['aria-describedby'] ); ?>" class="imagify-info">
547 499 <span class="dashicons dashicons-info"></span>
548 - <?php
549 - echo $args['info'];
550 - ?>
500 + <?php self::print_text( $args['info'] ); ?>
551 501 </span>
552 502 <?php
553 503 }
554 504
@@ -564,23 +514,23 @@
564 514 * {disabled_values} array Values to be disabled. Values are the array keys.
565 515 * {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 516 * {attributes} array A list of HTML attributes, as 'attribute' => 'value'.
567 517 * {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 518 */
572 519 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 );
520 + $args = array_merge(
521 + [
522 + 'option_name' => '',
523 + 'legend' => '',
524 + 'values' => [],
525 + 'disabled_values' => [],
526 + 'reverse_check' => false,
527 + 'attributes' => [],
528 + // To not use the plugin settings: use an array.
529 + 'current_values' => false,
530 + ],
531 + $args
532 + );
583 533
584 534 if ( ! $args['option_name'] || ! $args['values'] ) {
585 535 return;
586 536 }
@@ -593,13 +543,16 @@
593 543 $current_values = $this->options->get( $args['option_name'] );
594 544 }
595 545
596 546 $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'] );
547 + $attributes = array_merge(
548 + [
549 + 'name' => $this->option_name . '[' . $args['option_name'] . ( $args['reverse_check'] ? '-checked' : '' ) . '][]',
550 + 'id' => 'imagify_' . $option_name_class . '_%s',
551 + 'class' => 'imagify-row-check',
552 + ],
553 + $args['attributes']
554 + );
602 555
603 556 $id_attribute = $attributes['id'];
604 557 unset( $attributes['id'] );
605 558 $args['attributes'] = self::build_attributes( $attributes );
@@ -608,17 +561,15 @@
608 561 $nb_of_values = count( $args['values'] );
609 562 $display_check_all = $nb_of_values > 3;
610 563 $nb_of_checked = 0;
611 564 ?>
612 - <fieldset class="imagify-check-group<?php
613 - echo $nb_of_values > 5 ? ' imagify-is-scrollable' : '';
614 - ?>">
565 + <fieldset class="imagify-check-group <?php echo $nb_of_values > 5 ? ' imagify-is-scrollable' : ''; ?>">
615 566 <?php
616 567 if ( $args['legend'] ) {
617 568 ?>
618 - <legend class="screen-reader-text"><?php
619 - echo $args['legend'];
620 - ?></legend>
569 + <legend class="screen-reader-text">
570 + <?php self::print_text( $args['legend'] ); ?>
571 + </legend>
621 572 <?php
622 573 }
623 574
624 575 foreach ( $args['values'] as $value => $label ) {
@@ -633,28 +584,16 @@
633 584
634 585 $nb_of_checked = $checked ? $nb_of_checked + 1 : $nb_of_checked;
635 586
636 587 if ( $args['reverse_check'] ) {
637 - echo '<input type="hidden" name="' . $this->option_name . '[' . $args['option_name'] . '-reversed][]" value="' . esc_attr( $value ) . '" />';
588 + echo '<input type="hidden" name="' . esc_attr( $this->option_name . '[' . $args['option_name'] ) . '-reversed][]" value="' . esc_attr( $value ) . '" />';
638 589 }
639 590 ?>
640 591 <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>
592 + <input type="checkbox" value="<?php echo esc_attr( $value ); ?>" id="<?php echo esc_attr( $input_id ); ?>" <?php echo $args['attributes']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> <?php checked( $checked ); ?> <?php disabled( $disabled ); ?> />
593 + <label for="<?php echo esc_attr( $input_id ); ?>" onclick="">
594 + <?php self::print_text( $label ); ?>
595 + </label>
657 596 </p>
658 597 <?php
659 598 }
660 599 ?>
@@ -667,21 +606,21 @@
667 606 $all_checked = ! array_diff_key( $args['values'], $current_values );
668 607 }
669 608 ?>
670 609 <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>
610 + <button type="button" class="imagify-link-like imagify-select-all <?php echo $all_checked ? ' imagify-is-inactive" aria-disabled="true' : ''; ?>" data-action="select">
611 + <?php
612 + esc_html_e( 'Select All', 'imagify' );
613 + ?>
614 + </button>
676 615
677 616 <span class="imagify-pipe"></span>
678 617
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>
618 + <button type="button" class="imagify-link-like imagify-select-all <?php echo $nb_of_checked ? '' : ' imagify-is-inactive" aria-disabled="true'; ?> " data-action="unselect">
619 + <?php
620 + esc_html_e( 'Unselect All', 'imagify' );
621 + ?>
622 + </button>
684 623 </p>
685 624 <?php
686 625 }
687 626 }
@@ -689,9 +628,8 @@
689 628 /**
690 629 * Display a radio list group.
691 630 *
692 631 * @since 1.9
693 - * @access public
694 632 *
695 633 * @param array $args {
696 634 * Arguments.
697 635 *
@@ -701,20 +639,22 @@
701 639 * @type array $values List of values to display, in the form of 'value' => 'Label'. Mandatory.
702 640 * @type array $attributes A list of HTML attributes, as 'attribute' => 'value'.
703 641 * @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 642 * }
705 - * @author Grégory Viguier
706 643 */
707 644 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 );
645 + $args = array_merge(
646 + [
647 + 'option_name' => '',
648 + 'legend' => '',
649 + 'info' => '',
650 + 'values' => [],
651 + 'attributes' => [],
652 + // To not use the plugin settings: use an array.
653 + 'current_value' => false,
654 + ],
655 + $args
656 + );
717 657
718 658 if ( ! $args['option_name'] || ! $args['values'] ) {
719 659 return;
720 660 }
@@ -727,13 +667,16 @@
727 667 $current_value = $this->options->get( $args['option_name'] );
728 668 }
729 669
730 670 $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'] );
671 + $attributes = array_merge(
672 + [
673 + 'name' => $this->option_name . '[' . $args['option_name'] . ']',
674 + 'id' => 'imagify_' . $option_name_class . '_%s',
675 + 'class' => 'imagify-row-radio',
676 + ],
677 + $args['attributes']
678 + );
736 679
737 680 $id_attribute = $attributes['id'];
738 681 unset( $attributes['id'] );
739 682 $args['attributes'] = self::build_attributes( $attributes );
@@ -741,31 +684,23 @@
741 684 <fieldset class="imagify-radio-group">
742 685 <?php
743 686 if ( $args['legend'] ) {
744 687 ?>
745 - <legend class="screen-reader-text"><?php
746 - echo $args['legend'];
747 - ?></legend>
688 + <legend class="screen-reader-text">
748 689 <?php
690 + self::print_text( $args['legend'] );
691 + ?>
692 + </legend>
693 + <?php
749 694 }
750 695
751 696 foreach ( $args['values'] as $value => $label ) {
752 697 $input_id = sprintf( $id_attribute, sanitize_html_class( $value ) );
753 698 ?>
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>
699 + <input type="radio" value="<?php echo esc_attr( $value ); ?>" id="<?php echo esc_attr( $input_id ); ?>" <?php echo $args['attributes']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> <?php checked( $current_value, $value ); ?> />
700 + <label for="<?php echo esc_attr( $input_id ); ?>" onclick="">
701 + <?php self::print_text( $label ); ?>
702 + </label>
768 703 <br/>
769 704 <?php
770 705 }
771 706 ?>
@@ -774,16 +709,79 @@
774 709 if ( ! $args['info'] ) {
775 710 return;
776 711 }
777 712 ?>
778 - <span id="<?php
779 - echo $attributes['aria-describedby'];
780 - ?>" class="imagify-info">
713 + <span id="<?php echo esc_attr( $attributes['aria-describedby'] ); ?>" class="imagify-info">
781 714 <span class="dashicons dashicons-info"></span>
715 + <?php self::print_text( $args['info'] ); ?>
716 + </span>
717 + <?php
718 + }
719 +
720 + /**
721 + * Display styled radio list group.
722 + *
723 + * @param array $args Arguments:
724 + * {option_name} string The option name. E.g. 'disallowed-sizes'. Mandatory.
725 + * {values} array List of values to display, in the form of 'value' => 'Label'. Mandatory.
726 + * {attributes} array A list of HTML attributes, as 'attribute' => 'value'.
727 + * {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.
728 + *
729 + * @return void
730 + */
731 + public function field_inline_radio_list( $args ) {
732 + $args = array_merge(
733 + [
734 + 'option_name' => '',
735 + 'values' => [],
736 + 'info' => '',
737 + 'attributes' => [],
738 + 'current_value' => false,
739 + ],
740 + $args
741 + );
742 +
743 + if ( ! $args['option_name'] || ! $args['values'] ) {
744 + return;
745 + }
746 +
747 + if ( is_numeric( $args['current_value'] ) || is_string( $args['current_value'] ) ) {
748 + $current_value = $args['current_value'];
749 + } else {
750 + $current_value = $this->options->get( $args['option_name'] );
751 + }
752 +
753 + $option_name_class = sanitize_html_class( $args['option_name'] );
754 + $attributes = array_merge(
755 + [
756 + 'name' => $this->option_name . '[' . $args['option_name'] . ']',
757 + 'id' => 'imagify_' . $option_name_class . '_%s',
758 + 'class' => 'imagify-row-radio',
759 + ],
760 + $args['attributes']
761 + );
762 +
763 + $id_attribute = $attributes['id'];
764 + unset( $attributes['id'] );
765 + $args['attributes'] = self::build_attributes( $attributes );
766 + ?>
767 + <div class="imagify-setting-optim-level">
768 + <p class="imagify-inline-options imagify-inline-options-<?php echo esc_attr( $args['info_class'] ); ?>">
782 769 <?php
783 - echo $args['info'];
770 + foreach ( $args['values'] as $value => $label ) {
771 + $input_id = sprintf( $id_attribute, sanitize_html_class( $value ) );
772 + ?>
773 + <input type="radio" value="<?php echo esc_attr( $value ); ?>" id="<?php echo esc_attr( $input_id ); ?>"<?php echo $args['attributes']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> <?php checked( $current_value, $value ); ?> />
774 + <label for="<?php echo esc_attr( $input_id ); ?>" onclick=""><?php self::print_text( $label ); ?></label>
775 + <?php
776 + }
784 777 ?>
785 - </span>
778 + </p>
779 + <span id="<?php echo esc_attr( $attributes['aria-describedby'] ); ?>" class="imagify-<?php echo esc_attr( $args['info_class'] ); ?>">
780 + <span class="dashicons dashicons-info"></span>
781 + <?php self::print_text( $args['info'] ); ?>
782 + </span>
783 + </div>
786 784 <?php
787 785 }
788 786
789 787 /**
@@ -788,10 +786,9 @@
788 786
789 787 /**
790 788 * Display a text box.
791 789 *
792 - * @since 1.9.3
793 - * @access public
790 + * @since 1.9.3
794 791 *
795 792 * @param array $args Arguments:
796 793 * {option_name} string The option name. E.g. 'disallowed-sizes'. Mandatory.
797 794 * {label} string The label to use.
@@ -797,20 +794,21 @@
797 794 * {label} string The label to use.
798 795 * {info} string Text to display in an "Info box" after the field. A 'aria-describedby' attribute will automatically be created.
799 796 * {attributes} array A list of HTML attributes, as 'attribute' => 'value'.
800 797 * {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 798 */
804 799 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 );
800 + $args = array_merge(
801 + [
802 + 'option_name' => '',
803 + 'label' => '',
804 + 'info' => '',
805 + 'attributes' => [],
806 + // To not use the plugin settings.
807 + 'current_value' => null,
808 + ],
809 + $args
810 + );
813 811
814 812 if ( ! $args['option_name'] || ! $args['label'] ) {
815 813 return;
816 814 }
@@ -836,30 +834,20 @@
836 834 $attributes = array_merge( $attributes, $args['attributes'] );
837 835 $args['attributes'] = self::build_attributes( $attributes );
838 836 ?>
839 837 <!-- 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 -?> />
838 + <label for="<?php echo esc_attr( $attributes['id'] ); ?>" onclick="">
839 + <?php self::print_text( $args['label'] ); ?>
840 + </label>
841 + <input type="text" value="<?php echo esc_attr( $current_value ); ?>" <?php echo $args['attributes']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> />
850 842 <?php
851 843 if ( ! $args['info'] ) {
852 844 return;
853 845 }
854 846 ?>
855 - <span id="<?php
856 - echo $attributes['aria-describedby'];
857 - ?>" class="imagify-info">
847 + <span id="<?php echo esc_attr( $attributes['aria-describedby'] ); ?>" class="imagify-info">
858 848 <span class="dashicons dashicons-info"></span>
859 - <?php
860 - echo $args['info'];
861 - ?>
849 + <?php self::print_text( $args['info'] ); ?>
862 850 </span>
863 851 <?php
864 852 }
865 853
@@ -865,25 +853,25 @@
865 853
866 854 /**
867 855 * Display a simple hidden input.
868 856 *
869 - * @since 1.9.3
870 - * @access public
857 + * @since 1.9.3
871 858 *
872 859 * @param array $args Arguments:
873 860 * {option_name} string The option name. E.g. 'disallowed-sizes'. Mandatory.
874 861 * {attributes} array A list of HTML attributes, as 'attribute' => 'value'.
875 862 * {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 863 */
879 864 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 );
865 + $args = array_merge(
866 + [
867 + 'option_name' => '',
868 + 'attributes' => [],
869 + // To not use the plugin settings.
870 + 'current_value' => null,
871 + ],
872 + $args
873 + );
886 874
887 875 if ( ! $args['option_name'] ) {
888 876 return;
889 877 }
@@ -904,13 +892,9 @@
904 892
905 893 $attributes = array_merge( $attributes, $args['attributes'] );
906 894 $args['attributes'] = self::build_attributes( $attributes );
907 895 ?>
908 - <input type="hidden" value="<?php
909 - echo esc_attr( $current_value );
910 - ?>"<?php
911 - echo $args['attributes'];
912 -?> />
896 + <input type="hidden" value="<?php echo esc_attr( $current_value ); ?>" <?php echo $args['attributes']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> />
913 897 <?php
914 898 }
915 899
916 900
@@ -922,10 +906,8 @@
922 906 * Get the thumbnail sizes.
923 907 *
924 908 * @since 1.7
925 909 * @return array A list of thumbnail sizes in the form of 'medium' => 'medium - 300 Ă— 300'.
926 - * @author Grégory Viguier
927 - * @access public
928 910 */
929 911 public static function get_thumbnail_sizes() {
930 912 static $sizes;
931 913
@@ -949,15 +931,13 @@
949 931
950 932 /**
951 933 * Create HTML attributes from an array.
952 934 *
953 - * @since 1.7
954 - * @access public
935 + * @since 1.7
955 936 *
956 937 * @param array $attributes A list of attribute pairs.
957 938 *
958 - * @return string HTML attributes.
959 - * @author Grégory Viguier
939 + * @return string HTML attributes.
960 940 */
961 941 public static function build_attributes( $attributes ) {
962 942 if ( ! $attributes || ! is_array( $attributes ) ) {
963 943 return '';
@@ -969,6 +949,46 @@
969 949 $out .= ' ' . $attribute . '="' . esc_attr( $value ) . '"';
970 950 }
971 951
972 952 return $out;
953 + }
954 +
955 + /**
956 + * Print a human-readable field string, keeping the inline formatting it carries.
957 + *
958 + * The labels, legends and info messages of the field renderers are written as
959 + * markup by their callers: a `<br>` separating two sentences, a `<code>`
960 + * naming a filter, an `<em>` marking the recommended choice, a link to the
961 + * documentation. Passing them through `esc_html()` printed those tags to the
962 + * user instead of applying them, so they go through a narrow allow-list of
963 + * inline tags.
964 + *
965 + * Entities survive the allow-list, so a label built with `&times;` or
966 + * `&lt;picture&gt;` renders the character it stands for instead of being
967 + * escaped a second time.
968 + *
969 + * The string is already translated by the time it arrives, which is exactly
970 + * why the filtering happens here: whatever a translation introduces is held
971 + * to the same allow-list as the original string.
972 + *
973 + * @since 2.3.3
974 + *
975 + * @param string $text The string to print.
976 + * @return void
977 + */
978 + public static function print_text( $text ) {
979 + echo wp_kses(
980 + $text,
981 + [
982 + 'a' => [
983 + 'href' => true,
984 + 'rel' => true,
985 + 'target' => true,
986 + ],
987 + 'br' => [],
988 + 'code' => [],
989 + 'em' => [],
990 + 'strong' => [],
991 + ]
992 + );
973 993 }
974 994 }