Make WordPress Core

Changeset 41625


Ignore:
Timestamp:
09/27/2017 09:43:59 PM (9 years ago)
Author:
flixos90
Message:

Multisite: Improve initializing available roles when switch sites.

Switching the available roles and the current user's capabilities no longer happens in switch_to_blog() and restore_current_blog(), instead it has been moved to a new function wp_switch_roles_and_user() which is hooked into the site switching process. This allows to improve performance by temporarily unhooking the function when roles and capabilities do not need to be switched.

This change ensures that switching available roles now works closer to switching user capabilities, particularly the changes in [41624]. A new WP_Roles::for_site( $site_id ) method has been introduced, and the WP_Roles::_init() method has been deprecated. It is furthermore possible to retrieve the site ID for which the available roles are currently initialized through a new WP_Roles::get_site_id().

Props johnjamesjacoby, flixos90.
Fixes #38645.

Location:
trunk
Files:
4 edited

Legend:

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

    r41162 r41625  
    6666
    6767        /**
     68         * The site ID the roles are initialized for.
     69         *
     70         * @since 4.9.0
     71         * @var int
     72         */
     73        protected $site_id = 0;
     74
     75        /**
    6876         * Constructor
    6977         *
    7078         * @since 2.0.0
    71          */
    72         public function __construct() {
    73                 $this->_init();
     79         * @since 4.9.0 The $site_id argument was added.
     80         *
     81         * @global array $wp_user_roles Used to set the 'roles' property value.
     82         *
     83         * @param int $site_id Site ID to initialize roles for. Default is the current site.
     84         */
     85        public function __construct( $site_id = null ) {
     86                global $wp_user_roles;
     87
     88                $this->use_db = empty( $wp_user_roles );
     89
     90                $this->for_site( $site_id );
    7491        }
    7592
     
    98115         *
    99116         * @since 2.1.0
    100          *
    101          * @global array $wp_user_roles Used to set the 'roles' property value.
     117         * @deprecated 4.9.0 Use WP_Roles::for_site()
    102118         */
    103119        protected function _init() {
    104                 global $wp_user_roles, $wpdb;
    105 
    106                 $this->role_key = $wpdb->get_blog_prefix() . 'user_roles';
    107                 if ( ! empty( $wp_user_roles ) ) {
    108                         $this->roles = $wp_user_roles;
    109                         $this->use_db = false;
    110                 } else {
    111                         $this->roles = get_option( $this->role_key );
    112                 }
    113 
    114                 if ( empty( $this->roles ) )
    115                         return;
    116 
    117                 $this->role_objects = array();
    118                 $this->role_names =  array();
    119                 foreach ( array_keys( $this->roles ) as $role ) {
    120                         $this->role_objects[$role] = new WP_Role( $role, $this->roles[$role]['capabilities'] );
    121                         $this->role_names[$role] = $this->roles[$role]['name'];
    122                 }
    123 
    124                 /**
    125                  * After the roles have been initialized, allow plugins to add their own roles.
    126                  *
    127                  * @since 4.7.0
    128                  *
    129                  * @param WP_Roles $this A reference to the WP_Roles object.
    130                  */
    131                 do_action( 'wp_roles_init', $this );
     120                _deprecated_function( __METHOD__, '4.9.0', 'WP_Roles::for_site()' );
     121
     122                $this->for_site();
    132123        }
    133124
     
    139130         *
    140131         * @since 3.5.0
    141          * @deprecated 4.7.0 Use new WP_Roles()
     132         * @deprecated 4.7.0 Use WP_Roles::for_site()
    142133         */
    143134        public function reinit() {
    144                 _deprecated_function( __METHOD__, '4.7.0', 'new WP_Roles()' );
    145                 $this->_init();
     135                _deprecated_function( __METHOD__, '4.7.0', 'WP_Roles::for_site()' );
     136
     137                $this->for_site();
    146138        }
    147139
     
    271263                return isset( $this->role_names[$role] );
    272264        }
     265
     266        /**
     267         * Initializes all of the available roles.
     268         *
     269         * @since 4.9.0
     270         */
     271        public function init_roles() {
     272                if ( empty( $this->roles ) ) {
     273                        return;
     274                }
     275
     276                $this->role_objects = array();
     277                $this->role_names =  array();
     278                foreach ( array_keys( $this->roles ) as $role ) {
     279                        $this->role_objects[ $role ] = new WP_Role( $role, $this->roles[ $role ]['capabilities'] );
     280                        $this->role_names[ $role ] = $this->roles[ $role ]['name'];
     281                }
     282
     283                /**
     284                 * After the roles have been initialized, allow plugins to add their own roles.
     285                 *
     286                 * @since 4.7.0
     287                 *
     288                 * @param WP_Roles $this A reference to the WP_Roles object.
     289                 */
     290                do_action( 'wp_roles_init', $this );
     291        }
     292
     293        /**
     294         * Sets the site to operate on. Defaults to the current site.
     295         *
     296         * @since 4.9.0
     297         *
     298         * @global wpdb $wpdb WordPress database abstraction object.
     299         *
     300         * @param int $site_id Site ID to initialize roles for. Default is the current site.
     301         */
     302        public function for_site( $site_id = null ) {
     303                global $wpdb;
     304
     305                if ( ! empty( $site_id ) ) {
     306                        $this->site_id = absint( $site_id );
     307                } else {
     308                        $this->site_id = get_current_blog_id();
     309                }
     310
     311                $this->role_key = $wpdb->get_blog_prefix( $this->site_id ) . 'user_roles';
     312
     313                if ( ! empty( $this->roles ) && ! $this->use_db ) {
     314                        return;
     315                }
     316
     317                $this->roles = $this->get_roles_data();
     318
     319                $this->init_roles();
     320        }
     321
     322        /**
     323         * Gets the ID of the site for which roles are currently initialized.
     324         *
     325         * @since 4.9.0
     326         *
     327         * @return int Site ID.
     328         */
     329        public function get_site_id() {
     330                return $this->site_id;
     331        }
     332
     333        /**
     334         * Gets the available roles data.
     335         *
     336         * @since 4.9.0
     337         *
     338         * @global array $wp_user_roles Used to set the 'roles' property value.
     339         *
     340         * @return array Roles array.
     341         */
     342        protected function get_roles_data() {
     343                global $wp_user_roles;
     344
     345                if ( ! empty( $wp_user_roles ) ) {
     346                        return $wp_user_roles;
     347                }
     348
     349                if ( is_multisite() && $this->site_id != get_current_blog_id() ) {
     350                        remove_action( 'switch_blog', 'wp_switch_roles_and_user', 1 );
     351
     352                        $roles = get_blog_option( $this->site_id, $this->role_key, array() );
     353
     354                        add_action( 'switch_blog', 'wp_switch_roles_and_user', 1, 2 );
     355
     356                        return $roles;
     357                }
     358
     359                return get_option( $this->role_key, array() );
     360        }
    273361}
  • trunk/src/wp-includes/ms-blogs.php

    r41624 r41625  
    793793 */
    794794function switch_to_blog( $new_blog, $deprecated = null ) {
    795         global $wpdb, $wp_roles;
     795        global $wpdb;
    796796
    797797        $blog_id = get_current_blog_id();
     
    848848        }
    849849
    850         if ( did_action( 'init' ) ) {
    851                 $wp_roles = new WP_Roles();
    852                 $current_user = wp_get_current_user();
    853                 $current_user->for_site( $new_blog );
    854         }
    855 
    856850        /** This filter is documented in wp-includes/ms-blogs.php */
    857851        do_action( 'switch_blog', $new_blog, $prev_blog_id );
     
    877871 */
    878872function restore_current_blog() {
    879         global $wpdb, $wp_roles;
     873        global $wpdb;
    880874
    881875        if ( empty( $GLOBALS['_wp_switched_stack'] ) ) {
     
    922916        }
    923917
    924         if ( did_action( 'init' ) ) {
    925                 $wp_roles = new WP_Roles();
    926                 $current_user = wp_get_current_user();
    927                 $current_user->for_site( $blog );
    928         }
    929 
    930918        /** This filter is documented in wp-includes/ms-blogs.php */
    931919        do_action( 'switch_blog', $blog, $prev_blog_id );
     
    935923
    936924        return true;
     925}
     926
     927/**
     928 * Switches the initialized roles and current user capabilities to another site.
     929 *
     930 * @since 4.9.0
     931 *
     932 * @param int $new_site_id New site ID.
     933 * @param int $old_site_id Old site ID.
     934 */
     935function wp_switch_roles_and_user( $new_site_id, $old_site_id ) {
     936        if ( $new_site_id == $old_site_id ) {
     937                return;
     938        }
     939
     940        if ( ! did_action( 'init' ) ) {
     941                return;
     942        }
     943
     944        wp_roles()->for_site( $new_site_id );
     945        wp_get_current_user()->for_site( $new_site_id );
    937946}
    938947
  • trunk/src/wp-includes/ms-default-filters.php

    r40596 r41625  
    3232add_action( 'network_user_new_created_user',   'wp_send_new_user_notifications' );
    3333add_filter( 'sanitize_user', 'strtolower' );
     34
     35// Roles
     36add_action( 'switch_blog', 'wp_switch_roles_and_user', 1, 2 );
    3437
    3538// Blogs
  • trunk/tests/phpunit/tests/user/capabilities.php

    r41624 r41625  
    19401940                $this->assertSame( 333, $user->get_site_id() );
    19411941        }
     1942
     1943        /**
     1944         * @ticket 38645
     1945         * @group ms-required
     1946         */
     1947        function test_init_roles_for_different_site() {
     1948                global $wpdb;
     1949
     1950                $site_id = self::factory()->blog->create();
     1951
     1952                switch_to_blog( $site_id );
     1953
     1954                $role_name = 'uploader';
     1955                add_role( $role_name, 'Uploader', array(
     1956                        'read'         => true,
     1957                        'upload_files' => true,
     1958                ) );
     1959
     1960                restore_current_blog();
     1961
     1962                $wp_roles = wp_roles();
     1963                $wp_roles->for_site( $site_id );
     1964
     1965                $this->assertTrue( isset( $wp_roles->role_objects[ $role_name ] ) );
     1966        }
     1967
     1968        /**
     1969         * @ticket 38645
     1970         */
     1971        function test_get_roles_data() {
     1972                global $wpdb;
     1973
     1974                $custom_roles = array(
     1975                        'test_role' => array(
     1976                                'name'         => 'Test Role',
     1977                                'capabilities' => array(
     1978                                        'do_foo' => true,
     1979                                        'do_bar' => false,
     1980                                ),
     1981                        ),
     1982                );
     1983
     1984                // Test `WP_Roles::get_roles_data()` by manually setting the roles option.
     1985                update_option( $wpdb->get_blog_prefix( get_current_blog_id() ) . 'user_roles', $custom_roles );
     1986
     1987                $roles = new WP_Roles();
     1988                $this->assertSame( $custom_roles, $roles->roles );
     1989        }
     1990
     1991        /**
     1992         * @ticket 38645
     1993         */
     1994        function test_roles_get_site_id_default() {
     1995                $roles = new WP_Roles();
     1996                $this->assertSame( get_current_blog_id(), $roles->get_site_id() );
     1997        }
     1998
     1999        /**
     2000         * @ticket 38645
     2001         */
     2002        function test_roles_get_site_id() {
     2003                global $wpdb;
     2004
     2005                // Suppressing errors here allows to get around creating an actual site,
     2006                // which is unnecessary for this test.
     2007                $suppress = $wpdb->suppress_errors();
     2008                $roles = new WP_Roles( 333 );
     2009                $wpdb->suppress_errors( $suppress );
     2010
     2011                $this->assertSame( 333, $roles->get_site_id() );
     2012        }
    19422013}
Note: See TracChangeset for help on using the changeset viewer.