| | |
| | | <?php |
| | | namespace JVBase\managers; |
| | | |
| | | use JVBase\registrar\Registrar; |
| | | use JVBase\utility\Features; |
| | | use WP_User; |
| | | use WP_Role; |
| | |
| | | |
| | | public function __construct() |
| | | { |
| | | $this->roles = array_keys(JVB_USER); |
| | | $this->roles = array_keys(array_map(function ($instance) { |
| | | return $instance->slug; |
| | | }, Registrar::getRegistered('user'))); |
| | | |
| | | $this->content = array_map(function($content) { |
| | | return strtolower($content['plural']??$content['singular'].'s'); |
| | | },JVB_CONTENT); |
| | | $registrar = Registrar::getInstance($content); |
| | | return strtolower(str_replace(' ', '_', $registrar->getPlural()??$registrar->getSingular().'s')); |
| | | },array_merge( |
| | | Registrar::getRegistered('post'), |
| | | Registrar::getFeatured('is_content', 'term') |
| | | )); |
| | | add_action('set_user_role', [$this, 'updateRoles'], 10, 3); |
| | | } |
| | | |
| | |
| | | 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; |
| | |
| | | |
| | | 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; |
| | |
| | | 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); |
| | |
| | | } |
| | | } |
| | | |
| | | 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 (Features::forSite()->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 |
| | |
| | | "edit_others_{$plural}", |
| | | "publish_{$plural}", |
| | | "read_private_{$plural}", |
| | | "edit_{$plural}", |
| | | ]; |
| | | } |
| | | protected function getOthersCapabilities(string $content):array |
| | |
| | | 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 |
| | | { |
| | | foreach (JVB_USER as $slug => $config) { |
| | | $this->registerRole($slug, $config); |
| | | foreach (Registrar::getRegistered('user') as $role) { |
| | | $this->registerRole($role); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | $taxonomy = jvbNoBase($taxonomy); |
| | | |
| | | $registrar = Registrar::getInstance($taxonomy); |
| | | // Verify this is an ownable content taxonomy |
| | | if (!Features::forTaxonomy($taxonomy)->has('is_content') || |
| | | !Features::forTaxonomy($taxonomy)->has('is_ownable')) { |
| | | if (!$registrar || !$registrar->hasFeature('is_content') || |
| | | !$registrar->hasFeature('is_ownable')) { |
| | | return false; |
| | | } |
| | | |
| | |
| | | } |
| | | $taxonomy = jvbNoBase($taxonomy); |
| | | |
| | | $registrar = Registrar::getInstance($taxonomy); |
| | | // Verify this is an ownable content taxonomy |
| | | if (!Features::forTaxonomy($taxonomy)->has('is_content') || |
| | | !Features::forTaxonomy($taxonomy)->has('is_ownable')) { |
| | | if (!$registrar || !$registrar->hasFeature('is_content') || |
| | | !$registrar->hasFeature('is_ownable')) { |
| | | return false; |
| | | } |
| | | |
| | |
| | | static $ownable = null; |
| | | |
| | | if ($ownable === null) { |
| | | $ownable = []; |
| | | foreach (JVB_TAXONOMY as $taxonomy => $config) { |
| | | if (Features::forTaxonomy($taxonomy)->has('is_content') && |
| | | Features::forTaxonomy($taxonomy)->has('is_ownable')) { |
| | | $ownable[] = $taxonomy; |
| | | } |
| | | } |
| | | $ownable = array_map(function ($instance) { |
| | | return $instance->slug; |
| | | }, Registrar::getFeatured('is_ownable', 'term')); |
| | | } |
| | | |
| | | return $ownable; |
| | |
| | | static $invitable = null; |
| | | |
| | | if ($invitable === null) { |
| | | $invitable = []; |
| | | foreach (JVB_TAXONOMY as $taxonomy => $config) { |
| | | if (Features::forTaxonomy($taxonomy)->has('invitable')) { |
| | | $invitable[] = $taxonomy; |
| | | } |
| | | } |
| | | $invitable = array_map(function ($instance) { |
| | | return $instance->slug; |
| | | }, Registrar::getFeatured('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; |
| | | } |
| | | } |