WordPress.org

Make WordPress Core

Changeset 39320


Ignore:
Timestamp:
11/19/16 22:38:40 (5 months ago)
Author:
westonruter
Message:

Customize: Ensure that WP_Customize_Manager::save_changeset_post() returns setting_validities even for supplied values that are unchanged from values in changeset.

Check setting existence and authorization via WP_Customize_Manager::validate_setting_values() even for null values to account for custom params being added to settings, preventing failures from being silently ignored.

See #38705, #30937.
Fixes #38865.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-customize-manager.php

    r39276 r39320  
    17291729                continue; 
    17301730            } 
    1731             if ( is_null( $unsanitized_value ) ) { 
    1732                 continue; 
    1733             } 
    17341731            if ( $options['validate_capability'] && ! current_user_can( $setting->capability ) ) { 
    17351732                $validity = new WP_Error( 'unauthorized', __( 'Unauthorized to modify setting due to capability.' ) ); 
    17361733            } else { 
     1734                if ( is_null( $unsanitized_value ) ) { 
     1735                    continue; 
     1736                } 
    17371737                $validity = $setting->validate( $unsanitized_value ); 
    17381738            } 
     
    20312031            } 
    20322032        } 
    2033         $post_values = wp_array_slice_assoc( $post_values, $changed_setting_ids ); 
    20342033 
    20352034        /** 
     
    20472046 
    20482047        // Validate settings. 
    2049         $setting_validities = $this->validate_setting_values( $post_values, array( 
     2048        $validated_values = array_merge( 
     2049            array_fill_keys( array_keys( $args['data'] ), null ), // Make sure existence/capability checks are done on value-less setting updates. 
     2050            $post_values 
     2051        ); 
     2052        $setting_validities = $this->validate_setting_values( $validated_values, array( 
    20502053            'validate_capability' => true, 
    20512054            'validate_existence' => true, 
     
    20652068        } 
    20662069 
    2067         $response = array( 
    2068             'setting_validities' => $setting_validities, 
    2069         ); 
    2070  
    20712070        // Obtain/merge data for changeset. 
    20722071        $original_changeset_data = $this->get_changeset_post_data( $changeset_post_id ); 
     
    21062105                unset( $data[ $changeset_setting_id ] ); 
    21072106            } else { 
    2108                 // Merge any additional setting params that have been supplied with the existing params. 
     2107 
    21092108                if ( ! isset( $data[ $changeset_setting_id ] ) ) { 
    21102109                    $data[ $changeset_setting_id ] = array(); 
    21112110                } 
    21122111 
     2112                // Merge any additional setting params that have been supplied with the existing params. 
     2113                $merged_setting_params = array_merge( $data[ $changeset_setting_id ], $setting_params ); 
     2114 
     2115                // Skip updating setting params if unchanged (ensuring the user_id is not overwritten). 
     2116                if ( $data[ $changeset_setting_id ] === $merged_setting_params ) { 
     2117                    continue; 
     2118                } 
     2119 
    21132120                $data[ $changeset_setting_id ] = array_merge( 
    2114                     $data[ $changeset_setting_id ], 
    2115                     $setting_params, 
     2121                    $merged_setting_params, 
    21162122                    array( 
    21172123                        'type' => $setting->type, 
     
    22202226 
    22212227        remove_filter( 'wp_save_post_revision_post_has_changed', array( $this, '_filter_revision_post_has_changed' ) ); 
     2228 
     2229        $response = array( 
     2230            'setting_validities' => $setting_validities, 
     2231        ); 
    22222232 
    22232233        if ( is_wp_error( $r ) ) { 
  • trunk/tests/phpunit/tests/customize/manager.php

    r39276 r39320  
    861861 
    862862        $uuid = wp_generate_uuid4(); 
    863         $manager = new WP_Customize_Manager( array( 
    864             'changeset_uuid' => $uuid, 
    865         ) ); 
    866         $wp_customize = $manager; 
    867         do_action( 'customize_register', $manager ); 
    868         $manager->add_setting( 'scratchpad', array( 
    869             'type' => 'option', 
    870             'capability' => 'exist', 
    871         ) ); 
    872  
    873         // Create initial set of 
    874         $r = $manager->save_changeset_post( array( 
     863        $wp_customize = $this->create_test_manager( $uuid ); 
     864        $r = $wp_customize->save_changeset_post( array( 
    875865            'status' => 'auto-draft', 
    876866            'data' => array( 
     
    891881            $r['setting_validities'] 
    892882        ); 
    893         $post_id = $manager->find_changeset_post_id( $uuid ); 
     883        $post_id = $wp_customize->find_changeset_post_id( $uuid ); 
    894884        $data = json_decode( get_post( $post_id )->post_content, true ); 
    895885        $this->assertEquals( self::$admin_user_id, $data['blogname']['user_id'] ); 
     
    899889        // Attempt to save just one setting under a different user. 
    900890        wp_set_current_user( $other_admin_user_id ); 
    901         $r = $manager->save_changeset_post( array( 
     891        $wp_customize = $this->create_test_manager( $uuid ); 
     892        $r = $wp_customize->save_changeset_post( array( 
    902893            'status' => 'auto-draft', 
    903894            'data' => array( 
     
    924915 
    925916        // Attempt to save now as under-privileged user. 
    926         $r = $manager->save_changeset_post( array( 
     917        $wp_customize = $this->create_test_manager( $uuid ); 
     918        $r = $wp_customize->save_changeset_post( array( 
    927919            'status' => 'auto-draft', 
    928920            'data' => array( 
     921                'blogname' => array( 
     922                    'value' => 'Admin 2 Title', // Identical to what is already in the changeset so will be skipped. 
     923                ), 
    929924                'scratchpad' => array( 
    930925                    'value' => 'Subscriber Scratch', 
     
    935930        $this->assertInternalType( 'array', $r ); 
    936931        $this->assertEquals( 
    937             array_fill_keys( array( 'scratchpad' ), true ), 
     932            array_fill_keys( array( 'scratchpad', 'blogname' ), true ), 
    938933            $r['setting_validities'] 
    939934        ); 
    940935        $data = json_decode( get_post( $post_id )->post_content, true ); 
    941         $this->assertEquals( $other_admin_user_id, $data['blogname']['user_id'] ); 
     936        $this->assertEquals( $other_admin_user_id, $data['blogname']['user_id'], 'Expected setting to be untouched.' ); 
    942937        $this->assertEquals( self::$subscriber_user_id, $data['scratchpad']['user_id'] ); 
    943938        $this->assertEquals( $other_admin_user_id, $data[ $this->manager->get_stylesheet() . '::background_color' ]['user_id'] ); 
     
    956951        } 
    957952        $this->filtered_setting_current_user_ids = array(); 
    958         foreach ( $manager->settings() as $setting ) { 
     953        foreach ( $wp_customize->settings() as $setting ) { 
    959954            add_filter( sprintf( 'customize_sanitize_%s', $setting->id ), array( $this, 'filter_customize_setting_to_log_current_user' ), 10, 2 ); 
    960955        } 
     
    970965        $this->assertEquals( $other_admin_user_id, $this->filtered_setting_current_user_ids['background_color'] ); 
    971966        $this->assertEquals( 'Subscriber Scratch', get_option( 'scratchpad' ) ); 
     967    } 
     968 
     969    /** 
     970     * Create test manager. 
     971     * 
     972     * @param string $uuid Changeset UUID. 
     973     * @return WP_Customize_Manager Manager. 
     974     */ 
     975    protected function create_test_manager( $uuid ) { 
     976        $manager = new WP_Customize_Manager( array( 
     977            'changeset_uuid' => $uuid, 
     978        ) ); 
     979        do_action( 'customize_register', $manager ); 
     980        $manager->add_setting( 'blogfounded', array( 
     981            'type' => 'option', 
     982        ) ); 
     983        $manager->add_setting( 'blogterminated', array( 
     984            'type' => 'option', 
     985            'capability' => 'do_not_allow', 
     986        ) ); 
     987        $manager->add_setting( 'scratchpad', array( 
     988            'type' => 'option', 
     989            'capability' => 'exist', 
     990        ) ); 
     991        return $manager; 
     992    } 
     993 
     994    /** 
     995     * Test writing changesets when user supplies unchanged values. 
     996     * 
     997     * @ticket 38865 
     998     * @covers WP_Customize_Manager::save_changeset_post() 
     999     */ 
     1000    function test_save_changeset_post_with_unchanged_values() { 
     1001        global $wp_customize; 
     1002 
     1003        add_theme_support( 'custom-background' ); 
     1004        wp_set_current_user( self::$admin_user_id ); 
     1005        $other_admin_user_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); 
     1006 
     1007        $uuid = wp_generate_uuid4(); 
     1008        $wp_customize = $this->create_test_manager( $uuid ); 
     1009        $wp_customize->save_changeset_post( array( 
     1010            'status' => 'auto-draft', 
     1011            'data' => array( 
     1012                'blogname' => array( 
     1013                    'value' => 'Admin 1 Title', 
     1014                ), 
     1015                'blogdescription' => array( 
     1016                    'value' => 'Admin 1 Tagline', 
     1017                ), 
     1018                'blogfounded' => array( 
     1019                    'value' => '2016', 
     1020                ), 
     1021                'scratchpad' => array( 
     1022                    'value' => 'Admin 1 Scratch', 
     1023                ), 
     1024            ), 
     1025        ) ); 
     1026 
     1027        // Make sure that setting properties of unknown and unauthorized settings are rejected. 
     1028        $data = get_post( $wp_customize->changeset_post_id() )->post_content; 
     1029        $r = $wp_customize->save_changeset_post( array( 
     1030            'data' => array( 
     1031                'unknownsetting' => array( 
     1032                    'custom' => 'prop', 
     1033                ), 
     1034                'blogterminated' => array( 
     1035                    'custom' => 'prop', 
     1036                ), 
     1037            ), 
     1038        ) ); 
     1039        $this->assertInstanceOf( 'WP_Error', $r['setting_validities']['unknownsetting'] ); 
     1040        $this->assertEquals( 'unrecognized', $r['setting_validities']['unknownsetting']->get_error_code() ); 
     1041        $this->assertInstanceOf( 'WP_Error', $r['setting_validities']['blogterminated'] ); 
     1042        $this->assertEquals( 'unauthorized', $r['setting_validities']['blogterminated']->get_error_code() ); 
     1043        $this->assertEquals( $data, get_post( $wp_customize->changeset_post_id() )->post_content ); 
     1044 
     1045        // Test submitting data with changed and unchanged settings, creating a new instance so that the post_values are cleared. 
     1046        wp_set_current_user( $other_admin_user_id ); 
     1047        $wp_customize = $this->create_test_manager( $uuid ); 
     1048        $r = $wp_customize->save_changeset_post( array( 
     1049            'status' => 'auto-draft', 
     1050            'data' => array( 
     1051                'blogname' => array( 
     1052                    'value' => 'Admin 1 Title', // Unchanged value. 
     1053                ), 
     1054                'blogdescription' => array( 
     1055                    'value' => 'Admin 1 Tagline Changed', // Changed value. 
     1056                ), 
     1057                'blogfounded' => array( 
     1058                    'extra' => 'blogfounded_param', // New param. 
     1059                ), 
     1060                'scratchpad' => array( 
     1061                    'value' => 'Admin 1 Scratch', // Unchanged value. 
     1062                    'extra' => 'background_scratchpad2', // New param. 
     1063                ), 
     1064            ), 
     1065        ) ); 
     1066 
     1067        // Note that blogfounded is not included among setting_validities because no value was supplied and it is not unrecognized/unauthorized. 
     1068        $this->assertEquals( array_fill_keys( array( 'blogname', 'blogdescription', 'scratchpad' ), true ), $r['setting_validities'], 'Expected blogname even though unchanged.' ); 
     1069 
     1070        $data = json_decode( get_post( $wp_customize->changeset_post_id() )->post_content, true ); 
     1071 
     1072        $this->assertEquals( self::$admin_user_id, $data['blogname']['user_id'], 'Expected unchanged user_id since value was unchanged.' ); 
     1073        $this->assertEquals( $other_admin_user_id, $data['blogdescription']['user_id'] ); 
     1074        $this->assertEquals( $other_admin_user_id, $data['blogfounded']['user_id'] ); 
     1075        $this->assertEquals( $other_admin_user_id, $data['scratchpad']['user_id'] ); 
    9721076    } 
    9731077 
Note: See TracChangeset for help on using the changeset viewer.