[wp-trac] [WordPress Trac] #23016: Allow plugins to manipulate WP_Roles ($wp_roles global) on construct
WordPress Trac
noreply at wordpress.org
Wed Nov 2 18:35:57 UTC 2016
#23016: Allow plugins to manipulate WP_Roles ($wp_roles global) on construct
-------------------------------------------------+-------------------------
Reporter: johnjamesjacoby | Owner: pento
Type: defect (bug) | Status: closed
Priority: normal | Milestone: 4.7
Component: Role/Capability | Version: 3.5
Severity: normal | Resolution: fixed
Keywords: has-patch has-unit-tests commit | Focuses:
needs-dev-note |
-------------------------------------------------+-------------------------
Comment (by johnjamesjacoby):
@mnelson4 - interesting thoughts. I think the original behavior was
unintentional, and problematic for the way WordPress (and plugins &
themes) interact with Roles.
The old `reinit()` method used `$this` vs. directly touching the
`$wp_roles` global, so the current `_init()` method is a direct equivalent
-- either one could be used for the same end result (though, I think I
found a different consequence.)
Please consider these (very crude) examples (that should probably be unit
tests):
{{{
add_action( 'init', function() {
$wp_roles = new WP_Roles();
$my_reference_to_wp_roles = $wp_roles;
$wp_roles->foo = 'bar';
var_dump( $wp_roles->foo );
var_dump( $my_reference_to_wp_roles->foo );
die;
} );
}}}
Will output:
{{{
string 'bar' (length=3)
string 'bar' (length=3)
}}}
`$my_reference_to_wp_roles` was never modified, but because the variable
it points to was, it was too.
----
The same happens if you use the global:
{{{
add_action( 'init', function() {
global $wp_roles;
$my_reference_to_wp_roles = $wp_roles;
$wp_roles->foo = 'bar';
var_dump( $wp_roles->foo );
var_dump( $my_reference_to_wp_roles->foo );
die;
} );
}}}
Will output:
{{{
string 'bar' (length=3)
string 'bar' (length=3)
}}}
----
If we intentionally try to wipe out `$wp_roles`, we can. Our clone keeps
the changes (stale compared to the global.)
{{{
add_action( 'init', function() {
global $wp_roles;
$my_reference_to_wp_roles = $wp_roles;
$wp_roles->foo = 'bar';
$wp_roles = $wp_roles->reinit();
var_dump( $wp_roles->foo );
$wp_roles->foo = 'bar';
$wp_roles = new WP_Roles();
var_dump( $wp_roles->foo );
var_dump( $my_reference_to_wp_roles->foo );
die;
} );
}}}
Will output:
{{{
string null
string null
string 'bar' (length=3)
}}}
----
Lastly, let's mix & match a changed global reference:
{{{
add_action( 'init', function() {
global $wp_roles, $new_roles;
$new_roles = $wp_roles;
$wp_roles->changed = true;
}, 10 );
add_action( 'init', function() {
global $wp_roles;
$wp_roles->changed = false;
}, 11 );
add_action( 'init', function() {
global $wp_roles, $new_roles;
var_dump( $wp_roles->changed );
var_dump( $new_roles->changed );
die;
}, 12 );
}}}
And we'll get...
{{{
boolean false
boolean false
}}}
----
There is also `wp_roles()`, which (in)conveniently obscured the problem.
There might be places (even in core) that would benefit from using
`wp_roles()` vs `new WP_Roles()`, but we'll need to audit those & make
decisions based on intent. Basically: yield or not yield. (At a cursory, I
think all usages are OK.)
Either way, it appears to my eyes that there's not much of a change here,
and what change there is creates a more predictable and easier to
understand interaction with `WP_Roles`.
----
I think that `WP_Roles->reinit()` does need to keep it's `use_db` check,
though. Otherwise the `$wp_user_roles` isn't going to be respected as the
omega roles array for the entire installation. Patch imminent for this.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/23016#comment:29>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list