| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878 | <?php/** * User API: WP_User class * * @package WordPress * @subpackage Users * @since 4.4.0 *//** * Core class used to implement the WP_User object. * * @since 2.0.0 * * @property string $nickname * @property string $description * @property string $user_description * @property string $first_name * @property string $user_firstname * @property string $last_name * @property string $user_lastname * @property string $user_login * @property string $user_pass * @property string $user_nicename * @property string $user_email * @property string $user_url * @property string $user_registered * @property string $user_activation_key * @property string $user_status * @property int    $user_level * @property string $display_name * @property string $spam * @property string $deleted * @property string $locale * @property string $rich_editing * @property string $syntax_highlighting */class WP_User {	/**	 * User data container.	 *	 * @since 2.0.0	 * @var object	 */	public $data;	/**	 * The user's ID.	 *	 * @since 2.1.0	 * @var int	 */	public $ID = 0;	/**	 * The individual capabilities the user has been given.	 *	 * @since 2.0.0	 * @var array	 */	public $caps = array();	/**	 * User metadata option name.	 *	 * @since 2.0.0	 * @var string	 */	public $cap_key;	/**	 * The roles the user is part of.	 *	 * @since 2.0.0	 * @var array	 */	public $roles = array();	/**	 * All capabilities the user has, including individual and role based.	 *	 * @since 2.0.0	 * @var bool[] Array of key/value pairs where keys represent a capability name and boolean values	 *             represent whether the user has that capability.	 */	public $allcaps = array();	/**	 * The filter context applied to user data fields.	 *	 * @since 2.9.0	 * @var string	 */	public $filter = null;	/**	 * The site ID the capabilities of this user are initialized for.	 *	 * @since 4.9.0	 * @var int	 */	private $site_id = 0;	/**	 * @since 3.3.0	 * @var array	 */	private static $back_compat_keys;	/**	 * Constructor.	 *	 * Retrieves the userdata and passes it to WP_User::init().	 *	 * @since 2.0.0	 *	 * @param int|string|stdClass|WP_User $id User's ID, a WP_User object, or a user object from the DB.	 * @param string $name Optional. User's username	 * @param int $site_id Optional Site ID, defaults to current site.	 */	public function __construct( $id = 0, $name = '', $site_id = '' ) {		if ( ! isset( self::$back_compat_keys ) ) {			$prefix                 = $GLOBALS['wpdb']->prefix;			self::$back_compat_keys = array(				'user_firstname'             => 'first_name',				'user_lastname'              => 'last_name',				'user_description'           => 'description',				'user_level'                 => $prefix . 'user_level',				$prefix . 'usersettings'     => $prefix . 'user-settings',				$prefix . 'usersettingstime' => $prefix . 'user-settings-time',			);		}		if ( $id instanceof WP_User ) {			$this->init( $id->data, $site_id );			return;		} elseif ( is_object( $id ) ) {			$this->init( $id, $site_id );			return;		}		if ( ! empty( $id ) && ! is_numeric( $id ) ) {			$name = $id;			$id   = 0;		}		if ( $id ) {			$data = self::get_data_by( 'id', $id );		} else {			$data = self::get_data_by( 'login', $name );		}		if ( $data ) {			$this->init( $data, $site_id );		} else {			$this->data = new stdClass;		}	}	/**	 * Sets up object properties, including capabilities.	 *	 * @since  3.3.0	 *	 * @param object $data    User DB row object.	 * @param int    $site_id Optional. The site ID to initialize for.	 */	public function init( $data, $site_id = '' ) {		$this->data = $data;		$this->ID   = (int) $data->ID;		$this->for_site( $site_id );	}	/**	 * Return only the main user fields	 *	 * @since 3.3.0	 * @since 4.4.0 Added 'ID' as an alias of 'id' for the `$field` parameter.	 *	 * @global wpdb $wpdb WordPress database abstraction object.	 *	 * @param string $field The field to query against: 'id', 'ID', 'slug', 'email' or 'login'.	 * @param string|int $value The field value	 * @return object|false Raw user object	 */	public static function get_data_by( $field, $value ) {		global $wpdb;		// 'ID' is an alias of 'id'.		if ( 'ID' === $field ) {			$field = 'id';		}		if ( 'id' == $field ) {			// Make sure the value is numeric to avoid casting objects, for example,			// to int 1.			if ( ! is_numeric( $value ) ) {				return false;			}			$value = intval( $value );			if ( $value < 1 ) {				return false;			}		} else {			$value = trim( $value );		}		if ( ! $value ) {			return false;		}		switch ( $field ) {			case 'id':				$user_id  = $value;				$db_field = 'ID';				break;			case 'slug':				$user_id  = wp_cache_get( $value, 'userslugs' );				$db_field = 'user_nicename';				break;			case 'email':				$user_id  = wp_cache_get( $value, 'useremail' );				$db_field = 'user_email';				break;			case 'login':				$value    = sanitize_user( $value );				$user_id  = wp_cache_get( $value, 'userlogins' );				$db_field = 'user_login';				break;			default:				return false;		}		if ( false !== $user_id ) {			$user = wp_cache_get( $user_id, 'users' );			if ( $user ) {				return $user;			}		}		$user = $wpdb->get_row(			$wpdb->prepare(				"SELECT * FROM $wpdb->users WHERE $db_field = %s LIMIT 1",				$value			)		);		if ( ! $user ) {			return false;		}		update_user_caches( $user );		return $user;	}	/**	 * Magic method for checking the existence of a certain custom field.	 *	 * @since 3.3.0	 *	 * @param string $key User meta key to check if set.	 * @return bool Whether the given user meta key is set.	 */	public function __isset( $key ) {		if ( 'id' == $key ) {			_deprecated_argument(				'WP_User->id',				'2.1.0',				sprintf(					/* translators: %s: WP_User->ID */					__( 'Use %s instead.' ),					'<code>WP_User->ID</code>'				)			);			$key = 'ID';		}		if ( isset( $this->data->$key ) ) {			return true;		}		if ( isset( self::$back_compat_keys[ $key ] ) ) {			$key = self::$back_compat_keys[ $key ];		}		return metadata_exists( 'user', $this->ID, $key );	}	/**	 * Magic method for accessing custom fields.	 *	 * @since 3.3.0	 *	 * @param string $key User meta key to retrieve.	 * @return mixed Value of the given user meta key (if set). If `$key` is 'id', the user ID.	 */	public function __get( $key ) {		if ( 'id' == $key ) {			_deprecated_argument(				'WP_User->id',				'2.1.0',				sprintf(					/* translators: %s: WP_User->ID */					__( 'Use %s instead.' ),					'<code>WP_User->ID</code>'				)			);			return $this->ID;		}		if ( isset( $this->data->$key ) ) {			$value = $this->data->$key;		} else {			if ( isset( self::$back_compat_keys[ $key ] ) ) {				$key = self::$back_compat_keys[ $key ];			}			$value = get_user_meta( $this->ID, $key, true );		}		if ( $this->filter ) {			$value = sanitize_user_field( $key, $value, $this->ID, $this->filter );		}		return $value;	}	/**	 * Magic method for setting custom user fields.	 *	 * This method does not update custom fields in the database. It only stores	 * the value on the WP_User instance.	 *	 * @since 3.3.0	 *	 * @param string $key   User meta key.	 * @param mixed  $value User meta value.	 */	public function __set( $key, $value ) {		if ( 'id' == $key ) {			_deprecated_argument(				'WP_User->id',				'2.1.0',				sprintf(					/* translators: %s: WP_User->ID */					__( 'Use %s instead.' ),					'<code>WP_User->ID</code>'				)			);			$this->ID = $value;			return;		}		$this->data->$key = $value;	}	/**	 * Magic method for unsetting a certain custom field.	 *	 * @since 4.4.0	 *	 * @param string $key User meta key to unset.	 */	public function __unset( $key ) {		if ( 'id' == $key ) {			_deprecated_argument(				'WP_User->id',				'2.1.0',				sprintf(					/* translators: %s: WP_User->ID */					__( 'Use %s instead.' ),					'<code>WP_User->ID</code>'				)			);		}		if ( isset( $this->data->$key ) ) {			unset( $this->data->$key );		}		if ( isset( self::$back_compat_keys[ $key ] ) ) {			unset( self::$back_compat_keys[ $key ] );		}	}	/**	 * Determine whether the user exists in the database.	 *	 * @since 3.4.0	 *	 * @return bool True if user exists in the database, false if not.	 */	public function exists() {		return ! empty( $this->ID );	}	/**	 * Retrieve the value of a property or meta key.	 *	 * Retrieves from the users and usermeta table.	 *	 * @since 3.3.0	 *	 * @param string $key Property	 * @return mixed	 */	public function get( $key ) {		return $this->__get( $key );	}	/**	 * Determine whether a property or meta key is set	 *	 * Consults the users and usermeta tables.	 *	 * @since 3.3.0	 *	 * @param string $key Property	 * @return bool	 */	public function has_prop( $key ) {		return $this->__isset( $key );	}	/**	 * Return an array representation.	 *	 * @since 3.5.0	 *	 * @return array Array representation.	 */	public function to_array() {		return get_object_vars( $this->data );	}	/**	 * Makes private/protected methods readable for backward compatibility.	 *	 * @since 4.3.0	 *	 * @param string   $name      Method to call.	 * @param array    $arguments Arguments to pass when calling.	 * @return mixed|false Return value of the callback, false otherwise.	 */	public function __call( $name, $arguments ) {		if ( '_init_caps' === $name ) {			return $this->_init_caps( ...$arguments );		}		return false;	}	/**	 * Set up capability object properties.	 *	 * Will set the value for the 'cap_key' property to current database table	 * prefix, followed by 'capabilities'. Will then check to see if the	 * property matching the 'cap_key' exists and is an array. If so, it will be	 * used.	 *	 * @since 2.1.0	 * @deprecated 4.9.0 Use WP_User::for_site()	 *	 * @global wpdb $wpdb WordPress database abstraction object.	 *	 * @param string $cap_key Optional capability key	 */	protected function _init_caps( $cap_key = '' ) {		global $wpdb;		_deprecated_function( __METHOD__, '4.9.0', 'WP_User::for_site()' );		if ( empty( $cap_key ) ) {			$this->cap_key = $wpdb->get_blog_prefix( $this->site_id ) . 'capabilities';		} else {			$this->cap_key = $cap_key;		}		$this->caps = $this->get_caps_data();		$this->get_role_caps();	}	/**	 * Retrieves all of the capabilities of the roles of the user, and merges them with individual user capabilities.	 *	 * All of the capabilities of the roles of the user are merged with the user's individual capabilities. This means	 * that the user can be denied specific capabilities that their role might have, but the user is specifically denied.	 *	 * @since 2.0.0	 *	 * @return bool[] Array of key/value pairs where keys represent a capability name and boolean values	 *                represent whether the user has that capability.	 */	public function get_role_caps() {		$switch_site = false;		if ( is_multisite() && $this->site_id != get_current_blog_id() ) {			$switch_site = true;			switch_to_blog( $this->site_id );		}		$wp_roles = wp_roles();		// Filter out caps that are not role names and assign to $this->roles.		if ( is_array( $this->caps ) ) {			$this->roles = array_filter( array_keys( $this->caps ), array( $wp_roles, 'is_role' ) );		}		// Build $allcaps from role caps, overlay user's $caps.		$this->allcaps = array();		foreach ( (array) $this->roles as $role ) {			$the_role      = $wp_roles->get_role( $role );			$this->allcaps = array_merge( (array) $this->allcaps, (array) $the_role->capabilities );		}		$this->allcaps = array_merge( (array) $this->allcaps, (array) $this->caps );		if ( $switch_site ) {			restore_current_blog();		}		return $this->allcaps;	}	/**	 * Add role to user.	 *	 * Updates the user's meta data option with capabilities and roles.	 *	 * @since 2.0.0	 *	 * @param string $role Role name.	 */	public function add_role( $role ) {		if ( empty( $role ) ) {			return;		}		$this->caps[ $role ] = true;		update_user_meta( $this->ID, $this->cap_key, $this->caps );		$this->get_role_caps();		$this->update_user_level_from_caps();		/**		 * Fires immediately after the user has been given a new role.		 *		 * @since 4.3.0		 *		 * @param int    $user_id The user ID.		 * @param string $role    The new role.		 */		do_action( 'add_user_role', $this->ID, $role );	}	/**	 * Remove role from user.	 *	 * @since 2.0.0	 *	 * @param string $role Role name.	 */	public function remove_role( $role ) {		if ( ! in_array( $role, $this->roles ) ) {			return;		}		unset( $this->caps[ $role ] );		update_user_meta( $this->ID, $this->cap_key, $this->caps );		$this->get_role_caps();		$this->update_user_level_from_caps();		/**		 * Fires immediately after a role as been removed from a user.		 *		 * @since 4.3.0		 *		 * @param int    $user_id The user ID.		 * @param string $role    The removed role.		 */		do_action( 'remove_user_role', $this->ID, $role );	}	/**	 * Set the role of the user.	 *	 * This will remove the previous roles of the user and assign the user the	 * new one. You can set the role to an empty string and it will remove all	 * of the roles from the user.	 *	 * @since 2.0.0	 *	 * @param string $role Role name.	 */	public function set_role( $role ) {		if ( 1 == count( $this->roles ) && $role == current( $this->roles ) ) {			return;		}		foreach ( (array) $this->roles as $oldrole ) {			unset( $this->caps[ $oldrole ] );		}		$old_roles = $this->roles;		if ( ! empty( $role ) ) {			$this->caps[ $role ] = true;			$this->roles         = array( $role => true );		} else {			$this->roles = false;		}		update_user_meta( $this->ID, $this->cap_key, $this->caps );		$this->get_role_caps();		$this->update_user_level_from_caps();		/**		 * Fires after the user's role has changed.		 *		 * @since 2.9.0		 * @since 3.6.0 Added $old_roles to include an array of the user's previous roles.		 *		 * @param int      $user_id   The user ID.		 * @param string   $role      The new role.		 * @param string[] $old_roles An array of the user's previous roles.		 */		do_action( 'set_user_role', $this->ID, $role, $old_roles );	}	/**	 * Choose the maximum level the user has.	 *	 * Will compare the level from the $item parameter against the $max	 * parameter. If the item is incorrect, then just the $max parameter value	 * will be returned.	 *	 * Used to get the max level based on the capabilities the user has. This	 * is also based on roles, so if the user is assigned the Administrator role	 * then the capability 'level_10' will exist and the user will get that	 * value.	 *	 * @since 2.0.0	 *	 * @param int $max Max level of user.	 * @param string $item Level capability name.	 * @return int Max Level.	 */	public function level_reduction( $max, $item ) {		if ( preg_match( '/^level_(10|[0-9])$/i', $item, $matches ) ) {			$level = intval( $matches[1] );			return max( $max, $level );		} else {			return $max;		}	}	/**	 * Update the maximum user level for the user.	 *	 * Updates the 'user_level' user metadata (includes prefix that is the	 * database table prefix) with the maximum user level. Gets the value from	 * the all of the capabilities that the user has.	 *	 * @since 2.0.0	 *	 * @global wpdb $wpdb WordPress database abstraction object.	 */	public function update_user_level_from_caps() {		global $wpdb;		$this->user_level = array_reduce( array_keys( $this->allcaps ), array( $this, 'level_reduction' ), 0 );		update_user_meta( $this->ID, $wpdb->get_blog_prefix() . 'user_level', $this->user_level );	}	/**	 * Add capability and grant or deny access to capability.	 *	 * @since 2.0.0	 *	 * @param string $cap Capability name.	 * @param bool $grant Whether to grant capability to user.	 */	public function add_cap( $cap, $grant = true ) {		$this->caps[ $cap ] = $grant;		update_user_meta( $this->ID, $this->cap_key, $this->caps );		$this->get_role_caps();		$this->update_user_level_from_caps();	}	/**	 * Remove capability from user.	 *	 * @since 2.0.0	 *	 * @param string $cap Capability name.	 */	public function remove_cap( $cap ) {		if ( ! isset( $this->caps[ $cap ] ) ) {			return;		}		unset( $this->caps[ $cap ] );		update_user_meta( $this->ID, $this->cap_key, $this->caps );		$this->get_role_caps();		$this->update_user_level_from_caps();	}	/**	 * Remove all of the capabilities of the user.	 *	 * @since 2.1.0	 *	 * @global wpdb $wpdb WordPress database abstraction object.	 */	public function remove_all_caps() {		global $wpdb;		$this->caps = array();		delete_user_meta( $this->ID, $this->cap_key );		delete_user_meta( $this->ID, $wpdb->get_blog_prefix() . 'user_level' );		$this->get_role_caps();	}	/**	 * Returns whether the user has the specified capability.	 *	 * This function also accepts an ID of an object to check against if the capability is a meta capability. Meta	 * capabilities such as `edit_post` and `edit_user` are capabilities used by the `map_meta_cap()` function to	 * map to primitive capabilities that a user or role has, such as `edit_posts` and `edit_others_posts`.	 *	 * Example usage:	 *	 *     $user->has_cap( 'edit_posts' );	 *     $user->has_cap( 'edit_post', $post->ID );	 *     $user->has_cap( 'edit_post_meta', $post->ID, $meta_key );	 *	 * While checking against a role in place of a capability is supported in part, this practice is discouraged as it	 * may produce unreliable results.	 *	 * @since 2.0.0	 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter	 *              by adding it to the function signature.	 *	 * @see map_meta_cap()	 *	 * @param string $cap     Capability name.	 * @param mixed  ...$args Optional further parameters, typically starting with an object ID.	 * @return bool Whether the user has the given capability, or, if an object ID is passed, whether the user has	 *              the given capability for that object.	 */	public function has_cap( $cap, ...$args ) {		if ( is_numeric( $cap ) ) {			_deprecated_argument( __FUNCTION__, '2.0.0', __( 'Usage of user levels is deprecated. Use capabilities instead.' ) );			$cap = $this->translate_level_to_cap( $cap );		}		$caps = map_meta_cap( $cap, $this->ID, ...$args );		// Multisite super admin has all caps by definition, Unless specifically denied.		if ( is_multisite() && is_super_admin( $this->ID ) ) {			if ( in_array( 'do_not_allow', $caps ) ) {				return false;			}			return true;		}		// Maintain BC for the argument passed to the "user_has_cap" filter.		$args = array_merge( array( $cap, $this->ID ), $args );		/**		 * Dynamically filter a user's capabilities.		 *		 * @since 2.0.0		 * @since 3.7.0 Added the `$user` parameter.		 *		 * @param bool[]   $allcaps Array of key/value pairs where keys represent a capability name and boolean values		 *                          represent whether the user has that capability.		 * @param string[] $caps    Required primitive capabilities for the requested capability.		 * @param array    $args {		 *     Arguments that accompany the requested capability check.		 *		 *     @type string    $0 Requested capability.		 *     @type int       $1 Concerned user ID.		 *     @type mixed  ...$2 Optional second and further parameters, typically object ID.		 * }		 * @param WP_User  $user    The user object.		 */		$capabilities = apply_filters( 'user_has_cap', $this->allcaps, $caps, $args, $this );		// Everyone is allowed to exist.		$capabilities['exist'] = true;		// Nobody is allowed to do things they are not allowed to do.		unset( $capabilities['do_not_allow'] );		// Must have ALL requested caps.		foreach ( (array) $caps as $cap ) {			if ( empty( $capabilities[ $cap ] ) ) {				return false;			}		}		return true;	}	/**	 * Convert numeric level to level capability name.	 *	 * Prepends 'level_' to level number.	 *	 * @since 2.0.0	 *	 * @param int $level Level number, 1 to 10.	 * @return string	 */	public function translate_level_to_cap( $level ) {		return 'level_' . $level;	}	/**	 * Set the site to operate on. Defaults to the current site.	 *	 * @since 3.0.0	 * @deprecated 4.9.0 Use WP_User::for_site()	 *	 * @param int $blog_id Optional. Site ID, defaults to current site.	 */	public function for_blog( $blog_id = '' ) {		_deprecated_function( __METHOD__, '4.9.0', 'WP_User::for_site()' );		$this->for_site( $blog_id );	}	/**	 * Sets the site to operate on. Defaults to the current site.	 *	 * @since 4.9.0	 *	 * @global wpdb $wpdb WordPress database abstraction object.	 *	 * @param int $site_id Site ID to initialize user capabilities for. Default is the current site.	 */	public function for_site( $site_id = '' ) {		global $wpdb;		if ( ! empty( $site_id ) ) {			$this->site_id = absint( $site_id );		} else {			$this->site_id = get_current_blog_id();		}		$this->cap_key = $wpdb->get_blog_prefix( $this->site_id ) . 'capabilities';		$this->caps = $this->get_caps_data();		$this->get_role_caps();	}	/**	 * Gets the ID of the site for which the user's capabilities are currently initialized.	 *	 * @since 4.9.0	 *	 * @return int Site ID.	 */	public function get_site_id() {		return $this->site_id;	}	/**	 * Gets the available user capabilities data.	 *	 * @since 4.9.0	 *	 * @return array User capabilities array.	 */	private function get_caps_data() {		$caps = get_user_meta( $this->ID, $this->cap_key, true );		if ( ! is_array( $caps ) ) {			return array();		}		return $caps;	}}
 |