From 2127b1bdd73ecd2423e443992da4b442f5a3c1a3 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Wed, 04 Feb 2026 21:19:25 +0000
Subject: [PATCH] =Major overhaul of MetaManager.php -> Meta.php and RestRouteManager.php -> Rest.php. Seems to work for JakeVan

---
 inc/managers/RoleManager.php |  278 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 277 insertions(+), 1 deletions(-)

diff --git a/inc/managers/RoleManager.php b/inc/managers/RoleManager.php
index 4913bc4..d4a3988 100644
--- a/inc/managers/RoleManager.php
+++ b/inc/managers/RoleManager.php
@@ -17,7 +17,7 @@
     {
        $this->roles = array_keys(JVB_USER);
 	   $this->content = array_map(function($content) {
-		   return strtolower($content['plural']);
+		   return strtolower($content['plural']??$content['singular'].'s');
 	   },JVB_CONTENT);
 	   add_action('set_user_role', [$this, 'updateRoles'], 10, 3);
     }
@@ -438,4 +438,280 @@
 			$this->registerRole($slug, $config);
 		}
 	}
+
+	/******************************************************************
+	 * 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);
+
+		// Verify this is an ownable content taxonomy
+		if (!Features::forTaxonomy($taxonomy)->has('is_content') ||
+			!Features::forTaxonomy($taxonomy)->has('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);
+
+		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;
+		}
+
+		$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);
+
+		// Verify this is an ownable content taxonomy
+		if (!Features::forTaxonomy($taxonomy)->has('is_content') ||
+			!Features::forTaxonomy($taxonomy)->has('is_ownable')) {
+			return false;
+		}
+
+		$user = get_userdata($userID);
+		if (!$user) {
+			return false;
+		}
+
+		$user->add_cap(BASE . 'can_manage_' . $termID);
+
+		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);
+
+		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 = [];
+			foreach (JVB_TAXONOMY as $taxonomy => $config) {
+				if (Features::forTaxonomy($taxonomy)->has('is_content') &&
+					Features::forTaxonomy($taxonomy)->has('is_ownable')) {
+					$ownable[] = $taxonomy;
+				}
+			}
+		}
+
+		return $ownable;
+	}
+
+	/**
+	 * Get all invitable taxonomies
+	 *
+	 * @return array Array of taxonomy slugs
+	 */
+	public function getInvitableTaxonomies(): array
+	{
+		static $invitable = null;
+
+		if ($invitable === null) {
+			$invitable = [];
+			foreach (JVB_TAXONOMY as $taxonomy => $config) {
+				if (Features::forTaxonomy($taxonomy)->has('invitable')) {
+					$invitable[] = $taxonomy;
+				}
+			}
+		}
+
+		return $invitable;
+	}
 }

--
Gitblit v1.10.0