Allow plugins to manipulate WP_Roles ($wp_roles global) on construct
|Reported by:||johnjamesjacoby||Owned by:|
The WP_Roles class is difficult to extend. There are no actions, filters, or intercept points to allow plugins to target it. Because the $wp_roles global can be created anytime (even doing_it_wrong on plugins_loaded) there's no reliable way to modify any part of $wp_roles.
(The only place WP_Roles actually has any action at all is in the set_role() method, which is the least useful function in the class since it noops all user roles if a user has more than one.)
The specific use case I have is bbPress's dynamic roles.
bbPress is unable to add its dynamic roles to the $wp_roles global on switch_to_blog(). Neither of WP_Roles's initialization methods have actions to allow bbPress to add its roles on.
- switch_to_blog() calls $wp_roles->reinit()
- then wp_get_current_user()
- finally $current_user->for_blog()
At no point can bbPress reliably append its roles to $wp_roles->roles, causing the current user to incorrectly be missing their bbPress role for that site.
More over, the WP_Roles::reinit() method seems like a one-use stop-gap to fix a specific problem, that ends up introducing other issues with trying to extend it. If the use_db flag is set to false, it bails early, and there's no way for plugins that don't use database roles to reinitialize their roles correctly again.
The attached patch does two things:
- Removes the reinit() method completely, and instead re-instantiates the $wp_roles global inside switch_to_blog(). WP_Roles::_init() is not a heavy function, and the guts are basically identical between the two methods.
- Adds a byref action to WP_Roles::init() that allow plugins like bbPress to add their dynamic roles anytime $wp_roles is created.