class-wp-roles.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. <?php
  2. /**
  3. * User API: WP_Roles class
  4. *
  5. * @package WordPress
  6. * @subpackage Users
  7. * @since 4.4.0
  8. */
  9. /**
  10. * Core class used to implement a user roles API.
  11. *
  12. * The role option is simple, the structure is organized by role name that store
  13. * the name in value of the 'name' key. The capabilities are stored as an array
  14. * in the value of the 'capability' key.
  15. *
  16. * array (
  17. * 'rolename' => array (
  18. * 'name' => 'rolename',
  19. * 'capabilities' => array()
  20. * )
  21. * )
  22. *
  23. * @since 2.0.0
  24. */
  25. #[AllowDynamicProperties]
  26. class WP_Roles {
  27. /**
  28. * List of roles and capabilities.
  29. *
  30. * @since 2.0.0
  31. * @var array[]
  32. */
  33. public $roles;
  34. /**
  35. * List of the role objects.
  36. *
  37. * @since 2.0.0
  38. * @var WP_Role[]
  39. */
  40. public $role_objects = array();
  41. /**
  42. * List of role names.
  43. *
  44. * @since 2.0.0
  45. * @var string[]
  46. */
  47. public $role_names = array();
  48. /**
  49. * Option name for storing role list.
  50. *
  51. * @since 2.0.0
  52. * @var string
  53. */
  54. public $role_key;
  55. /**
  56. * Whether to use the database for retrieval and storage.
  57. *
  58. * @since 2.1.0
  59. * @var bool
  60. */
  61. public $use_db = true;
  62. /**
  63. * The site ID the roles are initialized for.
  64. *
  65. * @since 4.9.0
  66. * @var int
  67. */
  68. protected $site_id = 0;
  69. /**
  70. * Constructor.
  71. *
  72. * @since 2.0.0
  73. * @since 4.9.0 The `$site_id` argument was added.
  74. *
  75. * @global array $wp_user_roles Used to set the 'roles' property value.
  76. *
  77. * @param int $site_id Site ID to initialize roles for. Default is the current site.
  78. */
  79. public function __construct( $site_id = null ) {
  80. global $wp_user_roles;
  81. $this->use_db = empty( $wp_user_roles );
  82. $this->for_site( $site_id );
  83. }
  84. /**
  85. * Makes private/protected methods readable for backward compatibility.
  86. *
  87. * @since 4.0.0
  88. *
  89. * @param string $name Method to call.
  90. * @param array $arguments Arguments to pass when calling.
  91. * @return mixed|false Return value of the callback, false otherwise.
  92. */
  93. public function __call( $name, $arguments ) {
  94. if ( '_init' === $name ) {
  95. return $this->_init( ...$arguments );
  96. }
  97. return false;
  98. }
  99. /**
  100. * Sets up the object properties.
  101. *
  102. * The role key is set to the current prefix for the $wpdb object with
  103. * 'user_roles' appended. If the $wp_user_roles global is set, then it will
  104. * be used and the role option will not be updated or used.
  105. *
  106. * @since 2.1.0
  107. * @deprecated 4.9.0 Use WP_Roles::for_site()
  108. */
  109. protected function _init() {
  110. _deprecated_function( __METHOD__, '4.9.0', 'WP_Roles::for_site()' );
  111. $this->for_site();
  112. }
  113. /**
  114. * Reinitializes the object.
  115. *
  116. * Recreates the role objects. This is typically called only by switch_to_blog()
  117. * after switching wpdb to a new site ID.
  118. *
  119. * @since 3.5.0
  120. * @deprecated 4.7.0 Use WP_Roles::for_site()
  121. */
  122. public function reinit() {
  123. _deprecated_function( __METHOD__, '4.7.0', 'WP_Roles::for_site()' );
  124. $this->for_site();
  125. }
  126. /**
  127. * Adds a role name with capabilities to the list.
  128. *
  129. * Updates the list of roles, if the role doesn't already exist.
  130. *
  131. * The capabilities are defined in the following format: `array( 'read' => true )`.
  132. * To explicitly deny the role a capability, set the value for that capability to false.
  133. *
  134. * @since 2.0.0
  135. *
  136. * @param string $role Role name.
  137. * @param string $display_name Role display name.
  138. * @param bool[] $capabilities Optional. List of capabilities keyed by the capability name,
  139. * e.g. `array( 'edit_posts' => true, 'delete_posts' => false )`.
  140. * Default empty array.
  141. * @return WP_Role|void WP_Role object, if the role is added.
  142. */
  143. public function add_role( $role, $display_name, $capabilities = array() ) {
  144. if ( empty( $role ) || isset( $this->roles[ $role ] ) ) {
  145. return;
  146. }
  147. $this->roles[ $role ] = array(
  148. 'name' => $display_name,
  149. 'capabilities' => $capabilities,
  150. );
  151. if ( $this->use_db ) {
  152. update_option( $this->role_key, $this->roles );
  153. }
  154. $this->role_objects[ $role ] = new WP_Role( $role, $capabilities );
  155. $this->role_names[ $role ] = $display_name;
  156. return $this->role_objects[ $role ];
  157. }
  158. /**
  159. * Removes a role by name.
  160. *
  161. * @since 2.0.0
  162. *
  163. * @param string $role Role name.
  164. */
  165. public function remove_role( $role ) {
  166. if ( ! isset( $this->role_objects[ $role ] ) ) {
  167. return;
  168. }
  169. unset( $this->role_objects[ $role ] );
  170. unset( $this->role_names[ $role ] );
  171. unset( $this->roles[ $role ] );
  172. if ( $this->use_db ) {
  173. update_option( $this->role_key, $this->roles );
  174. }
  175. if ( get_option( 'default_role' ) == $role ) {
  176. update_option( 'default_role', 'subscriber' );
  177. }
  178. }
  179. /**
  180. * Adds a capability to role.
  181. *
  182. * @since 2.0.0
  183. *
  184. * @param string $role Role name.
  185. * @param string $cap Capability name.
  186. * @param bool $grant Optional. Whether role is capable of performing capability.
  187. * Default true.
  188. */
  189. public function add_cap( $role, $cap, $grant = true ) {
  190. if ( ! isset( $this->roles[ $role ] ) ) {
  191. return;
  192. }
  193. $this->roles[ $role ]['capabilities'][ $cap ] = $grant;
  194. if ( $this->use_db ) {
  195. update_option( $this->role_key, $this->roles );
  196. }
  197. }
  198. /**
  199. * Removes a capability from role.
  200. *
  201. * @since 2.0.0
  202. *
  203. * @param string $role Role name.
  204. * @param string $cap Capability name.
  205. */
  206. public function remove_cap( $role, $cap ) {
  207. if ( ! isset( $this->roles[ $role ] ) ) {
  208. return;
  209. }
  210. unset( $this->roles[ $role ]['capabilities'][ $cap ] );
  211. if ( $this->use_db ) {
  212. update_option( $this->role_key, $this->roles );
  213. }
  214. }
  215. /**
  216. * Retrieves a role object by name.
  217. *
  218. * @since 2.0.0
  219. *
  220. * @param string $role Role name.
  221. * @return WP_Role|null WP_Role object if found, null if the role does not exist.
  222. */
  223. public function get_role( $role ) {
  224. if ( isset( $this->role_objects[ $role ] ) ) {
  225. return $this->role_objects[ $role ];
  226. } else {
  227. return null;
  228. }
  229. }
  230. /**
  231. * Retrieves a list of role names.
  232. *
  233. * @since 2.0.0
  234. *
  235. * @return string[] List of role names.
  236. */
  237. public function get_names() {
  238. return $this->role_names;
  239. }
  240. /**
  241. * Determines whether a role name is currently in the list of available roles.
  242. *
  243. * @since 2.0.0
  244. *
  245. * @param string $role Role name to look up.
  246. * @return bool
  247. */
  248. public function is_role( $role ) {
  249. return isset( $this->role_names[ $role ] );
  250. }
  251. /**
  252. * Initializes all of the available roles.
  253. *
  254. * @since 4.9.0
  255. */
  256. public function init_roles() {
  257. if ( empty( $this->roles ) ) {
  258. return;
  259. }
  260. $this->role_objects = array();
  261. $this->role_names = array();
  262. foreach ( array_keys( $this->roles ) as $role ) {
  263. $this->role_objects[ $role ] = new WP_Role( $role, $this->roles[ $role ]['capabilities'] );
  264. $this->role_names[ $role ] = $this->roles[ $role ]['name'];
  265. }
  266. /**
  267. * Fires after the roles have been initialized, allowing plugins to add their own roles.
  268. *
  269. * @since 4.7.0
  270. *
  271. * @param WP_Roles $wp_roles A reference to the WP_Roles object.
  272. */
  273. do_action( 'wp_roles_init', $this );
  274. }
  275. /**
  276. * Sets the site to operate on. Defaults to the current site.
  277. *
  278. * @since 4.9.0
  279. *
  280. * @global wpdb $wpdb WordPress database abstraction object.
  281. *
  282. * @param int $site_id Site ID to initialize roles for. Default is the current site.
  283. */
  284. public function for_site( $site_id = null ) {
  285. global $wpdb;
  286. if ( ! empty( $site_id ) ) {
  287. $this->site_id = absint( $site_id );
  288. } else {
  289. $this->site_id = get_current_blog_id();
  290. }
  291. $this->role_key = $wpdb->get_blog_prefix( $this->site_id ) . 'user_roles';
  292. if ( ! empty( $this->roles ) && ! $this->use_db ) {
  293. return;
  294. }
  295. $this->roles = $this->get_roles_data();
  296. $this->init_roles();
  297. }
  298. /**
  299. * Gets the ID of the site for which roles are currently initialized.
  300. *
  301. * @since 4.9.0
  302. *
  303. * @return int Site ID.
  304. */
  305. public function get_site_id() {
  306. return $this->site_id;
  307. }
  308. /**
  309. * Gets the available roles data.
  310. *
  311. * @since 4.9.0
  312. *
  313. * @global array $wp_user_roles Used to set the 'roles' property value.
  314. *
  315. * @return array Roles array.
  316. */
  317. protected function get_roles_data() {
  318. global $wp_user_roles;
  319. if ( ! empty( $wp_user_roles ) ) {
  320. return $wp_user_roles;
  321. }
  322. if ( is_multisite() && get_current_blog_id() != $this->site_id ) {
  323. remove_action( 'switch_blog', 'wp_switch_roles_and_user', 1 );
  324. $roles = get_blog_option( $this->site_id, $this->role_key, array() );
  325. add_action( 'switch_blog', 'wp_switch_roles_and_user', 1, 2 );
  326. return $roles;
  327. }
  328. return get_option( $this->role_key, array() );
  329. }
  330. }