PluginProbe
WebberZone Top 10 — Popular Posts / 4.5.2
WebberZone Top 10 — Popular Posts v4.5.2
4.5.2 4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 All 118 releases
← All changes | includes/admin/settings/class-settings-api.php +78 -42 4.4.0 → 4.5.2 View file →
@@ -17,9 +17,9 @@
17 17
18 18 /**
19 19 * Settings API wrapper class
20 20 *
21 - * @version 2.9.0
21 + * @version 3.0.0
22 22 * @since 4.0.0
23 23 */
24 24 class Settings_API {
25 25
@@ -27,9 +27,9 @@
27 27 * Current version number
28 28 *
29 29 * @var string
30 30 */
31 - public const VERSION = '2.11.0';
31 + public const VERSION = '3.0.0';
32 32
33 33 /**
34 34 * Settings Key.
35 35 *
@@ -265,8 +265,11 @@
265 265 'reset_button_confirm' => 'Do you really want to reset all these settings to their default values?',
266 266 'button_label' => 'Choose File',
267 267 'previous_saved' => 'Previously saved',
268 268 'repeater_new_item' => 'New Item',
269 + 'repeater_move_up' => 'Move item up',
270 + 'repeater_move_down' => 'Move item down',
271 + 'repeater_remove_item' => 'Remove item',
269 272 'required_label' => 'Required',
270 273 'tom_select_no_results' => 'No results found for "%s"',
271 274 'search_placeholder' => 'Search settings',
272 275 'search_no_results' => 'No settings found. Try a different search term.',
@@ -542,9 +545,9 @@
542 545 true
543 546 );
544 547 wp_localize_script(
545 548 "wz-{$this->prefix}-admin",
546 - 'WZSettingsAdmin',
549 + 'WebberSettingsAdmin',
547 550 array(
548 551 'prefix' => $this->prefix,
549 552 'settings_key' => $this->settings_key,
550 553 'strings' => array(
@@ -605,9 +608,9 @@
605 608
606 609 // Localize Tom Select settings.
607 610 wp_localize_script(
608 611 "wz-{$prefix}-tom-select-init",
609 - 'WZTomSelectSettings',
612 + 'WebberTomSelectSettings',
610 613 $args
611 614 );
612 615 wp_enqueue_script( "wz-{$prefix}-tom-select-init" );
613 616
@@ -654,17 +657,26 @@
654 657 $id = $args['id'];
655 658 $name = $args['name'];
656 659 $type = isset( $args['type'] ) ? $args['type'] : 'text';
657 660 $callback = method_exists( $this->settings_form, "callback_{$type}" ) ? array( $this->settings_form, "callback_{$type}" ) : array( $this->settings_form, 'callback_missing' );
661 + $title = $name;
658 662
663 + if ( ! in_array( $type, array( 'header', 'repeater' ), true ) ) {
664 + $title = sprintf(
665 + '<label for="%1$s">%2$s</label>',
666 + esc_attr( $this->settings_form->get_field_id( $args ) ),
667 + wp_kses_post( $name )
668 + );
669 + }
670 +
659 671 // Tag header rows so the settings search can group fields under them.
660 672 if ( 'header' === $type ) {
661 - $args['class'] = trim( ( $args['class'] ?? '' ) . ' wz-settings-header-row' );
673 + $args['class'] = trim( ( $args['class'] ?? '' ) . ' wz-settings-header-row', " \t\n\r\0\x0B" );
662 674 }
663 675
664 676 add_settings_field(
665 677 "{$settings_key}[{$id}]", // ID of the settings field. We save it within the settings array.
666 - $name, // Label of the setting.
678 + $title, // Label of the setting.
667 679 $callback, // Function to handle the setting.
668 680 "{$settings_key}_{$section}", // Page to display the setting. In our case it is the section as defined above.
669 681 "{$settings_key}_{$section}", // Name of the section.
670 682 $args
@@ -676,10 +688,13 @@
676 688 register_setting(
677 689 $settings_key,
678 690 $settings_key,
679 691 array(
692 + 'type' => 'object',
693 + 'default' => $this->settings_defaults(),
680 694 'sanitize_callback' => array( $this, 'settings_sanitize' ),
681 - 'show_in_rest' => true,
695 + // The value is an open-ended map with no REST schema, and settings_sanitize() expects a form submission.
696 + 'show_in_rest' => false,
682 697 )
683 698 );
684 699 }
685 700
@@ -814,28 +829,23 @@
814 829 if ( $setting['id'] !== $key ) {
815 830 continue;
816 831 }
817 832
818 - // Return the callback name.
819 - $sanitize_callback = false;
820 -
821 833 if ( isset( $setting['sanitize_callback'] ) && is_callable( $setting['sanitize_callback'] ) ) {
822 - $sanitize_callback = $setting['sanitize_callback'];
823 - return $sanitize_callback;
834 + return $setting['sanitize_callback'];
824 835 }
825 836
826 - if ( is_callable( array( $settings_sanitize, 'sanitize_' . $setting['type'] . '_field' ) ) ) {
827 - // For repeater fields, create a closure to pass the field configuration.
828 - if ( 'repeater' === $setting['type'] ) {
829 - return function ( $value ) use ( $settings_sanitize, $setting ) {
830 - return $settings_sanitize->sanitize_repeater_field( $value, $setting );
831 - };
832 - }
833 - $sanitize_callback = array( $settings_sanitize, 'sanitize_' . $setting['type'] . '_field' );
834 - return $sanitize_callback;
837 + $method = 'sanitize_' . $setting['type'] . '_field';
838 +
839 + // Field types with no callback of their own must still not store raw input.
840 + if ( ! is_callable( array( $settings_sanitize, $method ) ) ) {
841 + $method = 'sanitize_missing';
835 842 }
836 843
837 - return $sanitize_callback;
844 + // Every callback receives the field configuration so choice fields can validate against their own options.
845 + return function ( $value ) use ( $settings_sanitize, $method, $setting ) {
846 + return $settings_sanitize->$method( $value, $setting );
847 + };
838 848 }
839 849 }
840 850
841 851 return false;
@@ -841,21 +851,40 @@
841 851 return false;
842 852 }
843 853
844 854 /**
855 + * Get the settings keys that are rendered locked (disabled or pro-gated).
856 + *
857 + * @return array Map of settings key => true for each locked setting.
858 + */
859 + public function get_locked_settings() {
860 + $locked = array();
861 +
862 + foreach ( $this->registered_settings as $settings ) {
863 + foreach ( $settings as $setting ) {
864 + if ( isset( $setting['id'] ) && ( ! empty( $setting['disabled'] ) || ! empty( $setting['pro'] ) ) ) {
865 + $locked[ $setting['id'] ] = true;
866 + }
867 + }
868 + }
869 +
870 + return $locked;
871 + }
872 +
873 + /**
845 874 * Sanitize the form data being submitted.
846 875 *
847 - * @param array $input Input unclean array.
876 + * @param mixed $input Unsanitized input. An array for form submissions, but REST and WP-CLI may pass anything.
848 877 * @return array Sanitized array
849 878 */
850 879 public function settings_sanitize( $input ) {
851 - // This should be set if a form is submitted, so let's save it in the $referrer variable.
852 - if ( empty( $_POST['_wp_http_referer'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
853 - return $input;
880 + // Set when a classic form is submitted; used only to pick the active tab below.
881 + $referrer = array();
882 +
883 + if ( ! empty( $_POST['_wp_http_referer'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
884 + parse_str( sanitize_text_field( wp_unslash( $_POST['_wp_http_referer'] ) ), $referrer ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
854 885 }
855 886
856 - parse_str( sanitize_text_field( wp_unslash( $_POST['_wp_http_referer'] ) ), $referrer ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
857 -
858 887 // Check if we need to set to defaults.
859 888 $reset = isset( $_POST['settings_reset'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
860 889
861 890 if ( $reset ) {
@@ -870,13 +899,14 @@
870 899 // Get the various settings we've registered.
871 900 $settings = get_option( $this->settings_key );
872 901 $settings = is_array( $settings ) ? $settings : array();
873 902 $settings_types = $this->get_registered_settings_types();
903 + $locked = $this->get_locked_settings();
874 904
875 905 // Get the tab. This is also our settings' section.
876 906 $tab = $referrer['tab'] ?? $this->default_tab;
877 907
878 - $input = $input ? $input : array();
908 + $input = is_array( $input ) ? $input : array();
879 909
880 910 /**
881 911 * Filter the settings for the tab. e.g. prefix_settings_general_sanitize.
882 912 *
@@ -883,10 +913,10 @@
883 913 * @param array $input Input unclean array
884 914 */
885 915 $input = apply_filters( $this->prefix . '_settings_' . $tab . '_sanitize', $input ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
886 916
887 - // Create an output array by merging the existing settings with the ones submitted.
888 - $output = array_merge( $settings, $input );
917 + // Start from what is stored. Submitted values are merged back in below, once sanitized.
918 + $output = $settings;
889 919
890 920 // Loop through each setting being saved and pass it through a sanitization filter.
891 921 foreach ( $settings_types as $key => $type ) {
892 922 /**
@@ -904,13 +934,9 @@
904 934 $sanitize_callback = $this->get_sanitize_callback( $key );
905 935
906 936 // If callback is set, call it.
907 937 if ( $sanitize_callback ) {
908 - if ( 'sensitive' === $type ) {
909 - $output[ $key ] = call_user_func( $sanitize_callback, $input[ $key ], $key );
910 - } else {
911 - $output[ $key ] = call_user_func( $sanitize_callback, $input[ $key ] );
912 - }
938 + $output[ $key ] = call_user_func( $sanitize_callback, $input[ $key ] );
913 939 continue;
914 940 }
915 941 }
916 942
@@ -915,15 +941,25 @@
915 941 }
916 942
917 943 // Delete any key that is not present when we submit the input array.
918 944 if ( ! isset( $input[ $key ] ) ) {
919 - unset( $output[ $key ] );
945 + // Disabled fields are never submitted, so a missing key must not delete them.
946 + if ( ! isset( $locked[ $key ] ) ) {
947 + unset( $output[ $key ] );
948 + }
920 949 }
950 + }
921 951
922 - // Delete any settings that are no longer part of our registered settings.
923 - if ( array_key_exists( $key, $output ) && ! array_key_exists( $key, $settings_types ) ) {
924 - unset( $output[ $key ] );
925 - }
952 + // Keys added by the tab filter are not registered settings, but must not be stored raw either.
953 + $settings_sanitize = new Settings_Sanitize(
954 + array(
955 + 'settings_key' => $this->settings_key,
956 + 'prefix' => $this->prefix,
957 + )
958 + );
959 +
960 + foreach ( array_diff_key( $input, $settings_types ) as $key => $value ) {
961 + $output[ sanitize_text_field( (string) $key ) ] = $settings_sanitize->sanitize_missing( $value );
926 962 }
927 963
928 964 add_settings_error( $this->prefix . '-notices', '', $this->translation_strings['success_message'], 'updated' );
929 965
@@ -955,9 +991,9 @@
955 991 }
956 992 ?>
957 993
958 994 <div id="poststuff">
959 - <div id="post-body" class="metabox-holder columns-2">
995 + <div id="post-body" class="metabox-holder columns-2 wz-settings-post-body">
960 996 <div id="post-body-content" class="wz-vertical-tabs">
961 997
962 998 <?php $this->show_navigation(); ?>
963 999 <?php $this->show_form(); ?>