Opened 6 years ago
Last modified 6 years ago
#44857 new defect (bug)
get_object_subtype uses get_user_by before it's defined
Reported by: | infostreams | Owned by: | |
---|---|---|---|
Milestone: | Awaiting Review | Priority: | normal |
Severity: | normal | Version: | 4.9.8 |
Component: | Users | Keywords: | reporter-feedback |
Focuses: | Cc: |
Description
In 'get_object_subtype' on line 1308 in wp-includes/meta.php, the function 'get_user_by' is used. This function is defined in wp-includes/pluggable.php (line 87-109). However, 'pluggable.php' is not loaded until after the plugins have initialized (see wp-settings.php line 160). Therefore, the situation can occur that 'get_object_subtype' calls a function that isn't defined yet.
Concretely, this situation occurs in the WPML plugin, in combination with a multisite installation. However, there are many other situations where it could occur (anywhere in any plugin initialization code). If you add a new site, the WPML plugin will try to assign the network admin new capabilities by calling (WP_User)->add_cap for all of the network administrators. 'add_cap' calls 'update_user_meta', which calls 'get_object_subtype', which results in a fatal error, which then displays a HTTP 500 error whenever the user is trying to access the WordPress dashboard. Fairly dramatic, indeed.
For any googlers, you can resolve this issue by creating a file 'wpml-multisite-fix.php' in 'wp-content/mu-plugins', with the following content:
<?php if ( ! function_exists( 'get_user_by' ) ) { /** * Define the 'get_user_by' function here instead of in pluggable.php, because WP 4.9.8 has a bug - * it uses 'get_user_by' before it's included (see meta.php line 1308, and see that it isn't * included yet in wp-settings.php line 160). * * @param string $field The field to retrieve the user with. id | ID | slug | email | login. * @param int|string $value A value for $field. A user ID, slug, email address, or login name. * @return WP_User|false WP_User object on success, false on failure. */ function get_user_by( $field, $value ) { $userdata = WP_User::get_data_by( $field, $value ); if ( ! $userdata ) { return false; } $user = new WP_User(); $user->init( $userdata ); return $user; } }
Change History (4)
#1
@
6 years ago
- Component changed from Bootstrap/Load to Users
- Focuses performance added
- Keywords dev-feedback added
- Type changed from defect (bug) to enhancement
#4
@
6 years ago
I'm sorry, that's a bit difficult because the WPML plugin is closed source and as such I cannot just include it here, neither can I provide a composer.json file to setup everything in such a way as to reproduce it.
Basically, reproducing it comes down to this:
- Install WordPress 4.9.8 - I'm going to assume it's still broken in the lastest WordPress, but it was originally reported for 4.9.8
- Convert it into a multisite
- Install the WPML plugin. You can probably get it from the WPML guys for free if you say that you're a WordPress core committer.
- Try to add a site
- Boom 💥
Hi @infostreams, welcome to WordPress Trac! Thanks for the report. Sorry it took a while for someone to get back to you.
Could you provide an example code to reproduce the issue? It sounds like it's caused by a plugin running some initialization code too early. Generally it's not recommended for plugins to run any code until the appropriate action fires, e.g.
plugins_loaded
orinit
.