PluginProbe
WebberZone Top 10 — Popular Posts / 4.5.1
WebberZone Top 10 — Popular Posts v4.5.1
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 1.6.1 All 117 releases
← All changes | includes/admin/settings/class-settings-api.php +40 -39 4.4.34.5.1 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 *
@@ -542,9 +542,9 @@
542 542 true
543 543 );
544 544 wp_localize_script(
545 545 "wz-{$this->prefix}-admin",
546 - 'WZSettingsAdmin',
546 + 'WebberSettingsAdmin',
547 547 array(
548 548 'prefix' => $this->prefix,
549 549 'settings_key' => $this->settings_key,
550 550 'strings' => array(
@@ -605,9 +605,9 @@
605 605
606 606 // Localize Tom Select settings.
607 607 wp_localize_script(
608 608 "wz-{$prefix}-tom-select-init",
609 - 'WZTomSelectSettings',
609 + 'WebberTomSelectSettings',
610 610 $args
611 611 );
612 612 wp_enqueue_script( "wz-{$prefix}-tom-select-init" );
613 613
@@ -657,9 +657,9 @@
657 657 $callback = method_exists( $this->settings_form, "callback_{$type}" ) ? array( $this->settings_form, "callback_{$type}" ) : array( $this->settings_form, 'callback_missing' );
658 658
659 659 // Tag header rows so the settings search can group fields under them.
660 660 if ( 'header' === $type ) {
661 - $args['class'] = trim( ( $args['class'] ?? '' ) . ' wz-settings-header-row' );
661 + $args['class'] = trim( ( $args['class'] ?? '' ) . ' wz-settings-header-row', " \t\n\r\0\x0B" );
662 662 }
663 663
664 664 add_settings_field(
665 665 "{$settings_key}[{$id}]", // ID of the settings field. We save it within the settings array.
@@ -676,10 +676,13 @@
676 676 register_setting(
677 677 $settings_key,
678 678 $settings_key,
679 679 array(
680 + 'type' => 'object',
681 + 'default' => $this->settings_defaults(),
680 682 'sanitize_callback' => array( $this, 'settings_sanitize' ),
681 - 'show_in_rest' => true,
683 + // The value is an open-ended map with no REST schema, and settings_sanitize() expects a form submission.
684 + 'show_in_rest' => false,
682 685 )
683 686 );
684 687 }
685 688
@@ -814,28 +817,23 @@
814 817 if ( $setting['id'] !== $key ) {
815 818 continue;
816 819 }
817 820
818 - // Return the callback name.
819 - $sanitize_callback = false;
820 -
821 821 if ( isset( $setting['sanitize_callback'] ) && is_callable( $setting['sanitize_callback'] ) ) {
822 - $sanitize_callback = $setting['sanitize_callback'];
823 - return $sanitize_callback;
822 + return $setting['sanitize_callback'];
824 823 }
825 824
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;
825 + $method = 'sanitize_' . $setting['type'] . '_field';
826 +
827 + // Field types with no callback of their own must still not store raw input.
828 + if ( ! is_callable( array( $settings_sanitize, $method ) ) ) {
829 + $method = 'sanitize_missing';
835 830 }
836 831
837 - return $sanitize_callback;
832 + // Every callback receives the field configuration so choice fields can validate against their own options.
833 + return function ( $value ) use ( $settings_sanitize, $method, $setting ) {
834 + return $settings_sanitize->$method( $value, $setting );
835 + };
838 836 }
839 837 }
840 838
841 839 return false;
@@ -862,19 +860,19 @@
862 860
863 861 /**
864 862 * Sanitize the form data being submitted.
865 863 *
866 - * @param array $input Input unclean array.
864 + * @param mixed $input Unsanitized input. An array for form submissions, but REST and WP-CLI may pass anything.
867 865 * @return array Sanitized array
868 866 */
869 867 public function settings_sanitize( $input ) {
870 - // This should be set if a form is submitted, so let's save it in the $referrer variable.
871 - if ( empty( $_POST['_wp_http_referer'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
872 - return $input;
868 + // Set when a classic form is submitted; used only to pick the active tab below.
869 + $referrer = array();
870 +
871 + if ( ! empty( $_POST['_wp_http_referer'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
872 + parse_str( sanitize_text_field( wp_unslash( $_POST['_wp_http_referer'] ) ), $referrer ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
873 873 }
874 874
875 - parse_str( sanitize_text_field( wp_unslash( $_POST['_wp_http_referer'] ) ), $referrer ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
876 -
877 875 // Check if we need to set to defaults.
878 876 $reset = isset( $_POST['settings_reset'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
879 877
880 878 if ( $reset ) {
@@ -894,9 +892,9 @@
894 892
895 893 // Get the tab. This is also our settings' section.
896 894 $tab = $referrer['tab'] ?? $this->default_tab;
897 895
898 - $input = $input ? $input : array();
896 + $input = is_array( $input ) ? $input : array();
899 897
900 898 /**
901 899 * Filter the settings for the tab. e.g. prefix_settings_general_sanitize.
902 900 *
@@ -903,10 +901,10 @@
903 901 * @param array $input Input unclean array
904 902 */
905 903 $input = apply_filters( $this->prefix . '_settings_' . $tab . '_sanitize', $input ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
906 904
907 - // Create an output array by merging the existing settings with the ones submitted.
908 - $output = array_merge( $settings, $input );
905 + // Start from what is stored. Submitted values are merged back in below, once sanitized.
906 + $output = $settings;
909 907
910 908 // Loop through each setting being saved and pass it through a sanitization filter.
911 909 foreach ( $settings_types as $key => $type ) {
912 910 /**
@@ -924,13 +922,9 @@
924 922 $sanitize_callback = $this->get_sanitize_callback( $key );
925 923
926 924 // If callback is set, call it.
927 925 if ( $sanitize_callback ) {
928 - if ( 'sensitive' === $type ) {
929 - $output[ $key ] = call_user_func( $sanitize_callback, $input[ $key ], $key );
930 - } else {
931 - $output[ $key ] = call_user_func( $sanitize_callback, $input[ $key ] );
932 - }
926 + $output[ $key ] = call_user_func( $sanitize_callback, $input[ $key ] );
933 927 continue;
934 928 }
935 929 }
936 930
@@ -940,13 +934,20 @@
940 934 if ( ! isset( $locked[ $key ] ) ) {
941 935 unset( $output[ $key ] );
942 936 }
943 937 }
938 + }
944 939
945 - // Delete any settings that are no longer part of our registered settings.
946 - if ( array_key_exists( $key, $output ) && ! array_key_exists( $key, $settings_types ) ) {
947 - unset( $output[ $key ] );
948 - }
940 + // Keys added by the tab filter are not registered settings, but must not be stored raw either.
941 + $settings_sanitize = new Settings_Sanitize(
942 + array(
943 + 'settings_key' => $this->settings_key,
944 + 'prefix' => $this->prefix,
945 + )
946 + );
947 +
948 + foreach ( array_diff_key( $input, $settings_types ) as $key => $value ) {
949 + $output[ sanitize_text_field( (string) $key ) ] = $settings_sanitize->sanitize_missing( $value );
949 950 }
950 951
951 952 add_settings_error( $this->prefix . '-notices', '', $this->translation_strings['success_message'], 'updated' );
952 953