Make WordPress Core

Changeset 61210


Ignore:
Timestamp:
11/11/2025 12:51:01 PM (2 months ago)
Author:
SergeyBiryukov
Message:

Users: Initialize the WP_User::$roles property as a sequential array.

Previously, if any roles were filtered out via array_filter() when assigning the WP_User::$roles property in WP_User::get_role_caps(), the resulting array could contain non-sequential numeric keys, which would then cause it to be treated as an object when JSON-encoded, e.g. in wp_localize_script(), instead of a proper array, breaking client-side expectations.

This commit ensures that the WP_User::$roles property is always treated as an array.

Follow-up to [2703], [2793], [22118].

Props haruncpi, peterwilsoncc, SirLouen, getsyash, wildworks, johnjamesjacoby, SergeyBiryukov.
Fixes #63427.

Location:
trunk
Files:
2 edited

Legend:

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

    r61037 r61210  
    516516        $wp_roles = wp_roles();
    517517
    518         // Filter out caps that are not role names and assign to $this->roles.
     518        // Select caps that are role names and assign to $this->roles.
    519519        if ( is_array( $this->caps ) ) {
    520             $this->roles = array_filter( array_keys( $this->caps ), array( $wp_roles, 'is_role' ) );
     520            $this->roles = array();
     521
     522            foreach ( $this->caps as $key => $value ) {
     523                if ( $wp_roles->is_role( $key ) ) {
     524                    $this->roles[] = $key;
     525                }
     526            }
    521527        }
    522528
  • trunk/tests/phpunit/tests/user.php

    r60941 r61210  
    21592159
    21602160    /**
     2161     * Tests that the `WP_User::$roles` property is a sequential array.
     2162     *
     2163     * @ticket 63427
     2164     *
     2165     * @covers WP_User::get_role_caps
     2166     */
     2167    public function test_wp_user_roles_property_is_sequential_array() {
     2168        $user = new WP_User( self::$author_id );
     2169        $this->assertTrue( $this->is_sequential( $user->roles ), 'Initial roles array should be sequential.' );
     2170
     2171        $user->remove_role( 'author' );
     2172        $this->assertIsArray( $user->roles, 'After removing all roles, $user->roles should still be an array.' );
     2173        $this->assertSame( array(), $user->roles, 'After removing all roles, $user->roles should be an empty array.' );
     2174
     2175        $user->add_role( 'author' );
     2176        $user->add_role( 'subscriber' );
     2177        $this->assertSame( array( 'author', 'subscriber' ), $user->roles, 'After adding multiple roles, $user->roles should contain added roles.' );
     2178        $this->assertTrue( $this->is_sequential( $user->roles ), 'After adding multiple roles, $user->roles should still be sequential.' );
     2179    }
     2180
     2181    /**
     2182     * Determines whether an array has sequential numeric keys.
     2183     *
     2184     * @param array $arr The array to check.
     2185     * @return bool True if the array has sequential numeric keys, false otherwise.
     2186     */
     2187    private function is_sequential( array $arr ) {
     2188        return array_keys( $arr ) === range( 0, count( $arr ) - 1 );
     2189    }
     2190
     2191    /**
    21612192     * @ticket 42564
    21622193     */
Note: See TracChangeset for help on using the changeset viewer.