| | |
| | | <?php |
| | | namespace JVBase\managers; |
| | | |
| | | use JVBase\utility\Features; |
| | | use JVBase\registrar\Registrar; |
| | | use JVBase\base\Site; |
| | | use WP_User; |
| | | use WP_Role; |
| | | |
| | |
| | | { |
| | | private array $roles; |
| | | private array $content; |
| | | private array $subTypes = []; |
| | | |
| | | public function __construct() |
| | | { |
| | | $this->roles = array_keys(JVB_USER); |
| | | $this->roles = Registrar::getRegistered('user'); |
| | | |
| | | $this->content = array_map(function($content) { |
| | | return strtolower($content['plural']); |
| | | },JVB_CONTENT); |
| | | $registrar = Registrar::getInstance($content); |
| | | return strtolower(str_replace(' ', '_', $registrar->getPlural()??$registrar->getSingular().'s')); |
| | | },array_merge( |
| | | Registrar::getRegistered('post'), |
| | | Registrar::withFeature('is_content', 'term') |
| | | )); |
| | | add_action('set_user_role', [$this, 'updateRoles'], 10, 3); |
| | | |
| | | $this->checkRoleSubTypes(); |
| | | } |
| | | |
| | | public function checkRoleSubTypes():void |
| | | { |
| | | foreach ($this->roles as $role) { |
| | | $registrar = Registrar::getInstance($role); |
| | | if ($registrar->getUserSubtype()){ |
| | | $this->subTypes[jvbCheckBase($registrar->getUserSubtype())] = $registrar->getCreatable(); |
| | | } |
| | | } |
| | | if (!empty($this->subTypes)) { |
| | | add_action('set_object_terms', [$this, 'maybeSwitchPermissions'],10, 6); |
| | | } |
| | | } |
| | | |
| | | public function updateRoles(int $userID, string $role, array $oldRoles):void |
| | | { |
| | | if (doing_action('set_user_role') > 1) { |
| | | return; |
| | | } |
| | | $temp = jvbNoBase($role); |
| | | if (array_key_exists($temp, JVB_USER)) { |
| | | $registrar = Registrar::getInstance($temp); |
| | | if ($registrar) { |
| | | $user = get_userdata($userID); |
| | | if (!$user) { |
| | | return; |
| | |
| | | { |
| | | $type = jvbNoBase($type); |
| | | |
| | | // Check in JVB_CONTENT array |
| | | if (array_key_exists($type, JVB_CONTENT)) { |
| | | $registrar = Registrar::getInstance($type); |
| | | if ($registrar && $registrar->getType() === 'post') { |
| | | return true; |
| | | } |
| | | |
| | | // Check in JVB_TAXONOMY for content taxonomies |
| | | if (array_key_exists($type, JVB_TAXONOMY)) { |
| | | $tax_config = JVB_TAXONOMY[$type]; |
| | | if ($tax_config['is_content'] ?? false) { |
| | | return true; |
| | | } |
| | | if ($registrar && $registrar->getType() === 'term' && $registrar->hasFeature('is_content')) { |
| | | return true; |
| | | } |
| | | |
| | | return false; |
| | |
| | | $roles = array_keys($user->roles); |
| | | |
| | | foreach ($roles as $role) { |
| | | $role = jvbNoBase($role); |
| | | $config = JVB_USER[$role]??false; |
| | | if (!$config) { |
| | | $registrar = Registrar::getInstance($role); |
| | | if (!$registrar) { |
| | | return false; |
| | | } |
| | | foreach ($config as $type) { |
| | | foreach ($registrar->getCreatable() as $type) { |
| | | if (is_array($type) && in_array($content, $type)) { |
| | | return true; |
| | | } elseif ($content === $type) { |
| | |
| | | if ($check) { |
| | | return $check; |
| | | } |
| | | $check = JVB_USER[$role]['can_create'] ??false; |
| | | if (!$check) { |
| | | |
| | | $registrar = Registrar::getInstance($role); |
| | | if (!$registrar) { |
| | | return false; |
| | | } |
| | | $out = []; |
| | | foreach ($check as $types) { |
| | | foreach ($types as $type => $content) { |
| | | $out[$type] = $content; |
| | | foreach ($registrar->getCreatable() as $types) { |
| | | if (is_array($types)) { |
| | | $out = array_merge($out, $types); |
| | | } else { |
| | | $out = [$types]; |
| | | } |
| | | $out = array_unique($out); |
| | | } |
| | | set_transient(BASE.'role_config_'.$role, $out, MONTH_IN_SECONDS); |
| | | return $out; |
| | |
| | | if (!in_array($type, $this->roles)) { |
| | | return false; |
| | | } |
| | | $link = get_user_meta($user->ID, BASE.'link', true); |
| | | $link = get_user_meta($user->ID, BASE.'profile_link', true); |
| | | if ($link === '') { |
| | | $type = BASE.$type; |
| | | $name = $user->display_name; |
| | |
| | | 'post_author' => $user->ID, |
| | | ]); |
| | | if ($link) { |
| | | update_user_meta($user->ID, BASE.'link', $link); |
| | | update_post_meta($link, BASE.'link', $user->ID); |
| | | update_user_meta($user->ID, BASE.'profile_link', $link); |
| | | update_post_meta($link, BASE.'profile_link', $user->ID); |
| | | } |
| | | } |
| | | return $link; |
| | | } |
| | | |
| | | public function registerRole(string $slug, array $config): void |
| | | public function registerRole(string $slug): void |
| | | { |
| | | $role_name = BASE . $slug; |
| | | $display_name = $config['label'] ?? ucfirst($slug); |
| | | |
| | | $registrar = Registrar::getInstance($slug); |
| | | if (!$registrar){ |
| | | return; |
| | | } |
| | | // Build capabilities for this role |
| | | $capabilities = $this->buildRoleCapabilities($slug, $config); |
| | | $capabilities = $this->buildRoleCapabilities($slug, $registrar); |
| | | |
| | | // Remove role first to ensure clean slate |
| | | remove_role($role_name); |
| | |
| | | add_role($role_name, $display_name, $capabilities); |
| | | |
| | | // Add management capabilities to administrator |
| | | if ($config['has_dashboard'] ?? false) { |
| | | if ($registrar->hasFeature('has_dashboard') ?? false) { |
| | | $admin_role = get_role('administrator'); |
| | | if ($admin_role) { |
| | | $admin_role->add_cap("manage_{$role_name}s", true); |
| | | $admin_role->add_cap("edit_{$role_name}_settings", true); |
| | | $admin_role->add_cap("manage_{$role_name}s"); |
| | | $admin_role->add_cap("edit_{$role_name}_settings"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private function buildRoleCapabilities(string $slug, array $config): array |
| | | private function buildRoleCapabilities(string $slug, Registrar $registrar): array |
| | | { |
| | | //Everyone can see the things |
| | | $capabilities = [ |
| | |
| | | ]; |
| | | |
| | | // Dashboard access |
| | | if ($this->config['has_dashboard'] ?? false) { |
| | | if ($registrar->hasFeature('has_dashboard') ?? false) { |
| | | $capabilities['access_dashboard'] = true; |
| | | } |
| | | |
| | | if (Features::forSite()->has('favourites') && $config['can_favourite'] ?? true) { |
| | | if (Site::has('favourites') && $registrar->hasFeature('can_favourite') ?? true) { |
| | | $capabilities['can_favourite'] = true; |
| | | } |
| | | |
| | | // Content creation capabilities |
| | | if (!empty($config['can_create'])) { |
| | | foreach ($config['can_create'] as $content_type) { |
| | | $this->addContentCapabilities($capabilities, $content_type, $config); |
| | | if (!empty($registrar->getCreatable())) { |
| | | $content = []; |
| | | foreach ($registrar->getCreatable() as $content_type) { |
| | | if (is_array($content_type)) { |
| | | $content = array_merge($content, $content_type); |
| | | }else { |
| | | $content[] = $content_type; |
| | | } |
| | | } |
| | | foreach ($content as $c) { |
| | | $this->addContentCapabilities($capabilities, $c, $registrar); |
| | | } |
| | | } |
| | | |
| | | // Management capabilities |
| | | if (!empty($this->config['manage_others'])) { |
| | | foreach ($this->config['manage_others'] as $type) { |
| | | if (!empty($registrar->getManageOthers())) { |
| | | foreach ($registrar->getManageOthers() as $type) { |
| | | // Skip if content type doesn't exist |
| | | if (!$this->isValidContentType($type)) { |
| | | error_log("Warning: User role '{$slug}' references non-existent content type '{$type}'"); |
| | |
| | | /** |
| | | * Add content capabilities to capability array |
| | | */ |
| | | private function addContentCapabilities(array &$capabilities, $content_type, array $config): void |
| | | private function addContentCapabilities(array &$capabilities, $content_type, Registrar $registrar): void |
| | | { |
| | | if (is_array($content_type)) { |
| | | // Handle array format for type-specific permissions |
| | | foreach ($content_type as $sub_type => $types) { |
| | | foreach ($types as $type) { |
| | | if (!$this->isValidContentType($type)) { |
| | | error_log("Warning: Role references non-existent content type '{$type}'"); |
| | | continue; |
| | | } |
| | | $this->addSingleContentCapabilities($capabilities, $type, $config); |
| | | } |
| | | } |
| | | } else { |
| | | if (!$this->isValidContentType($content_type)) { |
| | | error_log("Warning: Role references non-existent content type '{$content_type}'"); |
| | | return; |
| | | } |
| | | $this->addSingleContentCapabilities($capabilities, $content_type, $config); |
| | | if (!$this->isValidContentType($content_type)) { |
| | | error_log("Warning: Role references non-existent content type '{$content_type}'"); |
| | | return; |
| | | } |
| | | $this->addSingleContentCapabilities($capabilities, $content_type, $registrar); |
| | | } |
| | | |
| | | /** |
| | | * Add capabilities for a single content type |
| | | */ |
| | | private function addSingleContentCapabilities(array &$capabilities, string $type, array $config): void |
| | | private function addSingleContentCapabilities(array &$capabilities, string $type, Registrar $registrar): void |
| | | { |
| | | $caps = $this->getCapabilities($type); |
| | | foreach ($caps as $cap) { |
| | | $capabilities[$cap] = true; |
| | | } |
| | | |
| | | if (array_key_exists('approve_new', $config)) { |
| | | if ($registrar->hasFeature('approve_new')) { |
| | | $plural = $this->getContentPlural($type); |
| | | // Publish capability depends on approval setting |
| | | $capabilities["publish_{$plural}"] = !($config['approve_new'] ?? false); |
| | | } |
| | | |
| | | } |
| | | |
| | | public function grantRoleCapabilities(string $role_name, string $content_slug, bool $grant = true): void |
| | |
| | | |
| | | return [ |
| | | "edit_{$content}", |
| | | "edit_published_{$content}", |
| | | "read_{$content}", |
| | | "delete_{$content}", |
| | | "delete_published_{$content}", |
| | | "edit_{$plural}", |
| | | "edit_others_{$plural}", |
| | | "publish_{$plural}", |
| | | "read_private_{$plural}", |
| | | "edit_{$plural}", |
| | | "edit_private_{$plural}", |
| | | "delete_private_{$plural}", |
| | | ]; |
| | | } |
| | | protected function getOthersCapabilities(string $content):array |
| | |
| | | return [ |
| | | "edit_others_{$plural}", |
| | | "delete_others_{$plural}", |
| | | "read_private_{$plural}", |
| | | "edit_private_{$plural}", |
| | | "delete_private_{$plural}", |
| | | ]; |
| | | } |
| | | |
| | |
| | | public function getContentPlural(string $content): string |
| | | { |
| | | $content = jvbNoBase($content); |
| | | $config = Features::getConfig($content); |
| | | $capsMap = $config['capability_type']??[]; |
| | | if (empty($capsMap)){ |
| | | $capsMap = [ |
| | | $content, |
| | | str_replace('-', '_',sanitize_title(strtolower(JVB_CONTENT[$content]['plural']??JVB_TAXONOMY[$content]['plural']))) |
| | | ]; |
| | | return $capsMap[1]; |
| | | $registrar = Registrar::getInstance($content); |
| | | if ($registrar && $registrar->getPlural()) { |
| | | return str_replace(' ', '_', $registrar->getPlural()); |
| | | } |
| | | return str_replace('-', '_', sanitize_title(strtolower($content . 's'))); |
| | | return str_replace(' ', '_', $content.'s'); |
| | | } |
| | | |
| | | public function activate(): void |
| | | public static function activate(): void |
| | | { |
| | | foreach (JVB_USER as $slug => $config) { |
| | | $this->registerRole($slug, $config); |
| | | error_log('[RoleManager]::activate'); |
| | | error_log('Registering roles...'); |
| | | $instance = new self; |
| | | foreach (Registrar::getRegistered('user') as $role) { |
| | | $instance->registerRole($role); |
| | | } |
| | | error_log('Roles registered!'); |
| | | error_log('Removing unneeded roles...'); |
| | | remove_role('contributor'); |
| | | remove_role('author'); |
| | | remove_role('editor'); |
| | | error_log('Roles removed!'); |
| | | |
| | | error_log('Adding Admin Capabilities'); |
| | | $instance->addAdminCaps(); |
| | | error_log('Ensuring Existing User\'s Roles...'); |
| | | $instance->ensureRoleCaps(); |
| | | error_log('Roles activated!'); |
| | | } |
| | | protected function addAdminCaps():void |
| | | { |
| | | $users = get_users(['role' => 'administrator']); |
| | | foreach (array_merge(Registrar::getRegistered('post'), Registrar::withFeature('is_content')) as $slug) { |
| | | $this->grantRoleCapabilities('administrator', $slug); |
| | | $this->grantRoleOthersCapabilities('administrator', $slug); |
| | | |
| | | foreach ($users as $user) { |
| | | $this->grantContent($user, $slug); |
| | | $this->grantOthersContent($user, $slug); |
| | | } |
| | | } |
| | | } |
| | | protected function ensureRoleCaps():void |
| | | { |
| | | $roles = Registrar::getRegistered('user'); |
| | | foreach ($roles as $role) { |
| | | $registrar = Registrar::getInstance($role); |
| | | $creatable = $registrar->getCreatable(); |
| | | $manageable = $registrar->getManageOthers(); |
| | | if (!empty($creatable) || !empty($manageable)) { |
| | | $users = get_users(['role' => jvbCheckBase($role)]); |
| | | foreach ($users as $user) { |
| | | foreach ($creatable as $slug) { |
| | | $this->grantContent($user, $slug); |
| | | } |
| | | foreach ($manageable as $slug) { |
| | | $this->grantOthersContent($user, $slug); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /****************************************************************** |
| | | * OWNABLE and MANAGABLE terms (ie: tattoo shops) |
| | | ******************************************************************/ |
| | | /** |
| | | * Grant ownership of a content taxonomy term |
| | | * Owners have full control over the term and its members |
| | | * |
| | | * @param int $userID User ID |
| | | * @param int $termID Term ID |
| | | * @param string $taxonomy Taxonomy slug (without BASE) |
| | | * @return bool Success |
| | | */ |
| | | public function grantOwnership(int $userID, int $termID, string $taxonomy): bool |
| | | { |
| | | if (!get_userdata($userID) || !term_exists($termID)){ |
| | | return false; |
| | | } |
| | | $taxonomy = jvbNoBase($taxonomy); |
| | | |
| | | $registrar = Registrar::getInstance($taxonomy); |
| | | // Verify this is an ownable content taxonomy |
| | | if (!$registrar || !$registrar->hasFeature('is_content') || |
| | | !$registrar->hasFeature('is_ownable')) { |
| | | return false; |
| | | } |
| | | |
| | | $user = get_userdata($userID); |
| | | if (!$user) { |
| | | return false; |
| | | } |
| | | |
| | | // Grant both ownership and management |
| | | $user->add_cap(BASE . 'can_own_' . $termID); |
| | | $user->add_cap(BASE . 'can_manage_' . $termID); |
| | | |
| | | $owners = get_term_meta($termID, BASE.'owners', true); |
| | | if (empty($owners)) { |
| | | $owners = []; |
| | | } |
| | | $owners[] = $userID; |
| | | $owners = array_unique($owners); |
| | | update_term_meta($termID, BASE.'owners', $owners); |
| | | |
| | | |
| | | do_action(BASE . 'granted_ownership', $userID, $termID, $taxonomy); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Revoke ownership of a content taxonomy term |
| | | * |
| | | * @param int $userID User ID |
| | | * @param int $termID Term ID |
| | | * @param string $taxonomy Taxonomy slug (without BASE) |
| | | * @return bool Success |
| | | */ |
| | | public function revokeOwnership(int $userID, int $termID, string $taxonomy): bool |
| | | { |
| | | if (!get_userdata($userID) || !term_exists($termID)){ |
| | | return false; |
| | | } |
| | | $taxonomy = jvbNoBase($taxonomy); |
| | | |
| | | $user = get_userdata($userID); |
| | | if (!$user) { |
| | | return false; |
| | | } |
| | | |
| | | $owners = get_term_meta($termID, BASE.'owners', true); |
| | | if (empty($owners)) { |
| | | $owners = []; |
| | | } |
| | | if (in_array($userID, $owners)) { |
| | | unset($owners[array_search($userID, $owners)]); |
| | | } |
| | | $owners = array_unique($owners); |
| | | update_term_meta($termID, BASE.'owners', $owners); |
| | | |
| | | $user->remove_cap(BASE . 'can_own_' . $termID); |
| | | |
| | | do_action(BASE . 'revoked_ownership', $userID, $termID, $taxonomy); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Grant management capabilities for a content taxonomy term |
| | | * Managers can approve members and edit content but don't own the term |
| | | * |
| | | * @param int $userID User ID |
| | | * @param int $termID Term ID |
| | | * @param string $taxonomy Taxonomy slug (without BASE) |
| | | * @return bool Success |
| | | */ |
| | | public function grantManagement(int $userID, int $termID, string $taxonomy): bool |
| | | { |
| | | if (!get_userdata($userID) || !term_exists($termID)){ |
| | | return false; |
| | | } |
| | | $taxonomy = jvbNoBase($taxonomy); |
| | | |
| | | $registrar = Registrar::getInstance($taxonomy); |
| | | // Verify this is an ownable content taxonomy |
| | | if (!$registrar || !$registrar->hasFeature('is_content') || |
| | | !$registrar->hasFeature('is_ownable')) { |
| | | return false; |
| | | } |
| | | |
| | | $user = get_userdata($userID); |
| | | if (!$user) { |
| | | return false; |
| | | } |
| | | |
| | | $user->add_cap(BASE . 'can_manage_' . $termID); |
| | | |
| | | $managers = get_term_meta($termID, BASE.'managers', true); |
| | | if (empty($managers)) { |
| | | $managers = []; |
| | | } |
| | | $managers[] = $userID; |
| | | $managers = array_unique($managers); |
| | | update_term_meta($termID, BASE.'managers', $managers); |
| | | |
| | | do_action(BASE . 'granted_management', $userID, $termID, $taxonomy); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Revoke management capabilities for a content taxonomy term |
| | | * |
| | | * @param int $userID User ID |
| | | * @param int $termID Term ID |
| | | * @param string $taxonomy Taxonomy slug (without BASE) |
| | | * @return bool Success |
| | | */ |
| | | public function revokeManagement(int $userID, int $termID, string $taxonomy): bool |
| | | { |
| | | if (!get_userdata($userID) || !term_exists($termID)){ |
| | | return false; |
| | | } |
| | | $taxonomy = jvbNoBase($taxonomy); |
| | | |
| | | $user = get_userdata($userID); |
| | | if (!$user) { |
| | | return false; |
| | | } |
| | | |
| | | $user->remove_cap(BASE . 'can_manage_' . $termID); |
| | | |
| | | $managers = get_term_meta($termID, BASE.'managers', true); |
| | | if (empty($managers)) { |
| | | $managers = []; |
| | | } |
| | | if (in_array($userID, $managers)) { |
| | | unset($managers[array_search($userID, $managers)]); |
| | | } |
| | | $managers = array_unique($managers); |
| | | update_term_meta($termID, BASE.'managers', $managers); |
| | | |
| | | do_action(BASE . 'revoked_management', $userID, $termID, $taxonomy); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Check if user owns a term |
| | | * |
| | | * @param int $userID User ID |
| | | * @param int $termID Term ID |
| | | * @return bool |
| | | */ |
| | | public function isOwner(int $userID, int $termID): bool |
| | | { |
| | | return user_can($userID, BASE . 'can_own_' . $termID); |
| | | } |
| | | |
| | | /** |
| | | * Check if user can manage a term (owner or manager) |
| | | * |
| | | * @param int $userID User ID |
| | | * @param int $termID Term ID |
| | | * @return bool |
| | | */ |
| | | public function isManager(int $userID, int $termID): bool |
| | | { |
| | | return user_can($userID, BASE . 'can_manage_' . $termID) || |
| | | user_can($userID, BASE . 'can_own_' . $termID); |
| | | } |
| | | |
| | | /** |
| | | * Get all terms a user owns |
| | | * |
| | | * @param int $userID User ID |
| | | * @param string|null $taxonomy Optional: filter by taxonomy |
| | | * @return array Array of term IDs |
| | | */ |
| | | public function getOwnedTerms(int $userID, ?string $taxonomy = null): array |
| | | { |
| | | $user = get_userdata($userID); |
| | | if (!$user) { |
| | | return []; |
| | | } |
| | | |
| | | $owned = []; |
| | | foreach ($user->allcaps as $cap => $value) { |
| | | if ($value && strpos($cap, BASE . 'can_own_') === 0) { |
| | | $termID = (int) str_replace(BASE . 'can_own_', '', $cap); |
| | | if ($termID) { |
| | | $owned[] = $termID; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Filter by taxonomy if specified |
| | | if ($taxonomy && !empty($owned)) { |
| | | $taxonomy = jvbCheckBase($taxonomy); |
| | | $filtered = []; |
| | | foreach ($owned as $termID) { |
| | | $term = get_term($termID); |
| | | if ($term && !is_wp_error($term) && $term->taxonomy === $taxonomy) { |
| | | $filtered[] = $termID; |
| | | } |
| | | } |
| | | return $filtered; |
| | | } |
| | | |
| | | return $owned; |
| | | } |
| | | |
| | | /** |
| | | * Get all terms a user can manage (owns or manages) |
| | | * |
| | | * @param int $userID User ID |
| | | * @param string|null $taxonomy Optional: filter by taxonomy |
| | | * @return array Array of term IDs |
| | | */ |
| | | public function getManagedTerms(int $userID, ?string $taxonomy = null): array |
| | | { |
| | | $user = get_userdata($userID); |
| | | if (!$user) { |
| | | return []; |
| | | } |
| | | |
| | | $managed = []; |
| | | foreach ($user->allcaps as $cap => $value) { |
| | | if ($value && (strpos($cap, BASE . 'can_manage_') === 0 || |
| | | strpos($cap, BASE . 'can_own_') === 0)) { |
| | | $termID = (int) str_replace([BASE . 'can_manage_', BASE . 'can_own_'], '', $cap); |
| | | if ($termID && !in_array($termID, $managed)) { |
| | | $managed[] = $termID; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Filter by taxonomy if specified |
| | | if ($taxonomy && !empty($managed)) { |
| | | $taxonomy = jvbCheckBase($taxonomy); |
| | | $filtered = []; |
| | | foreach ($managed as $termID) { |
| | | $term = get_term($termID); |
| | | if ($term && !is_wp_error($term) && $term->taxonomy === $taxonomy) { |
| | | $filtered[] = $termID; |
| | | } |
| | | } |
| | | return $filtered; |
| | | } |
| | | |
| | | return $managed; |
| | | } |
| | | |
| | | /** |
| | | * Get all ownable taxonomies |
| | | * |
| | | * @return array Array of taxonomy slugs |
| | | */ |
| | | public function getOwnableTaxonomies(): array |
| | | { |
| | | static $ownable = null; |
| | | |
| | | if ($ownable === null) { |
| | | $ownable = array_map(function ($instance) { |
| | | return $instance->slug; |
| | | }, Registrar::withFeature('is_ownable', 'term')); |
| | | } |
| | | |
| | | return $ownable; |
| | | } |
| | | |
| | | /** |
| | | * Get all invitable taxonomies |
| | | * |
| | | * @return array Array of taxonomy slugs |
| | | */ |
| | | public function getInvitableTaxonomies(): array |
| | | { |
| | | static $invitable = null; |
| | | |
| | | if ($invitable === null) { |
| | | $invitable = array_map(function ($instance) { |
| | | return $instance->slug; |
| | | }, Registrar::withFeature('invitable', 'term')); |
| | | } |
| | | |
| | | return $invitable; |
| | | } |
| | | |
| | | public function getPermission(string $action, string $content, ?int $ID = null):?string |
| | | { |
| | | $plural = $this->getContentPlural($content); |
| | | switch ($action) { |
| | | case 'edit': |
| | | if ($ID) { |
| | | return "edit_{$content}"; |
| | | } |
| | | return "edit_{$plural}"; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public function maybeSwitchPermissions(int $object_id, array $terms, array $tt_ids, string $taxonomy, bool $append, array $old_tt_ids):void |
| | | { |
| | | //This shouldn't happen, but whatever |
| | | if (empty($this->subTypes)) { |
| | | return; |
| | | } |
| | | |
| | | if (!in_array($taxonomy, array_keys($this->subTypes))) { |
| | | return; |
| | | } |
| | | |
| | | $new = array_diff($tt_ids, $old_tt_ids); |
| | | $old = array_diff($old_tt_ids, $tt_ids); |
| | | |
| | | $userID = (int)get_post_meta($object_id, BASE.'profile_link',true); |
| | | if ($userID === 0) { |
| | | return; |
| | | } |
| | | $user = get_userdata($userID); |
| | | if (!$user) { |
| | | return; |
| | | } |
| | | |
| | | //Revoke old first |
| | | if (!empty($old)) { |
| | | $old = array_filter(array_map(function ($id) use ($taxonomy) { |
| | | $termID = $this->getTermIDFromTTID($id); |
| | | return $this->getRootTermSlug($termID, $taxonomy); |
| | | }, $old)); |
| | | foreach ($old as $slug) { |
| | | if (!array_key_exists($slug, $this->subTypes[$taxonomy])) { |
| | | error_log('[RoleManager]::maybeSwitchPermissions Could not find creatable types for role subtype '.$slug); |
| | | continue; |
| | | } |
| | | foreach ($this->subTypes[$taxonomy][$slug] ?? [] as $s) { |
| | | $this->grantContent($user, $s, false); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (!empty($new)) { |
| | | $new = array_filter(array_map(function ($id) use ($taxonomy){ |
| | | $termID = $this->getTermIDFromTTID($id); |
| | | return $this->getRootTermSlug($termID, $taxonomy); |
| | | }, $new)); |
| | | foreach ($new as $slug) { |
| | | if (!array_key_exists($slug, $this->subTypes[$taxonomy])) { |
| | | error_log('[RoleManager]::maybeSwitchPermissions Could not find creatable types for role subtype '.$slug); |
| | | continue; |
| | | } |
| | | foreach ($this->subTypes[$taxonomy][$slug] ?? [] as $s) { |
| | | $this->grantContent($user, $s); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Helper function to get term_id from term_taxonomy_id |
| | | * @param int $tt_id |
| | | * |
| | | * @return int |
| | | */ |
| | | private function getTermIDFromTTID(int $tt_id):int |
| | | { |
| | | global $wpdb; |
| | | return $wpdb->get_var($wpdb->prepare( |
| | | "SELECT term_id FROM {$wpdb->term_taxonomy} WHERE term_taxonomy_id = %d", |
| | | $tt_id |
| | | )); |
| | | } |
| | | |
| | | private function getRootTermSlug(int $termID, string $taxonomy): string|false |
| | | { |
| | | $term = get_term($termID, $taxonomy); |
| | | if (!$term || is_wp_error($term)) { |
| | | return false; |
| | | } |
| | | while ($term->parent !== 0) { |
| | | $term = get_term($term->parent, $taxonomy); |
| | | if (!$term || is_wp_error($term)) { |
| | | return false; |
| | | } |
| | | } |
| | | return $term->slug; |
| | | } |
| | | } |