/** * @return array|mixed */ static function role_classes() { if (!($role_classes = WPLib::cache_get($cache_key = 'role_classes'))) { WPLib::autoload_all_classes(); $role_classes = array(); foreach (get_declared_classes() as $user_class) { if (!is_subclass_of($user_class, 'WPLib_User_Base')) { continue; } if ($role_slug = self::get_role_slug_by('class', $user_class)) { $role_classes[$role_slug] = $user_class; } } WPLib::cache_set($cache_key, $role_classes); } return $role_classes; }
/** * Return the list of classes declared after WPLib first loads. * @return array */ static function site_classes() { if (!($site_classes = WPLib::cache_get($cache_key = 'site_classes'))) { /** * Make sure we have all classes loaded. */ WPLib::autoload_all_classes(); $site_classes = array_reverse(array_slice(get_declared_classes(), self::$_non_app_class_count)); $site_classes = array_filter($site_classes, function ($element) { /* * Strip out WordPress core classes */ return !preg_match('#^(WP|wp)_?#', $element); }); WPLib::cache_set($cache_key, $site_classes); } return $site_classes; }
/** * Runs through all the registered roles and ensures that all roles and get_capabilities * are set as defined in the classes. * * @param string $recent_commit * @param string $previous_commit */ private static function _initialize_roles($recent_commit, $previous_commit) { WPLib::autoload_all_classes(); $app_slug = strtolower(WPLib::app_class()); $option = get_option($option_name = "{$app_slug}_roles", array()); $wp_roles = new WP_Roles(); $dirty = false; foreach (self::$_roles as $role_slug => $role) { if (preg_match('#^WPLib_(Administrators|Editors|Contributors|Subscribers|Authors)$#', $role['class_name'])) { /* * Easier just to punt on these for right now. * WordPress does some weird things with built-in roles, * especially with Administrator related to Multisite */ continue; } if (empty($role_slug)) { /* * Somehow we got an empty role slug?!?. Carry on. */ continue; } $capabilities = call_user_func(array($role['class_name'], 'capabilities')); if (!isset($option[$role_slug])) { $option[$role_slug] = array('prior_capabilities' => $capabilities, 'recent_commit' => $recent_commit, 'previous_commit' => $previous_commit); $dirty = true; } $display_name = self::get_role_display_name($role_slug); $prior_capabilities = $option[$role_slug]['prior_capabilities']; /* * Get the capabilities */ if (is_null($current_capabilities = $wp_roles->role_objects[$role_slug]->capabilities)) { $current_capabilities = array(); } else { /** * Remove all the legacy level_0 through level_10 capabilities. */ for ($i = 0; $i <= 10; $i++) { unset($current_capabilities["level_{$i}"]); } } if (empty($prior_capabilities)) { /** * First time in, let's assume previous are same as current. */ $prior_capabilities = $current_capabilities; } /** * Filter the capabilities that should be applied for the role. * * @since 0.11.0 * * @param string[] $capabilities * @param string $role_slug { * @param array $role { * An array of information about the role as assigned in self::register_role(). * * @type string $display_name Title used to display the role to users. * @type string[] $capabilities Array of capabilities that should be assigned to the role. * @type string $class_name Name of class defining the role that inherits from WPLib_Role_Module_Base. * } */ $capabilities = apply_filters('wplib_role_capabilities', $capabilities, $role_slug, $role); $capabilities = array_fill_keys($capabilities, true); if (defined('WPLIB_UPDATE_ROLES') && WPLIB_UPDATE_ROLES) { $change_role = true; } else { if (!isset($wp_roles->roles[$role_slug])) { /* * Whelp, the role does not exists, so let's add it. */ $change_role = true; } else { if (isset($merged) || !self::_arrays_are_equivalent($capabilities, $current_capabilities)) { /* * The new capabilities are different than the current ones, AND * nobody changed the capabilities since we last updated them. * * This stops manually changed capabilities from being overwritten * at the expense of not containing new capabilities defined in the * code. Better to respect the user's efforts and add a burden on * them then to ignore the user's efforts and simply reset. */ $change_role = self::_arrays_are_equivalent($current_capabilities, $prior_capabilities); } else { if ($display_name !== $wp_roles->role_names[$role_slug]) { /* * The display name has changed so let's update the role. */ $change_role = true; } else { if ($display_name !== $wp_roles->role_names[$role_slug]) { /* * Does not seem there is a reason to change. */ $change_role = false; } else { /* * Bah. Don't change it. No evidence we need to. */ $change_role = false; } } } } } if ($change_role) { /** * @note: Just FYI, this will remove the legacy get_capabilities of level_0..level_10. * @note: Should not be an issue for a modern WP app. If it becomes an issue we can test for them too. */ remove_role($role_slug); call_user_func($role_slug, $display_name, $capabilities); $option[$role_slug] = array('prior_capabilities' => $capabilities, 'recent_commit' => $recent_commit, 'previous_commit' => $previous_commit); $dirty = true; } } self::$_roles = array(); if ($dirty) { update_option($option_name, $option, 'no'); /** * @future Change this to redirect to the same URL they were on * Which means adding something like WPLib::current_url(). * Maybe even a WPLib::redirect_to_self(). * But I want to sleep on that a few days first. */ wp_safe_redirect(home_url('/')); exit; } }
/** * Returns array of class names $base_class children with positive values for $base_class::$contant_name. * * @param $base_class * * @param $constant_name * * @return string[] */ static function get_child_classes($base_class, $constant_name) { $cache_key = "classes[{$base_class}::{$constant_name}]"; if (!WPLib::is_development()) { $cache_key = md5($cache_key); } if (!($child_classes = self::cache_get($cache_key))) { WPLib::autoload_all_classes(); $child_classes = array(); foreach (self::site_classes() as $class_name) { do { if (!is_subclass_of($class_name, $base_class)) { continue; } if (is_null($constant_value = self::get_constant($constant_name, $class_name))) { continue; } $child_classes[$constant_value] = $class_name; } while (false); } self::cache_set($cache_key, $child_classes); } return $child_classes; }