From 56a9a1ccf764ff7a6af8f8a2292cb07443cb4aa7 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Thu, 28 May 2026 18:19:57 +0000
Subject: [PATCH] =New Gitbit setpu

---
 inc/managers/DashboardManager.php |  541 +++++++++++++++++++++++++-----------------------------
 1 files changed, 251 insertions(+), 290 deletions(-)

diff --git a/inc/managers/DashboardManager.php b/inc/managers/DashboardManager.php
index 67844ec..28aa956 100644
--- a/inc/managers/DashboardManager.php
+++ b/inc/managers/DashboardManager.php
@@ -1,11 +1,12 @@
 <?php
 namespace JVBase\managers;
 
-use JVBase\forms\TaxonomySelector;use JVBase\managers\CRUD;
-use JVBase\meta\MetaManager;
-use JVBase\utility\Features;
+use JVBase\forms\TaxonomySelector;
+use JVBase\base\Site;
+use JVBase\meta\Form;
+use JVBase\registrar\Registrar;
 use JVBase\ui\Navigation;
-use WP_User;
+use WP_Error;use WP_Query;use WP_User;
 
 if (!defined('ABSPATH')) {
     exit; // Exit if accessed directly
@@ -17,21 +18,22 @@
 class DashboardManager
 {
     protected WP_User $user;
-    protected CacheManager $cache;
+    protected Cache $cache;
     protected string $role;
 	protected string $baseURL;
     protected int $userLink;
 
     public function __construct()
     {
-        $this->cache = CacheManager::for('dashboard', WEEK_IN_SECONDS);
+        $this->cache = Cache::for('dashboard', WEEK_IN_SECONDS)->connect('user');
+		if (JVB_TESTING) {
+			$this->cache->flush();
+		}
         add_action('init', [$this, 'registerDashboard']);
-        if (!$this->isRegistered()) {
-            add_action('init', [$this, 'buildDashboard']);
-        }
+
         $this->user = wp_get_current_user();
         $this->role = jvbUserRole($this->user->ID);
-        $this->userLink = (int)get_user_meta($this->user->ID, BASE.'link', true);
+        $this->userLink = (int)get_user_meta($this->user->ID, BASE.'profile_link', true);
 		$this->baseURL = get_home_url(null, '/dash');
 
     	add_action('template_redirect', [$this, 'handleRedirects']);
@@ -40,6 +42,8 @@
         add_action('wp_enqueue_scripts', [$this, 'dashboardScripts'], 50);
 		add_filter('jvbDashboardPage', [$this, 'renderIndex'], 10, 2);
 
+		jvb_register_do_once('buildDashboard', [$this, 'activate']);
+
 		add_filter('the_seo_framework_sitemap_exclude_ids', [$this, 'excludeDashboard'], 10, 1);
     }
 
@@ -67,18 +71,21 @@
         $singular = 'Dashboard';
         register_post_type(BASE.'dash', array(
             'labels'                => [
-                'name' => $plural,
-                'singular_name' => $singular,
-                'menu_name' => $plural,
-                'add_new' => "Add New {$singular}",
-                'add_new_item' => "Add New {$singular}",
-                'edit_item' => "Edit {$singular}",
-                'new_item' => "New {$singular}",
-                'view_item' => "View {$singular}",
-                'search_items' => "Search {$plural}",
-                'not_found' => "No {$plural} found",
-                'not_found_in_trash' => "No {$plural} found in Trash"
-            ],
+				'name'               => $plural,
+				'singular_name'      => $singular,
+				'menu_name'          => $plural,
+				'name_admin_bar'     => $singular,
+				'add_new'            => "Add New",
+				'add_new_item'       => "Add New {$singular}",
+				'new_item'           => "New {$singular}",
+				'edit_item'          => "Edit {$singular}",
+				'view_item'          => "View {$singular}",
+				'all_items'          => "All {$plural}",
+				'search_items'       => "Search {$plural}",
+				'parent_item_colon'  => "Parent {$plural}:",
+				'not_found'          => "No {$plural} found.",
+				'not_found_in_trash' => "No {$plural} found in Trash.",
+			],
             'menu_icon'             => jvbCSSIcon('gauge'),
             'public'                => true,
             'publicly_queryable'    => true,
@@ -133,14 +140,14 @@
 	}
 
 
-	protected function getConfig(string $page):array
+	protected function getConfig(string $page):Registrar|false
 	{
 		$pages = $this->getAllDashboardPages();
 		$key = array_search($page, $pages);
 		if ($key === false || is_numeric($key)) {
-			return [];
+			return false;
 		}
-		return Features::getConfig($key);
+		return Registrar::getInstance($key)??false;
 	}
 
 	/**
@@ -160,9 +167,9 @@
 
 	protected function getTitle(string $slug):string
 	{
-		$config = $this->getConfig($slug);
-		if (!empty($config)) {
-			return $config['dash_title']??$config['plural'];
+		$registrar = $this->getConfig($slug);
+		if ($registrar) {
+			return $registrar->getConfig('dashboard')['title']??$registrar->getPlural();
 		}
 		return ucwords(str_replace('-', ' ', str_replace('_', ' ', $slug)));
 	}
@@ -207,10 +214,10 @@
 			$page = $this->getCurrentPageTitle();
 			// Check if page exists in allowed pages
 			$allowedPages = $this->getUserAllowedPages();
+
 			if (!in_array($page, $allowedPages)) {
 				error_log("User not allowed to access page: {$page}");
 				$this->redirectToDashboard();
-				return;
 			}
 		}
 	}
@@ -219,34 +226,65 @@
      * Ensures the necessary pages are created
      * @return void
      */
-    public function buildDashboard():void
+    public function activate():void
     {
         $manageableContent = $this->getAllDashboardPages();
+		error_log('[DashboardManager]::buildDashboard Manageable Content: '.print_r($manageableContent, true));
         foreach ($manageableContent as $slug => $page) {
 			if ($page === 'dash') {
 				continue;
 			}
-			$slug = $this->getSlug($slug, $page);
-			$existing = get_page_by_path($slug, OBJECT, BASE.'dash');
-			if ($existing) {
-				continue;
+
+			$ID = $this->createDashboardPage($slug, $page);
+
+
+			$registrar = Registrar::getInstance($slug);
+			if ($registrar) {
+				$create = [
+					'new_'	=> 'Create New ',
+					'edit_'	=> 'Edit '
+				];
+				$parentID = (int)$ID;
+				foreach ($create as $s => $t) {
+					$s .= $slug;
+					$t .= $page;
+					$this->createDashboardPage($s, $t, $parentID);
+				}
 			}
-            $title = $page;
-
-            $ID = wp_insert_post(array(
-                'post_title'    => $title,
-                'post_name'     => $slug,
-                'post_type'     => BASE.'dash',
-                'post_status'   => 'publish',
-            ));
-
-			if ($title === 'Integrations') {
+			if ($page === 'Integrations') {
 				$this->buildIntegrationPages($ID);
 			}
         }
-        update_option(BASE.'dashboard_registered', true);
-        remove_action('init', [$this, 'buildDashboard']);
     }
+		public function createDashboardPage(string $slug, string $page, int $parentID = 0):int|WP_Error
+		{
+			if (is_numeric($slug)) {
+				$slug = $this->getSlug($slug, $page);
+			}
+
+			$existing = new WP_Query([
+				'post_type'	=> BASE.'dash',
+				'name'	=> $slug,
+				'fields'	=> 'ids',
+				'posts_per_page'	=> 1,
+			]);
+
+			if ($existing->have_posts()) {
+				return $existing->posts[0];
+			}
+
+
+			$args = [
+				'post_title'    => $page,
+                'post_name'     => $slug,
+                'post_type'     => BASE.'dash',
+                'post_status'   => 'publish',
+			];
+			if ($parentID > 0) {
+				$args['post_parent'] = $parentID;
+			}
+            return wp_insert_post($args);
+		}
 
 	/**
 	 * Build integration sub-pages
@@ -259,36 +297,18 @@
 
 		foreach ($integrations as $name => $integration) {
 			$title = $integration->getTitle();
+
 			$slug = sanitize_title($title);
-
-			// Check if integration page already exists
-			$existing = get_posts([
-				'post_type' => BASE.'dash',
-				'name' => $slug,
-				'post_parent' => $parentID,
-				'posts_per_page' => 1,
-			]);
-
-			if (!empty($existing)) {
-				continue; // Skip if exists
-			}
-
-			wp_insert_post([
-				'post_title'    => $title,
-				'post_name'     => $slug,
-				'post_type'     => BASE.'dash',
-				'post_status'   => 'publish',
-				'post_parent'   => $parentID
-			]);
+			$this->createDashboardPage($slug, $title, $parentID);
 		}
 	}
 
 
     protected function getDescription(string $page):string
     {
-		$config = $this->getConfig($page);
-        if (!empty($config)) {
-            $description = (array_key_exists('dash_description', $config)) ? $config['dash_description'] : '';
+		$registrar = $this->getConfig($page);
+        if ($registrar) {
+            $description =  $registrar->getConfig('dashboard')['description']??'';
         } else {
 			$description = apply_filters('jvbDashboardDescription', $page);
             switch ($page) {
@@ -313,14 +333,6 @@
         return $description;
     }
 
-    /**
-     * Checks if we've already created the need pages
-     * @return bool
-     */
-    protected function isRegistered():bool
-    {
-        return get_option(BASE.'dashboard_registered', false);
-    }
 
     /**
      * Hacking into the template_include to set our custom templates and protections
@@ -336,10 +348,10 @@
 
         // Get current page/section
         $page = $this->getCurrentPageTitle();
-		$config = $this->getConfig($page);
-		if(!empty($config)) {
-			add_filter('jvbLoadingIcon', function() use ($config) {
-				return $config['icon'];
+		$registrar = $this->getConfig($page);
+		if($registrar) {
+			add_filter('jvbLoadingIcon', function() use ($registrar) {
+				return $registrar->getIcon();
 			});
 		}
 		$integrationSlugs = array_map(function($name) {
@@ -351,14 +363,14 @@
 			// Pass along to the Integrations template handler which knows to check for subpages
 			$page = 'integrations';
 		}
-		echo $this->renderDashboard($page);
-		//TODO: Reenable
-//		echo $this->cache->remember(
-//			$page,
-//		 	function() use ($page) {
-//				return $this->renderDashboard($page);
-//		 	}
-//		);
+//		echo $this->renderDashboard($page);
+
+		echo $this->cache->remember(
+			$page,
+		 	function() use ($page) {
+				return $this->renderDashboard($page);
+		 	}
+		);
 
 		return '';
     }
@@ -370,13 +382,14 @@
 	}
 	protected function renderDashboard(string $page):string
 	{
-		ob_start();
+//		ob_start();
 		jvbInlineStyles('nav');
 		jvbInlineStyles('dash');
 		jvbInlineStyles('forms');
 		$this->renderHeader();
 		// Pass to page handler
 		$constantSlug = $this->getConstantSlug($page);
+
         echo apply_filters(
 			'jvbDashboardPage',
 			$this->renderPage($page),
@@ -385,7 +398,8 @@
 		);
 
 		$this->renderFooter();
-		return ob_get_clean();
+//		return ob_get_clean();
+return '';
 //		$integrationSlugs = array_map(function($name) {
 //			return sanitize_title(str_replace('_', '-', $name));
 //		}, array_keys(JVB()->getAvailableServices(false)));
@@ -393,11 +407,11 @@
 //		if ($page === 'integrations' || in_array($page, $integrationSlugs)) {
 //			// Check integration access
 //			if ($page === 'integrations') {
-//				if (!Features::hasAnyIntegration('user', $this->role)) {
+//				if (!Site::hasAnyIntegration('user', $this->role)) {
 //					$this->redirectToDashboard();
 //				}
 //			} else {
-//				if (!Features::hasIntegration($page, 'user', $this->role)) {
+//				if (!Site::hasIntegration($page, 'user', $this->role)) {
 //					$this->redirectToDashboard();
 //				}
 //			}
@@ -511,8 +525,8 @@
 		if (!is_singular(BASE.'dash') && !is_post_type_archive(BASE.'dash')) {
             return;
         }
-		wp_enqueue_style('jvb-icons-dash');
-		wp_enqueue_style('jvb-icons-forms');
+		IconsManager::for('forms')->enqueueIconStyles();
+		IconsManager::for('dash')->enqueueIconStyles();
 
 		wp_enqueue_script('jvb-form');
 		wp_enqueue_script('jvb-selector');
@@ -523,7 +537,7 @@
 
             switch ($page) {
                 case 'notifications':
-					if (Features::forSite()->has('notifications')) {
+					if (Site::has('notifications')) {
 						wp_enqueue_script('jvb-notification-manager');
 					}
                     break;
@@ -533,28 +547,28 @@
 					break;
                 case 'admin':
                 case 'dash':
-                    if (current_user_can('manage_options') && apply_filters('jvbAdminDashboard', '') === '') {
-                        wp_enqueue_script(
-                        'jvb-admin',
-                        JVB_URL . 'assets/js/min/admin.min.js',
-                        [
-                            'jvb-queue',
-                            'jvb-loading'
-                        ],
-                        [
-                            'strategy' => 'defer',
-                            'in_footer' => true
-                        ]
-                    );
+//                    if (current_user_can('manage_options') && apply_filters('jvbAdminDashboard', '') === '') {
+//                        wp_enqueue_script(
+//                        'jvb-admin',
+//                        JVB_URL . 'assets/js/min/admin.min.js',
+//                        [
+//                            'jvb-queue',
+////                            'jvb-loading'
+//                        ],
+//                        [
+//                            'strategy' => 'defer',
+//                            'in_footer' => true
+//                        ]
+//                    );
 
-                    wp_localize_script(
-                        'jvb-admin',
-                        'jvbAdmin',
-                        [
-                            'nonce' => wp_create_nonce('itsme')
-                        ]
-                    );
-                    }
+//                    wp_localize_script(
+//                        'jvb-admin',
+//                        'jvbAdmin',
+//                        [
+//                            'nonce' => wp_create_nonce('itsme')
+//                        ]
+//                    );
+//                    }
 					break;
 				case 'seo':
 					wp_enqueue_script('jvb-schema');
@@ -563,7 +577,7 @@
 					wp_enqueue_script('jvb-crud');
 					break;
             }
-			if (Features::forSite()->has('favourites')) {
+			if (Site::has('favourites')) {
 				 wp_enqueue_script('jvb-favourites');
 				wp_localize_script('jvb-favourites-manager', 'favouritesSettings', [
 					'strings' => [
@@ -579,7 +593,7 @@
 
 			wp_enqueue_script('jvb-creator');
 
-			if (Features::forSite()->has('forum')) {
+			if (Site::has('forum')) {
 			wp_enqueue_script('jvb-news');
 			}
 			do_action('jvbDashScripts', $page);
@@ -595,8 +609,7 @@
         if (!$post) {
             return '';
         }
-
-        return $post->post_title;
+        return html_entity_decode($post->post_title);
     }
    protected function getCurrentPageSlug():string
     {
@@ -616,10 +629,11 @@
 		return $this->cache->remember('icon_'.sanitize_title($page), function() use ($slug, $page) {
 			$icon = sanitize_title($page);
 			if (!is_numeric($slug)) {
-				$config = Features::getConfig($slug);
-				if (array_key_exists('icon', $config)) {
-					$icon = $config['icon'];
+				$registrar =Registrar::getInstance($slug);
+				if ($registrar) {
+				return $registrar->getIcon();
 				}
+
 			}
 			return $icon;
 		});
@@ -641,7 +655,7 @@
         <!DOCTYPE html>
     <html <?php language_attributes(); ?>>
         <head>
-            <title><?= (array_key_exists('dashboard_title', JVB_SITE)) ? JVB_SITE['dashboard_title'] : 'Dashboard | '.get_bloginfo('name') ?></title>
+            <title><?= Site::dashboardTitle()??'Dashboard | '.get_bloginfo('name') ?></title>
             <meta charset="<?php bloginfo('charset'); ?>">
             <meta name="viewport" content="width=device-width, initial-scale=1.0">
             <?php
@@ -661,41 +675,27 @@
     <body class="dashboard<?= ' '.$this->getCurrentPageSlug()?>">
         <?php jvbAccessibility();?>
         <header>
-            <?php
-            $checked = (is_user_logged_in() && current_user_can('prefers_dark_theme', true)) ? ' checked' : '';
-            $title = ($checked == '') ? 'Toggle Dark Mode' : 'Toggle Light Mode';
-            echo '<label title="'.$title.'" id="theme-switch" class="toggle-switch" for="theme-switcher">
-                    <input class="theme-switch row" id="theme-switcher" name="theme-switcher" type="checkbox"'.$checked.' data-setting="theme" data-theme role="switch" name="dark-mode" aria-label="Toggle dark mode"><span class="slider">'.
-					jvbIcon('sun-dim', ['title'=> 'Light Mode']).
-					jvbIcon('moon', ['title'=>'Dark Mode']).
-					'</span></label>';
-            ?>
-            <p class="title">
-                <a href="<?= get_home_url(); ?>" rel="home" title="Back to Site">
-                    <?php
-                    $icon = (int) get_option( 'site_icon' );
-					$out = '';
-					if ($icon > 0) {
-						$url = wp_get_attachment_image_url( $icon);
-						if ($url) {
-							$out = '<img src="'.$url.'">';
-						}
-					}
-					if ($out == '') {
-						$out =jvbIcon('house');
-					}
-                    ?><?= $out ?>
-                </a>
-            </p>
+			<?= jvbDarkModeToggle() ?>
+			<?php
+			$function = BASE.'render_core_site_logo';
+			if (function_exists($function)) {
+				echo $function([],'');
+			} else {
+				echo render_block( [
+					'blockName' => 'core/site-logo',
+					'attrs'     => [],
+				]);
+			}
+			?>
 
-            <nav>
-                <ul>
-                    <?= jvbNotificationMenu() ?>
-                    <?= jvbHelpMenu() ?>
-                    <li><a href="<?=wp_logout_url(get_home_url())?>" title="Logout"><?=jvbIcon('sign-out')?></a></li>
-                </ul>
-            </nav>
-        </header>
+			<nav>
+				<ul>
+					<?= jvbNotificationMenu() ?>
+					<?= jvbHelpMenu() ?>
+					<li><a href="<?=wp_logout_url(get_home_url())?>" title="Logout"><?=jvbIcon('sign-out')?></a></li>
+				</ul>
+			</nav>
+		</header>
 
         <main><section class="replace">
     <?php
@@ -708,9 +708,9 @@
 
 		<?php
 		$menu = new Navigation('sidebar');
-		$menuClasses = ['col', 'a-start', 'nowrap'];
+		$menuClasses = ['left'];
 		$itemClasses = ['col'];
-		$menu->addClass('col a-start')->hasToggle()->defaultMenuClasses($menuClasses);
+		$menu->addClass('sidebar left')->hasToggle()->defaultMenuClasses($menuClasses);
 		$menu->defaultItemClasses($itemClasses);
 		$pages = $this->getUserAllowedPages()?:[];
 		//Dashboard
@@ -736,9 +736,12 @@
 
 		//Content
 			//content types
-				//Taxonomies
-		$availableContent = array_filter($pages, function($page, $key) {
-			return !is_numeric($key) && array_key_exists($key, JVB_CONTENT);
+		$all = array_merge(
+			Registrar::getRegistered('post'),
+			Registrar::getFeatured('is_content', 'term')
+		);
+		$availableContent = array_filter($pages, function($page, $key) use($all) {
+			return !is_numeric($key) && in_array($key, $all) && JVB()->roles()->checkRole($this->user, $key);
 		}, ARRAY_FILTER_USE_BOTH);
 		if (!empty ($availableContent)){
 			$content = $menu->addItem('Your Content', jvbDashIcon('book-bookmark'))
@@ -746,25 +749,33 @@
 				->defaultMenuClasses($menuClasses)
 				->defaultItemClasses($itemClasses);
 			foreach ($availableContent as $slug => $page) {
-				$config = JVB_CONTENT[$slug];
-				$item = $content->addItem($page, jvbDashIcon($config['icon']))
+				$registrar = Registrar::getInstance($slug);
+
+				$item = $content->addItem($page, $registrar->getIcon())
 					->url($this->baseURL.'/'.$slug);
 
-				$taxonomies = array_filter(JVB_TAXONOMY, function ($value, $key) use ($slug) {
-					return in_array($slug, $value['for_content']);
-				},1);
-				if (!empty ($taxonomies)) {
-					//TODO: If we add a dedicated 'create item' page, remove this from the empty check
-					$itemMenu = $item->submenu($slug);
-					foreach ($taxonomies as $s => $config) {
-						$itemMenu->addItem($config['plural'], $config['icon'])
-							->url($this->baseURL.'/'.$s);
+				if ($registrar->getType() === 'post') {
+					$taxonomies = $registrar->registrar->taxonomies;
+					if (!empty ($taxonomies)) {
+						//TODO: If we add a dedicated 'create item' page, remove this from the empty check
+						$itemMenu = $item->submenu($slug);
+						foreach ($taxonomies as $s) {
+							$taxRegistrar = Registrar::getInstance($s);
+							if ($taxRegistrar) {
+								$itemMenu->addItem($taxRegistrar->getPlural(), $taxRegistrar->getIcon())
+								->url($this->baseURL.'/'.$s);
+							}
+
+						}
 					}
 				}
 
+
 			}
 		}
 
+		//Taxonomies
+
 		//Settings
 		$settings = $menu->addItem('Settings', jvbDashIcon('faders'))
 			->submenu('settings')
@@ -852,7 +863,7 @@
 			return $content;
 		}
 
-		if (Features::forSite()->has('referrals')) {
+		if (Site::has('referrals')) {
 			$whatever = JVB()->referrals()->getReferralWelcomeMessage($this->user->ID);
 			if (!empty($whatever)) {
 				return $whatever;
@@ -862,14 +873,14 @@
 		ob_start();
         $name = ($this->user->first_name !== '') ? $this->user->first_name : $this->user->display_name;
 
-        echo '<h1 style="text-transform:none;margin-top:2em!important;">Hey '.$name.'</h1>';
+        echo '<h1>Hey '.$name.'</h1>';
         echo '<p>Welcome back!</p>';
 
         $pages = $this->getUserAllowedPages();
 
         echo '<h2>What would you like to do today?</h2>';
 
-        echo '<ul>';
+        echo '<ul class="dashboard">';
         foreach ($pages as $slug => $page) {
 			if ($page === 'dash') {
 				continue;
@@ -966,7 +977,7 @@
 		$connection = (array_key_exists($page, $map)) ? $map[$page] : $page;
 		if ($connection !== 'integrations') {
 
-			$userID = (jvbSiteHasMembership()) ? $this->user->ID : null;
+			$userID = (Site::has('has_membership')) ? $this->user->ID : null;
 			$integration = JVB()->connect($connection, $userID);
 
 			echo '<h1>Managing '.$integration->title.'</h1>';
@@ -998,18 +1009,18 @@
     {
         ?>
         <div class="approvals container">
-            <nav class="tabs row start" role="tablist">
+            <nav class="tabs row left" role="tablist">
                 <button type="button" class="tab active" data-tab="summary" role="tab" aria-selected="true">
-                    <h2><?= jvbDashIcon('infinity')?>All</h2>
+                   <?= jvbDashIcon('infinity')?>All
                 </button>
                 <button type="button" class="tab" data-tab="artists" role="tab" aria-selected="false">
-                    <h2><?= jvbDashIcon('users-three')?>Artists</h2>
+                    <?= jvbDashIcon('users-three')?>Artists
                 </button>
                 <button type="button" class="tab" data-tab="terms" role="tab" aria-selected="false">
-                    <h2><?= jvbDashIcon('hash')?>Terms</h2>
+                   <?= jvbDashIcon('hash')?>Terms
                 </button>
                 <button type="button" class="tab" data-tab="yours" role="tab" aria-selected="false">
-                    <h2><?= jvbDashIcon('user')?>Yours</h2>
+                    <?= jvbDashIcon('user')?>Yours
                 </button>
             </nav>
         </div>
@@ -1070,23 +1081,22 @@
 		}
 		ob_start();
         ?>
-        <nav class="tabs row start" role="tablist">
+        <nav class="tabs row left" role="tablist">
         <?php
         $i=1;
-        $content = JVB_CONTENT;
-        $contentTax = array_filter(JVB_TAXONOMY, function ($tax) {
-            return jvbCheck('is_content', $tax);
-        });
-        $taxonomies = JVB_TAXONOMY;
-        foreach($contentTax as $key => $config) {
-            unset($taxonomies[$key]);
+        $content = Registrar::getRegistered('post');
+        $contentTax = Registrar::getFeatured('is_content', 'term');
+        $taxonomies = Registrar::getRegistered('term');
+        foreach($contentTax as $index => $tax) {
+            unset($taxonomies[$index]);
         }
         $content = array_merge($content, $contentTax);
-        foreach ($content as $type => $settings) {
+        foreach ($content as $type) {
+			$registrar = Registrar::getInstance($type);
             $active = ($i === 1) ? ' active' : '';
             ?>
             <button type="button" class="tab<?=$active?>" data-tab="<?=$type?>" role="tab" aria-selected="<?= ($active !== '') ? 'true' : 'false'?>">
-                <h2><?=jvbDashIcon($settings['icon']??$key)?> <?= $settings['plural'] ?></h2>
+                <h2><?=jvbDashIcon($registrar->getIcon())?> <?= $registrar->getPlural() ?></h2>
             </button>
             <?php
             $i++;
@@ -1097,8 +1107,9 @@
             <option> ... Taxonomy</option>
             <?php
 
-            foreach ($taxonomies as $type => $settings) {
-                echo '<option value="'.$type.'">'.$settings['plural'].'</option>';
+            foreach ($taxonomies as $type) {
+				$taxRegistrar = Registrar::getInstance($type);
+                echo '<option value="'.$type.'">'.$taxRegistrar->getPlural().'</option>';
             }
             ?>
         </select>
@@ -1122,11 +1133,10 @@
 
     <?php
 
-    $jvb_everything = array_merge(JVB_CONTENT, JVB_TAXONOMY);
 
-    foreach ($jvb_everything as $type => $settings) {
-        $meta = new MetaManager(null, 'form');
-        $fields = jvbGetFields($type);
+
+    foreach (Registrar::getRegistered() as $type) {
+        $fields = Registrar::getFieldsFor($type);
         ?>
         <template class="<?= $type ?>Table">
             <table>
@@ -1195,7 +1205,7 @@
                             <?php
                             $config['type'] = 'text';
                             $config['description'] = '';
-                            $meta->render('form', $n, $config);
+                            Form::render($n, null, $config);
                             ?>
                         </td>
                         <?php
@@ -1210,10 +1220,9 @@
         echo jvbNewModal(
             'edit-modal '.$type,
             'Edit '.ucfirst($type),
-            $meta->renderForm('admin', [], $fields)
+            jvbRenderForm('admin', $fields)
         );
         }
-
 		return ob_get_clean();
     }
 
@@ -1245,53 +1254,55 @@
 			$pages = [];
 			$pages[] = 'SEO';
 			// Add feature-dependent pages (non-config)
-			if (Features::forSite()->has('referrals')) {
+			if (Site::has('referrals')) {
 				$pages[] = 'Referrals';
 			}
-
-			if (Features::forMembership()->has('can_invite')) {
+			$membership = Site::membership();
+			if ($membership && $membership->has('can_invite')) {
 				$pages[] = 'Invites';
 			}
 
-			if (Features::forMembership()->has('term_approval')) {
+			if ($membership && $membership->has('term_approval')) {
 				$pages[] = 'Approvals';
 			}
 
-			if (Features::forMembership()->has('forum')) {
+			if ($membership && $membership->has('forum')) {
 				$pages[] = 'News';
 			}
 
-			if (Features::forMembership()->has('member_content')) {
+			if ($membership && $membership->has('member_content')) {
 				$pages[] = 'Metrics';
 			}
 
-			if (Features::forSite()->has('favourites')) {
+			if (Site::has('favourites')) {
 				$pages[] = 'Favourites';
 			}
 
-			if (Features::anyContentHas('karma') || Features::anyTaxonomyHas('karma') || Features::anyUserHas('karma')) {
+			if (!empty(Registrar::getFeatured('karma'))) {
 				$pages[] = 'Karmic Score';
 			}
 
-			if (Features::forSite()->has('notifications')) {
+			if (Site::has('notifications')) {
 				$pages[] = 'Notifications';
 			}
 
-			if (Features::forSite()->has('support')) {
+			if (Site::has('support')) {
 				$pages[] = 'Support';
 			}
 
-			if (Features::hasAnyIntegration()) {
+			if (Site::hasAnyIntegration()) {
 				$pages[] = 'Integrations';
 			}
 
 			// Add all content types (with config keys)
-			foreach (JVB_CONTENT as $slug => $config) {
-				$pages[$slug] = $config['plural'];
+			foreach (Registrar::getRegistered('post') as $slug) {
+				$registrar = Registrar::getInstance($slug);
+				$pages[$slug] = $registrar->getPlural();
 			}
 
-			foreach (JVB_TAXONOMY as $slug=>$config) {
-				$pages[$slug] = $config['plural'];
+			foreach (Registrar::getRegistered('term') as $slug) {
+				$registrar = Registrar::getInstance($slug);
+				$pages[$slug] = $registrar->getPlural();
 			}
 
 			// Allow filtering
@@ -1309,21 +1320,6 @@
 		return $pages;
 	}
 
-	/**
-	 * Get pages available to a specific role
-	 * @param string $role The role slug (with or without BASE prefix)
-	 * @return array
-	 */
-	protected function getRolePages(string $role):array
-	{
-		$role = jvbNoBase($role);
-
-		if (!array_key_exists($role, JVB_USER)) {
-			return [];
-		}
-
-		return Features::forUser($role)->getDashboardPages();
-	}
 
 	/**
 	 * Get pages that a specific user is allowed to access
@@ -1345,15 +1341,14 @@
 		}
 
 
-		$cacheKey = "user_pages_{$userID}";
-		$pages = $this->cache->get($cacheKey);
-		$pages = false;
+		$pages = $this->cache->get($userID);
+
 		if ($pages === false || JVB_TESTING) {
 			if (user_can($userID, 'manage_options')) {
 				// Admin gets all pages as flat array
 				$pages = $this->getAllDashboardPages();
 				// Extract just the values (slugs)
-				$this->cache->set($cacheKey, $pages, WEEK_IN_SECONDS);
+				$this->cache->set($userID, $pages, WEEK_IN_SECONDS);
 				return $pages;
 			}
 			$roles = array_map('jvbNoBase', $user->roles);
@@ -1364,21 +1359,23 @@
 				//Default to Remove pages
 				$remove = true;
 				if (!is_numeric($key)) {
-					$type  = Features::getType($key);
+					$registrar = Registrar::getInstance($key);
+					$membership = Site::membership();
+					$type  = $registrar? $registrar->getType() : false;
 					if ($type) {
-						$permission = RoleManager::getPlural($key);
+						$permission = JVB()->roles()->getPermission('edit', $key);
 					}
 					switch ($type) {
 						case 'content':
-							if (user_can($userID, "edit_{$permission}")) {
+							if (user_can($userID, $permission)) {
 								$remove = false;
 							}
 							break;
 						case 'taxonomy':
-							$config = Features::getConfig($key, 'taxonomy');
-							if (array_key_exists('is_content', $config) && $config['is_content'] && (user_can($userID, "own_{$key}") || user_can($userID, "manage_{$key}"))) {
+							$registrar = Registrar::getInstance($key);
+							if ($registrar && $registrar->hasFeature('is_content') && (!empty(JVB()->roles()->getOwnedTerms($userID, $key)) || !empty(JVB()->roles()->getManagedTerms($userID, $key)))){
 								$remove = false;
-							} else if (count(array_intersect($config['for_content'], array_keys($pages))) > 0) {
+							} else if (count(array_intersect($registrar->registrar->for, array_keys($pages))) > 0) {
 								$remove = false;
 							}
 							break;
@@ -1387,7 +1384,7 @@
 					switch ($slug) {
 						case 'Integrations':
 							foreach($roles as $role) {
-								if (Features::hasAnyIntegration('user', $role)) {
+								if (Registrar::getInstance($role)->hasAnyIntegrations()) {
 									$remove = false;
 								}
 							}
@@ -1400,14 +1397,15 @@
 								}
 							}
 							if ($remove) {
-								if ($canSkip || array_key_exists('invitable', $config)) {
+								//TODO: Figure out what $config was supposed to be
+								if ($canSkip || ($registrar && $registrar->hasFeature('invitable'))) {
 									$remove = false;
 								}
 							}
 							break;
 						case 'Approvals':
 							$canApprove = false;
-							if (Features::forMembership()->has('term_approval')) {
+							if ($membership && $membership->has('term_approval')) {
 								if (array_key_exists('can_approve', JVB_MEMBERSHIP)) {
 									foreach ($roles as $role) {
 										if (in_array($role, JVB_MEMBERSHIP['can_approve'])) {
@@ -1438,20 +1436,17 @@
 							break;
 						case 'metrics':
 							foreach ($roles as $role) {
-								if (!empty(Features::forUser($role)->getCreatableContent())) {
+								if (!empty(Registrar::getInstance($role)?->getCreatable())) {
 									$remove = false;
 								}
 							}
 							break;
 						case 'karmic-score':
 							foreach ($roles as $role) {
-								$contents = Features::forUser($role)->getCreatableContent();
+								$contents = Registrar::getInstance($role)?->getCreatable();
 								if (!empty($contents)) {
-									foreach($contents as $content) {
-										if (Features::forContent($content)->has('karma')) {
-											$remove = false;
-										}
-									}
+									$hasKarma = Registrar::getFeatured('karma');
+									$remove = empty(array_intersect($contents, $hasKarma));
 								}
 							}
 							break;
@@ -1475,7 +1470,7 @@
 			$pages = apply_filters('jvbUserDashboardPages', $pages, $user->roles, $userID);
 			$pages = array_unique($pages);
 
-			$this->cache->set($cacheKey, $pages, WEEK_IN_SECONDS);
+			$this->cache->set($userID, $pages, WEEK_IN_SECONDS);
 		}
 
 		return $pages;
@@ -1497,7 +1492,7 @@
 
 		$creatable = [];
 		foreach ($roles as $role) {
-			$roleCreatable = Features::forUser($role)->getCreatableContent();
+			$roleCreatable = Registrar::getInstance($role)?->getCreatable();
 			$creatable = array_merge($creatable, $roleCreatable);
 		}
 
@@ -1511,9 +1506,7 @@
 	 */
 	protected function getRolesWithDashboard():array
 	{
-		return array_keys(array_filter(JVB_USER, function ($role) {
-			return Features::forUser(array_search($role, JVB_USER))->has('has_dashboard');
-		}));
+		return Registrar::getFeatured('has_dashboard', 'user');
 	}
 
 	/**
@@ -1533,36 +1526,4 @@
 		return count(array_intersect($dashboardRoles, $userRoles)) > 0;
 	}
 
-	/**
-	 * Get the capability needed to access a content type
-	 * @param string $type
-	 * @return string
-	 */
-	protected function getPermissionForType(string $type):string
-	{
-		// Check if it's a registered content type
-		if (array_key_exists($type, JVB_CONTENT)) {
-			$plural = JVB_CONTENT[$type]['plural'];
-			return 'edit_'.$plural;
-		}
-
-		// Default to edit_{type}s
-		return 'edit_'.$type.'s';
-	}
-
-	/**
-	 * Invalidate dashboard page cache for a user or all users
-	 * Call this when user roles or permissions change
-	 * @param int|null $userID Specific user to invalidate, null for all
-	 * @return void
-	 */
-	public function invalidatePagesCache(?int $userID = null):void
-	{
-		if ($userID !== null) {
-			$this->cache->delete("user_pages_{$userID}");
-		} else {
-			// Invalidate all user caches by invalidating the group
-			$this->cache->invalidate();
-		}
-	}
 }

--
Gitblit v1.10.0