From ba1e1ccf869b818f7a7a897264dfea05563a7796 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 07 Jun 2026 20:10:20 +0000
Subject: [PATCH] =Major overhaul of Integrations. Playing around with adding fields to post types through Registrar from an integrations' class file.

---
 inc/managers/Notifications/Notifications.php      |   10 
 inc/managers/SEO/render/SchemaOutput.php          |    2 
 jvb.php                                           |   50 +++++
 inc/rest/routes/NotificationsRoutes.php           |    2 
 inc/registrar/config/Integration.php              |    8 
 inc/admin/ContentTaxonomy.php                     |    4 
 inc/managers/DashboardManager.php                 |   15 +
 inc/registrar/helpers/MakeTimelineType.php        |    4 
 inc/managers/CRUDManager.php                      |   11 
 inc/managers/RoleManager.php                      |    8 
 inc/rest/routes/FeedRoutes.php                    |    8 
 assets/js/min/favourites.min.js                   |    2 
 inc/rest/routes/ApprovalRoutes.php                |    4 
 inc/managers/_setup.php                           |    8 
 inc/blocks/RegisterBlocks.php                     |    4 
 JVBase.php                                        |    8 
 inc/managers/LoginManager.php                     |    3 
 inc/integrations/Square.php                       |   85 +++-----
 inc/managers/Notifications/EmailDigests.php       |    8 
 base/Site.php                                     |    4 
 inc/integrations/Integrations.php                 |   11 +
 inc/integrations/Facebook.php                     |    9 +
 inc/integrations/Instagram.php                    |    3 
 inc/managers/DirectoryManager.php                 |    6 
 inc/registrar/Registrar.php                       |   68 ++++++-
 activate.php                                      |    4 
 assets/js/concise/FrontendFavourites.js           |    3 
 inc/registrar/helpers/MakeCalendarType.php        |    9 
 inc/blocks/_setup.php                             |    8 
 inc/rest/routes/ContentTermsRoutes.php            |    2 
 inc/helpers/dashboard.php                         |    4 
 inc/blocks/FAQBlock.php                           |    2 
 inc/rest/_setup.php                               |    4 
 assets/js/concise/AuthManager.js                  |    1 
 assets/js/min/auth.min.js                         |    2 
 inc/registrar/config/Section.php                  |   13 
 inc/registrar/Fields.php                          |    2 
 inc/integrations/GoogleMyBusiness.php             |    5 
 checks.php                                        |    2 
 inc/registrar/fields/Field.php                    |   17 +
 inc/registrar/helpers/AddIntegrationFields.php    |    6 
 inc/managers/SEO/render/Thing/Product/Product.php |    7 
 inc/admin/_setup.php                              |    2 
 inc/managers/ApprovalManager.php                  |    2 
 inc/registrar/helpers/HideSingle.php              |    7 
 inc/integrations/GoogleMaps.php                   |    2 
 inc/rest/Rest.php                                 |    4 
 inc/rest/RestRouteManager.php                     |    4 
 inc/rest/routes/LoginRoutes.php                   |   31 +-
 inc/managers/VerifyEntryManager.php               |    2 
 inc/managers/InvitationsManager.php               |    8 
 51 files changed, 321 insertions(+), 177 deletions(-)

diff --git a/JVBase.php b/JVBase.php
index f0b0c3d..28efe56 100644
--- a/JVBase.php
+++ b/JVBase.php
@@ -151,7 +151,7 @@
 			$this->managers['notifications'] = new NotificationManager();
 			$this->routes['notifications'] = new NotificationsRoutes();
 		}
-		if (!empty(Registrar::getFeatured('approve_new'))) {
+		if (!empty(Registrar::withFeature('approve_new'))) {
 			$this->managers['approvals'] = new ApprovalManager();
 		}
 		if (Site::has('feed_block') || Site::has('dashboard')) {
@@ -183,13 +183,13 @@
 		if ($membership && $membership->has('invitable')) {
 			$this->managers['invitations'] = new InvitationsManager();
 		}
-		if (!empty(Registrar::getFeatured('has_responses'))) {
+		if (!empty(Registrar::withFeature('has_responses'))) {
 			$this->routes['comments'] = new ResponseRoutes();
 		}
-		if (!empty(Registrar::getFeatured('karma'))) {
+		if (!empty(Registrar::withFeature('karma'))) {
 			$this->routes['vote'] = new VoteRoutes();
 		}
-		if (!empty(Registrar::getFeatured('karma'))
+		if (!empty(Registrar::withFeature('karma'))
 			|| ($membership && $membership->has('member_verified')) ||
             ($membership && $membership->has('term_approval'))) {
 			$this->routes['approvals'] = new ApprovalRoutes();
diff --git a/activate.php b/activate.php
index c76a65d..af0f7a1 100644
--- a/activate.php
+++ b/activate.php
@@ -64,7 +64,7 @@
 
 	$role = get_role('administrator');
 	$users = get_users(['role' => 'administrator']);
-    foreach (array_merge(Registrar::getRegistered('post'), Registrar::getFeatured('is_content')) as $slug) {
+    foreach (array_merge(Registrar::getRegistered('post'), Registrar::withFeature('is_content')) as $slug) {
 		error_log('Adding administrative roles to '.$slug);
 		$plural = $roleManager->getContentPlural($slug);
 		$capabilities = [
@@ -105,7 +105,7 @@
 	$roleManager = new RoleManager();
 	$users = get_users(['role' => 'administrator']);
 
-	foreach (array_merge(Registrar::getRegistered('post'), Registrar::getFeatured('is_content', 'term')) as $slug) {
+	foreach (array_merge(Registrar::getRegistered('post'), Registrar::withFeature('is_content', 'term')) as $slug) {
 
 		foreach ($users as $user) {
 			// These methods should check if post type exists before adding caps
diff --git a/assets/js/concise/AuthManager.js b/assets/js/concise/AuthManager.js
index ab70c92..12a4a5f 100644
--- a/assets/js/concise/AuthManager.js
+++ b/assets/js/concise/AuthManager.js
@@ -127,6 +127,7 @@
 		this.authenticated = authData.authenticated || false;
 		this.user = authData.user || false;
 		this.nonces = authData.nonces || {};
+		console.log(this.nonces);
 
 		// Session expired — was logged in, now isn't
 		if (wasAuthenticated && !this.authenticated) {
diff --git a/assets/js/concise/FrontendFavourites.js b/assets/js/concise/FrontendFavourites.js
index e016107..661bbfc 100644
--- a/assets/js/concise/FrontendFavourites.js
+++ b/assets/js/concise/FrontendFavourites.js
@@ -7,6 +7,9 @@
 				storeName: 'favourites',
 				keyPath: 'id',
 				endpoint: 'favourites',
+				headers: {
+					'X-Action-Nonce': window.auth.getNonce('favourites')
+				},
 				indexes: [
 					{name: 'content', keyPath: 'content'},
 					{name: 'listId', keyPath: 'listId'},
diff --git a/assets/js/min/auth.min.js b/assets/js/min/auth.min.js
index 587eafa..daad9f4 100644
--- a/assets/js/min/auth.min.js
+++ b/assets/js/min/auth.min.js
@@ -1 +1 @@
-window.auth=new class{constructor(){this.initialized=!1,this.isAuthenticating=!1,this.authenticated=!1,this.user=!1,this.nonces={},this.subscribers=new Set,this.cacheExpiry=3e5,this.init()}async init(){if(!this.isAuthenticating){this.isAuthenticating=!0;try{if("undefined"!=typeof jvbAuth)return this.setAuthData(jvbAuth),this.initialized=!0,this.isAuthenticating=!1,void this.notify("auth-loaded",{fromCache:!1});await this.fetchAuth()}catch(t){this.clearAuthData(),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-error",{error:t})}}}async refreshNonce(t="wp_rest"){try{return await this.fetchAuth(),this.getNonce(t)}catch(t){return console.error("Failed to refresh nonce:",t),null}}async fetch(t,i={}){const e=async(s=0)=>{const h={...!(i.body instanceof FormData)&&{"Content-Type":"application/json"},...i.headers,"X-WP-Nonce":this.getNonce()},n=await fetch(t,{...i,credentials:"same-origin",headers:h});if((403===n.status||401===n.status)&&0===s){const t=await n.clone().json();if("rest_cookie_invalid_nonce"===t.code||t.message?.includes("Cookie check"))return console.log("Nonce invalid, refreshing auth..."),await this.refresh(),e(s+1)}return n};return e()}async fetchAuth(){const t=await fetch(`${jvbSettings.api}auth/status`,{method:"GET",credentials:"same-origin",headers:{"Content-Type":"application/json"}});if(!t.ok)throw new Error("Auth check failed");const i=await t.json();this.setAuthData(i),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-loaded",{fromCache:!1})}setAuthData(t){const i=this.initialized&&this.authenticated;this.authenticated=t.authenticated||!1,this.user=t.user||!1,this.nonces=t.nonces||{},i&&!this.authenticated&&(window.location.href=`/login?redirect_to=${encodeURIComponent(window.location.href)}`)}clearAuthData(){this.authenticated=!1,this.user=null,this.nonces={}}async refresh(){this.isAuthenticating=!0,this.initialized=!1;try{await this.fetchAuth(),this.notify("auth-refreshed",{})}catch(t){console.error("Failed to refresh auth:",t),this.clearAuthData(),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-error",{error:t})}}getNonce(t="wp_rest"){return this.nonces[t]||""}getUser(){return this.user}isAuthenticated(){return this.authenticated}async handleLogin(t=null){if(t)return this.setAuthData(t),this.initialized=!0,this.isAuthenticating=!1,void this.notify("auth-loaded",{fromCache:!1,fromLogin:!0});await this.refresh()}handleLogout(){this.clearAuthData(),this.notify("logged-out",{})}subscribe(t){return this.subscribers.add(t),this.initialized&&t("auth-loaded",{fromCache:!1,immediate:!0}),()=>this.subscribers.delete(t)}notify(t,i){this.subscribers.forEach((e=>{try{e(t,i)}catch(t){console.error("Subscriber error:",t)}}))}};
\ No newline at end of file
+window.auth=new class{constructor(){this.initialized=!1,this.isAuthenticating=!1,this.authenticated=!1,this.user=!1,this.nonces={},this.subscribers=new Set,this.cacheExpiry=3e5,this.init()}async init(){if(!this.isAuthenticating){this.isAuthenticating=!0;try{if("undefined"!=typeof jvbAuth)return this.setAuthData(jvbAuth),this.initialized=!0,this.isAuthenticating=!1,void this.notify("auth-loaded",{fromCache:!1});await this.fetchAuth()}catch(t){this.clearAuthData(),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-error",{error:t})}}}async refreshNonce(t="wp_rest"){try{return await this.fetchAuth(),this.getNonce(t)}catch(t){return console.error("Failed to refresh nonce:",t),null}}async fetch(t,i={}){const e=async(s=0)=>{const n={...!(i.body instanceof FormData)&&{"Content-Type":"application/json"},...i.headers,"X-WP-Nonce":this.getNonce()},h=await fetch(t,{...i,credentials:"same-origin",headers:n});if((403===h.status||401===h.status)&&0===s){const t=await h.clone().json();if("rest_cookie_invalid_nonce"===t.code||t.message?.includes("Cookie check"))return console.log("Nonce invalid, refreshing auth..."),await this.refresh(),e(s+1)}return h};return e()}async fetchAuth(){const t=await fetch(`${jvbSettings.api}auth/status`,{method:"GET",credentials:"same-origin",headers:{"Content-Type":"application/json"}});if(!t.ok)throw new Error("Auth check failed");const i=await t.json();this.setAuthData(i),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-loaded",{fromCache:!1})}setAuthData(t){const i=this.initialized&&this.authenticated;this.authenticated=t.authenticated||!1,this.user=t.user||!1,this.nonces=t.nonces||{},console.log(this.nonces),i&&!this.authenticated&&(window.location.href=`/login?redirect_to=${encodeURIComponent(window.location.href)}`)}clearAuthData(){this.authenticated=!1,this.user=null,this.nonces={}}async refresh(){this.isAuthenticating=!0,this.initialized=!1;try{await this.fetchAuth(),this.notify("auth-refreshed",{})}catch(t){console.error("Failed to refresh auth:",t),this.clearAuthData(),this.initialized=!0,this.isAuthenticating=!1,this.notify("auth-error",{error:t})}}getNonce(t="wp_rest"){return this.nonces[t]||""}getUser(){return this.user}isAuthenticated(){return this.authenticated}async handleLogin(t=null){if(t)return this.setAuthData(t),this.initialized=!0,this.isAuthenticating=!1,void this.notify("auth-loaded",{fromCache:!1,fromLogin:!0});await this.refresh()}handleLogout(){this.clearAuthData(),this.notify("logged-out",{})}subscribe(t){return this.subscribers.add(t),this.initialized&&t("auth-loaded",{fromCache:!1,immediate:!0}),()=>this.subscribers.delete(t)}notify(t,i){this.subscribers.forEach((e=>{try{e(t,i)}catch(t){console.error("Subscriber error:",t)}}))}};
\ No newline at end of file
diff --git a/assets/js/min/favourites.min.js b/assets/js/min/favourites.min.js
index 359b69b..8369985 100644
--- a/assets/js/min/favourites.min.js
+++ b/assets/js/min/favourites.min.js
@@ -1 +1 @@
-(()=>{class t{constructor(){let t=window.jvbStore.register("favourites",{storeName:"favourites",keyPath:"id",endpoint:"favourites",indexes:[{name:"content",keyPath:"content"},{name:"listId",keyPath:"listId"}],TTL:36e4,showLoading:!1,filters:{user:window.auth.getUser(),content:"all",order:"desc",orderby:"date",page:1,all:!0}});this.store=t.favourites,this.store.subscribe(((t,e)=>{t}))}toggleFavourite(t){if(!window.auth.getUser())return void(window.location.href=jvbSettings.redirect+"&action=register&type=favourites");t.classList.toggle("favourited");const e=t.classList.contains("favourited")?"add":"remove",o=t.classList.contains("favourited")?`Added ${t.dataset.type} to favourites.`:`Removed ${t.dataset.type} from favourites.`;window.jvbA11y.announce(o),t.innerHTML=jvbSettings.icons[t.classList.contains("favourited")?"heart-filled":"heart"],this.store.setItem(t.dataset.id,{target_id:t.dataset.id,action:e,type:t.dataset.type,artist:t.dataset.artist})}isFavourited(t,e){const o=`${this.userId}_${t}_${e}`;return void 0!==this.store.get(o)}}document.addEventListener("DOMContentLoaded",(function(){window.jvbFavourites=!1,window.auth.subscribe((e=>{"auth-loaded"===e&&(window.jvbFavourites=new t)}))})),window.toggleFavourite=function(t){window.jvbFavourites()?window.jvbFavourites.toggleFavourite(t):console.log("No Favourites Loaded")},window.isFavourited=function(t,e){if(window.jvbFavourites())return window.jvbFavourites.isFavourited(t,e);console.log("No Favourites Loaded")}})();
\ No newline at end of file
+(()=>{class t{constructor(){let t=window.jvbStore.register("favourites",{storeName:"favourites",keyPath:"id",endpoint:"favourites",headers:{"X-Action-Nonce":window.auth.getNonce("favourites")},indexes:[{name:"content",keyPath:"content"},{name:"listId",keyPath:"listId"}],TTL:36e4,showLoading:!1,filters:{user:window.auth.getUser(),content:"all",order:"desc",orderby:"date",page:1,all:!0}});this.store=t.favourites,this.store.subscribe(((t,e)=>{t}))}toggleFavourite(t){if(!window.auth.getUser())return void(window.location.href=jvbSettings.redirect+"&action=register&type=favourites");t.classList.toggle("favourited");const e=t.classList.contains("favourited")?"add":"remove",o=t.classList.contains("favourited")?`Added ${t.dataset.type} to favourites.`:`Removed ${t.dataset.type} from favourites.`;window.jvbA11y.announce(o),t.innerHTML=jvbSettings.icons[t.classList.contains("favourited")?"heart-filled":"heart"],this.store.setItem(t.dataset.id,{target_id:t.dataset.id,action:e,type:t.dataset.type,artist:t.dataset.artist})}isFavourited(t,e){const o=`${this.userId}_${t}_${e}`;return void 0!==this.store.get(o)}}document.addEventListener("DOMContentLoaded",(function(){window.jvbFavourites=!1,window.auth.subscribe((e=>{"auth-loaded"===e&&(window.jvbFavourites=new t)}))})),window.toggleFavourite=function(t){window.jvbFavourites()?window.jvbFavourites.toggleFavourite(t):console.log("No Favourites Loaded")},window.isFavourited=function(t,e){if(window.jvbFavourites())return window.jvbFavourites.isFavourited(t,e);console.log("No Favourites Loaded")}})();
\ No newline at end of file
diff --git a/base/Site.php b/base/Site.php
index e082012..43d194a 100644
--- a/base/Site.php
+++ b/base/Site.php
@@ -1,8 +1,6 @@
 <?php
 namespace JVBase\base;
 
-use JVBase\base\Login;
-
 if (!defined('ABSPATH')) {
 	exit;
 }
@@ -92,7 +90,7 @@
 	public static function getInstance():Site {
 		if (!isset(self::$instance)) {
 			self::$instance = new self();
-			do_action('jvbLoadDefinitions');
+			do_action('jvb_define_site');
 		}
 		return self::$instance;
 	}
diff --git a/checks.php b/checks.php
index 6b55711..d968100 100644
--- a/checks.php
+++ b/checks.php
@@ -14,7 +14,7 @@
 
 function jvbUserTypes():array
 {
-	return  Registrar::getFeatured('profile_link', 'user');
+	return  Registrar::withFeature('profile_link', 'user');
 }
 
 
diff --git a/inc/admin/ContentTaxonomy.php b/inc/admin/ContentTaxonomy.php
index 399d3ac..0863a1e 100644
--- a/inc/admin/ContentTaxonomy.php
+++ b/inc/admin/ContentTaxonomy.php
@@ -17,7 +17,7 @@
 {
     public function __construct()
     {
-		if (empty(Registrar::getFeatured('is_content', 'term'))){
+		if (empty(Registrar::withFeature('is_content', 'term'))){
 			return;
 		}
         add_filter(BASE.'handle_bulk_operation', [ $this, 'processOperation' ], 10, 3);
@@ -124,7 +124,7 @@
                     </thead>
                     <tbody>
                     <?php
-					$taxonomies = Registrar::getFeatured('is_content', 'term');
+					$taxonomies = Registrar::withFeature('is_content', 'term');
 					foreach ($taxonomies as $slug):
 						$registrar = Registrar::getInstance($slug);
                         $taxonomy = BASE . $slug;
diff --git a/inc/admin/_setup.php b/inc/admin/_setup.php
index 6ae125f..31d7b6c 100644
--- a/inc/admin/_setup.php
+++ b/inc/admin/_setup.php
@@ -8,7 +8,7 @@
 add_action('init', 'jvb_maybe_setup_content_taxonomy', 1);
 function jvb_maybe_setup_content_taxonomy(): void
 {
-	if (!empty(Registrar::getFeatured('is_content', 'term'))) {
+	if (!empty(Registrar::withFeature('is_content', 'term'))) {
 		require(JVB_DIR . '/inc/admin/ContentTaxonomy.php');
 	}
 }
diff --git a/inc/blocks/FAQBlock.php b/inc/blocks/FAQBlock.php
index 81e3db9..fd6d84d 100644
--- a/inc/blocks/FAQBlock.php
+++ b/inc/blocks/FAQBlock.php
@@ -32,7 +32,7 @@
 		);
 
 
-		$faq = array_values(Registrar::getFeatured('is_faq','post'));
+		$faq = array_values(Registrar::withFeature('is_faq','post'));
 		$registrar = Registrar::getInstance($faq[0]);
 		$this->section = array_map('jvbCheckBase', $registrar->registrar->taxonomies)[0];
 		$this->postType = $registrar->getBased();
diff --git a/inc/blocks/RegisterBlocks.php b/inc/blocks/RegisterBlocks.php
index e9811ff..efe6e51 100644
--- a/inc/blocks/RegisterBlocks.php
+++ b/inc/blocks/RegisterBlocks.php
@@ -14,7 +14,7 @@
 require(JVB_DIR . '/build/summary/render.php');
 require(JVB_DIR . '/build/forms/render.php');
 require(JVB_DIR . '/build/menu/render.php');
-if (!empty(Registrar::getFeatured('is_glossary'))) {
+if (!empty(Registrar::withFeature('is_glossary'))) {
 	error_log('Has Glossary Type');
 	require(JVB_DIR . '/build/glossary/render.php');
 }
@@ -39,7 +39,7 @@
 //            ]
 //        );
 //    }
-	if (!empty(Registrar::getFeatured('show_directory'))) {
+	if (!empty(Registrar::withFeature('show_directory'))) {
         register_block_type(
             JVB_DIR . '/build/list',
             [
diff --git a/inc/blocks/_setup.php b/inc/blocks/_setup.php
index cdae9f1..42ec61d 100644
--- a/inc/blocks/_setup.php
+++ b/inc/blocks/_setup.php
@@ -20,17 +20,17 @@
 		new JVBase\blocks\MenuBlock();
 	}
 
-	if (!empty(Registrar::getFeatured('is_faq'))) {
+	if (!empty(Registrar::withFeature('is_faq'))) {
 		require('FAQBlock.php');
 		new JVBase\blocks\FAQBlock();
 	}
 
-	if (!empty(Registrar::getFeatured('is_glossary'))) {
+	if (!empty(Registrar::withFeature('is_glossary'))) {
 		require('GlossaryBlock.php');
 		new JVBase\blocks\GlossaryBlock();
 	}
 
-	if (!empty(Registrar::getFeatured('is_timeline'))) {
+	if (!empty(Registrar::withFeature('is_timeline'))) {
 		require('TimelineBlock.php');
 		new JVBase\blocks\TimelineBlock();
 	}
@@ -47,7 +47,7 @@
 //            ]
 //        );
 //    }
-//	if (!empty(Registrar::getFeatured('show_directory'))) {
+//	if (!empty(Registrar::withFeature('show_directory'))) {
 //		error_log('Registering Directory List Block');
 //		register_block_type(
 //			JVB_DIR . '/build/list',
diff --git a/inc/helpers/dashboard.php b/inc/helpers/dashboard.php
index bd1b1ac..918200d 100644
--- a/inc/helpers/dashboard.php
+++ b/inc/helpers/dashboard.php
@@ -62,7 +62,7 @@
             array_map(function ($role) {
                 return BASE.$role;
             },
-               Registrar::getFeatured('has_dashboard', 'user'))
+               Registrar::withFeature('has_dashboard', 'user'))
         )
     )>0;
 }
@@ -109,7 +109,7 @@
             }
         }
 
-        $types = Registrar::getFeatured('show_feed');
+        $types = Registrar::withFeature('show_feed');
         $types = array_filter($temp, function ($type) use ($types) {
             return in_array($type, $types);
         });
diff --git a/inc/integrations/Facebook.php b/inc/integrations/Facebook.php
index 197ca61..e7d54e9 100644
--- a/inc/integrations/Facebook.php
+++ b/inc/integrations/Facebook.php
@@ -17,6 +17,15 @@
 class Facebook extends Integrations
 {
 	// Facebook-specific properties
+	protected array $allowedContent = [
+		'post',
+		'photo',
+		'video',
+		'event',
+		'offer',
+		'note',
+		'milestone'
+	];
 	private string $page_id = '';
 	private string $page_access_token = '';
 	private array $permissions = [];
diff --git a/inc/integrations/GoogleMaps.php b/inc/integrations/GoogleMaps.php
index 68d58fa..31a3d36 100644
--- a/inc/integrations/GoogleMaps.php
+++ b/inc/integrations/GoogleMaps.php
@@ -542,7 +542,7 @@
 			return true;
 		}
 
-		if (!empty(Registrar::getFeatured('is_content', 'term')) && get_term_meta(get_queried_object_id(), BASE . 'has_map', true) === true) {
+		if (!empty(Registrar::withFeature('is_content', 'term')) && get_term_meta(get_queried_object_id(), BASE . 'has_map', true) === true) {
 			return true;
 		}
 
diff --git a/inc/integrations/GoogleMyBusiness.php b/inc/integrations/GoogleMyBusiness.php
index 9e86377..5893851 100644
--- a/inc/integrations/GoogleMyBusiness.php
+++ b/inc/integrations/GoogleMyBusiness.php
@@ -9,6 +9,11 @@
 
 class GoogleMyBusiness extends Integrations
 {
+	protected array $allowedContent = [
+		'menu_item',
+		'post',
+		'event',
+	];
 	private ?string $access_token = null;
 	protected string $readMask = 'name,title,storefrontAddress,metadata,openInfo,storeCode,categories,phoneNumbers,labels,specialHours';
 	private ?string $location = null;
diff --git a/inc/integrations/Instagram.php b/inc/integrations/Instagram.php
index 63910b1..4513381 100644
--- a/inc/integrations/Instagram.php
+++ b/inc/integrations/Instagram.php
@@ -17,6 +17,9 @@
 
 class Instagram extends Integrations
 {
+	protected array $allowedContent = [
+		'post'
+	];
 	private string $ig_user_id = '';
 	private string $page_id = '';
 	private string $page_access_token = '';
diff --git a/inc/integrations/Integrations.php b/inc/integrations/Integrations.php
index 7b32588..ef1a135 100644
--- a/inc/integrations/Integrations.php
+++ b/inc/integrations/Integrations.php
@@ -29,6 +29,15 @@
 abstract class Integrations
 {
 	/**
+	 * Queue types
+	 * These types match with IntegrationExecutor
+	 */
+	protected static string $syncTo = 'sync_to';
+	protected static string $deleteFrom = 'delete_from';
+	protected static string $syncFrom = 'sync_from';
+	protected static string $syncCustomer = 'sync_customer';
+	protected static string $import = 'import';
+	/**
 	 * API Configuration
 	 * These properties define how the integration connects to external services
 	 */
@@ -319,7 +328,7 @@
 		if (!$taxonomies) {
 			// Combine both content and taxonomy filtering
 			$taxonomies = [];
-			foreach (Registrar::getFeatured('is_content', 'term') as $type) {
+			foreach (Registrar::withFeature('is_content', 'term') as $type) {
 				$registrar = Registrar::getInstance($type);
 				if ($registrar->hasIntegration($this->service_name)) {
 					$taxonomies[] = $registrar->getSlug();
diff --git a/inc/integrations/Square.php b/inc/integrations/Square.php
index ba37b92..a6346f1 100644
--- a/inc/integrations/Square.php
+++ b/inc/integrations/Square.php
@@ -26,6 +26,14 @@
  */
 class Square extends Integrations
 {
+	protected array $allowedContent = [
+		'REGULAR',
+		'FOOD_AND_BEV',
+		'APPOINTMENTS_SERVICE',
+		'DIGITAL',
+		'EVENT',
+		'DONATION'
+	];
 	/**
 	 * Square API Configuration
 	 */
@@ -45,6 +53,9 @@
 	 * OAuth Configuration
 	 */
 	protected bool $isOAuthService = true;
+
+	protected string $orderPostType = '_sq_order';
+	protected array $newOrder = [];
 	protected array $oauth = [
 		'authorize' => '',
 		'token' => '',
@@ -80,6 +91,11 @@
 
 		$this->refresh_interval = 7 * DAY_IN_SECONDS;
 
+		$this->newOrder = [
+			'post_type'		=> $this->orderPostType,
+			'post_status' 	=> 'PROPOSED',
+		];
+
 		// Define credential fields
 		$this->fields = [
 			'environment'	=> [
@@ -180,8 +196,7 @@
 				'sync_to_square' => 'Sync Site to Square',
 			]
 		);
-
-		add_action('init', [$this, 'registerSquarePostTypes']);
+		add_action('init', [$this, 'registerSquarePostTypes'], 5);
 	}
 
 	/**
@@ -228,24 +243,20 @@
 					'square_order_id' => [
 						'type' => 'text',
 						'label' => 'Square Order ID',
-						'readonly' => true
 					],
 					'square_payment_id' => [
 						'type' => 'text',
 						'label' => 'Square Payment ID',
-						'readonly' => true
 					],
 					'square_customer_id' => [
 						'type' => 'text',
 						'label' => 'Square Customer ID',
-						'readonly' => true
 					],
 					'amount' => [
 						'type' => 'number',
 						'label' => 'Total Amount (cents)',
-						'readonly' => true
 					],
-					'status' => [
+					'post_status' => [
 						'type' => 'select',
 						'label' => 'Order Status',
 						'options' => [
@@ -255,7 +266,6 @@
 							'COMPLETED' => 'Completed',
 							'CANCELED' => 'Canceled'
 						],
-						'readonly' => true
 					],
 					'fulfillment_status' => [
 						'type' => 'select',
@@ -268,7 +278,6 @@
 							'CANCELED' => 'Canceled',
 							'FAILED' => 'Failed'
 						],
-						'readonly' => true
 					],
 					'pickup_time' => [
 						'type' => 'datetime',
@@ -277,27 +286,22 @@
 					'customer_email' => [
 						'type' => 'email',
 						'label' => 'Customer Email',
-						'readonly' => true
 					],
 					'customer_name' => [
 						'type' => 'text',
 						'label' => 'Customer Name',
-						'readonly' => true
 					],
 					'customer_phone' => [
-						'type' => 'tel',
+						'type' => 'phone',
 						'label' => 'Customer Phone',
-						'readonly' => true
 					],
 					'special_instructions' => [
 						'type' => 'textarea',
 						'label' => 'Special Instructions',
-						'readonly' => true
 					],
 					'items' => [
 						'type' => 'repeater',
 						'label' => 'Order Items',
-						'readonly' => true,
 						'fields' => [
 							'name' => ['type' => 'text', 'label' => 'Item Name'],
 							'quantity' => ['type' => 'number', 'label' => 'Quantity'],
@@ -308,17 +312,14 @@
 					'receipt_url' => [
 						'type' => 'url',
 						'label' => 'Receipt URL',
-						'readonly' => true
 					],
 					'created_at' => [
 						'type' => 'datetime',
 						'label' => 'Created At',
-						'readonly' => true
 					],
 					'updated_at' => [
 						'type' => 'datetime',
 						'label' => 'Last Updated',
-						'readonly' => true
 					]
 				];
 	}
@@ -327,16 +328,14 @@
 	{
 		$orders = Registrar::forPost('_sq_orders', 'Square Order', 'Square Orders');
 		$orders->make([
-			'public'	=> false
-			]
-		);
+			'public'	=> true
+		]);
 		$orders->setAll(['system']);
 
 		$fields = $orders->fields();
 		foreach ($this->getOrderFields() as $fieldName => $config) {
 			$fields->addField($fieldName, $config);
 		}
-
 	}
 
 	/**
@@ -845,10 +844,9 @@
 		add_action('wp_login', [$this, 'trackUserLogin'], 10, 2);
 		add_action('wp_enqueue_scripts', [$this, 'enqueueScripts']);
 
-		// Shared checkout UI (replaces outputCheckout)
 		add_filter('jvbAdditionalActions', [Checkout::class, 'render']);
 
-		// Square-specific checkout description
+
 		add_filter('jvb_checkout_description', function (string $desc, string $provider) {
 			if ($provider === 'square') {
 				return 'Securely checkout with your name, email, and payments processed by Square.';
@@ -902,31 +900,31 @@
 		$queue    = JVB()->queue();
 		$executor = new IntegrationExecutor();
 
-		$queue->registry()->register('square_sync_to', new TypeConfig(
+		$queue->registry()->register(self::$syncTo, new TypeConfig(
 			executor:   $executor,
 			chunkKey:   'items',
 			chunkSize:  50,
 			maxRetries: 3
 		));
 
-		$queue->registry()->register('square_delete_from', new TypeConfig(
+		$queue->registry()->register(self::$deleteFrom, new TypeConfig(
 			executor:   $executor,
 			chunkKey:   'external_ids',
 			chunkSize:  200,
 			maxRetries: 2
 		));
 
-		$queue->registry()->register('square_sync_from', new TypeConfig(
+		$queue->registry()->register(self::$syncFrom, new TypeConfig(
 			executor:   $executor,
 			maxRetries: 3
 		));
 
-		$queue->registry()->register('square_sync_customer', new TypeConfig(
+		$queue->registry()->register(self::$syncCustomer, new TypeConfig(
 			executor:   $executor,
 			maxRetries: 2
 		));
 
-		$queue->registry()->register('square_import', new TypeConfig(
+		$queue->registry()->register(self::$import, new TypeConfig(
 			executor:   $executor,
 			maxRetries: 3
 		));
@@ -941,7 +939,7 @@
 	 */
 	protected function handleTheSavePost(int $postID, \WP_Post $post, bool $update, array $settings): void
 	{
-		$this->queueOperation('sync_to', [
+		$this->queueOperation(self::$syncTo, [
 			'items'   => [$postID],
 			'user_id' => $this->userID,
 		], [
@@ -960,7 +958,7 @@
 		$square_id = get_post_meta($postID, BASE . '_square_catalog_id', true);
 
 		if ($square_id) {
-			$this->queueOperation('delete_from', [
+			$this->queueOperation(self::$deleteFrom, [
 				'external_ids' => [$square_id],
 				'post_id'      => $postID,
 			], [
@@ -970,26 +968,6 @@
 	}
 
 	/**
-	 * @deprecated IntegrationExecutor handles new operations via registerQueueTypes().
-	 * Kept for legacy-typed operations ('square_sync_to_square') already queued.
-	 * Safe to remove once all legacy operations have been processed.
-	 */
-	public function processOperation(WP_Error|array $result, object $operation, array $data): WP_Error|array
-	{
-		$base   = strtolower($this->service_name) . '_';
-		$square = array_key_exists('user', $data) ? new self((int) $data['user']) : $this;
-
-		return match ($operation->type) {
-			$base . 'sync_to_square'     => $square->processSyncToSquare($data),
-			$base . 'delete_from_square' => $square->processDeleteFromSquare($data),
-			$base . 'sync_from_square'   => $square->processSyncFromSquare($data),
-			$base . 'sync_customer'      => $square->processSyncCustomer($data),
-			default                      => $result,
-		};
-	}
-
-
-	/**
 	 * Process sync to Square
 	 */
 	private function processSyncToSquare(array $data): array
@@ -2764,17 +2742,18 @@
 			return [];
 		}
 		$array = $this->setBaseFields();
-		return array_combine(
+		$return = array_combine(
 			array_map(fn($k) => 'sq_' . $k, array_keys($array)),
 			$array
 		);
+
+		return $return;
 	}
 	protected function setBaseFields():array
 	{
 		return [
 			'price' => [
 				'type'        => 'number',
-				'bulkEdit'    => true,
 				'label'       => 'Price',
 				'step'        => 0.01,
 				'max'         => 99999,
diff --git a/inc/managers/ApprovalManager.php b/inc/managers/ApprovalManager.php
index 42200e0..38a4f3a 100644
--- a/inc/managers/ApprovalManager.php
+++ b/inc/managers/ApprovalManager.php
@@ -32,7 +32,7 @@
 
 	protected function defineTables():void
 	{
-		$types = Registrar::getFeatured('approve_new');
+		$types = Registrar::withFeature('approve_new');
 		foreach ($types as $type) {
 			$requests = CustomTable::for("approval_{$type}_requests");
 			$registrar = Registrar::getInstance($type);
diff --git a/inc/managers/CRUDManager.php b/inc/managers/CRUDManager.php
index badcd6d..58aa17d 100644
--- a/inc/managers/CRUDManager.php
+++ b/inc/managers/CRUDManager.php
@@ -64,9 +64,14 @@
 		// Fields and sections
 		$this->skeleton->setFields($this->registrar->getFields());
 
-		foreach ($this->registrar->getSections() as $config) {
-			$this->skeleton->addSection($config['id'], $config);
-		}
+		jvbDump($this->registrar->getSections());
+        $sections = $this->registrar->getSections();
+        if (count($sections) > 1) {
+            foreach ($sections as $config) {
+                jvbDump($config);
+                $this->skeleton->addSection($config['id'], $config);
+            }
+        }
 
 		// Taxonomies
 		$this->initTaxonomies();
diff --git a/inc/managers/DashboardManager.php b/inc/managers/DashboardManager.php
index 395e6c2..bb671e8 100644
--- a/inc/managers/DashboardManager.php
+++ b/inc/managers/DashboardManager.php
@@ -641,7 +641,10 @@
 				}
 
 			}
-			return $icon;
+			return match($icon) {
+				'favourites'	=> 'heart',
+				default => $icon
+			};
 		});
 	}
 	protected function getSlug(string $slug, string $page):string
@@ -744,7 +747,7 @@
 			//content types
 		$all = array_merge(
 			Registrar::getRegistered('post'),
-			Registrar::getFeatured('is_content', 'term')
+			Registrar::withFeature('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);
@@ -1091,7 +1094,7 @@
         <?php
         $i=1;
         $content = Registrar::getRegistered('post');
-        $contentTax = Registrar::getFeatured('is_content', 'term');
+        $contentTax = Registrar::withFeature('is_content', 'term');
         $taxonomies = Registrar::getRegistered('term');
         foreach($contentTax as $index => $tax) {
             unset($taxonomies[$index]);
@@ -1284,7 +1287,7 @@
 				$pages[] = 'Favourites';
 			}
 
-			if (!empty(Registrar::getFeatured('karma'))) {
+			if (!empty(Registrar::withFeature('karma'))) {
 				$pages[] = 'Karmic Score';
 			}
 
@@ -1451,7 +1454,7 @@
 							foreach ($roles as $role) {
 								$contents = Registrar::getInstance($role)?->getCreatable();
 								if (!empty($contents)) {
-									$hasKarma = Registrar::getFeatured('karma');
+									$hasKarma = Registrar::withFeature('karma');
 									$remove = empty(array_intersect($contents, $hasKarma));
 								}
 							}
@@ -1512,7 +1515,7 @@
 	 */
 	protected function getRolesWithDashboard():array
 	{
-		return Registrar::getFeatured('has_dashboard', 'user');
+		return Registrar::withFeature('has_dashboard', 'user');
 	}
 
 	/**
diff --git a/inc/managers/DirectoryManager.php b/inc/managers/DirectoryManager.php
index 4645f97..ffe4843 100644
--- a/inc/managers/DirectoryManager.php
+++ b/inc/managers/DirectoryManager.php
@@ -90,21 +90,21 @@
 			$directories = [];
 			//content
 
-			$content = Registrar::getFeatured('show_directory', 'post');
+			$content = Registrar::withFeature('show_directory', 'post');
 			if(!empty($content)) {
 				foreach ($content as $key) {
 					$directories[$key] = 'content';
 				}
 			}
 
-			$taxonomies = Registrar::getFeatured('show_directory', 'term');
+			$taxonomies = Registrar::withFeature('show_directory', 'term');
 			if(!empty($taxonomies)) {
 				foreach ($taxonomies as $key) {
 					$directories[$key] = 'taxonomy';
 				}
 			}
 
-			$users = Registrar::getFeatured('show_directory', 'user');
+			$users = Registrar::withFeature('show_directory', 'user');
 			if(!empty($users)) {
 				foreach ($users as $key) {
 					$directories[$key] = 'user';
diff --git a/inc/managers/InvitationsManager.php b/inc/managers/InvitationsManager.php
index c8d17a2..da6cec1 100644
--- a/inc/managers/InvitationsManager.php
+++ b/inc/managers/InvitationsManager.php
@@ -36,7 +36,7 @@
 
 	public function defineTable():void
 	{
-		$terms = Registrar::getFeatured('invitable', 'term');
+		$terms = Registrar::withFeature('invitable', 'term');
 		$membership = Site::membership();
 		$roles = ($membership) ? Site::membership()->has('can_invite') :[];
 		if (empty($terms) && empty($roles)) {
@@ -163,9 +163,9 @@
 				}
 
 				// Term invitations from invitable content taxonomies
-				$invitable = Registrar::getFeatured('invitable', 'term');
-				$content = Registrar::getFeatured('is_content', 'term');
-				$ownable = Registrar::getFeatured('is_ownable', 'term');
+				$invitable = Registrar::withFeature('invitable', 'term');
+				$content = Registrar::withFeature('is_content', 'term');
+				$ownable = Registrar::withFeature('is_ownable', 'term');
 				$taxonomies = array_intersect($invitable, $content, $ownable);
 				if (!empty($taxonomies)) {
 					$users = Registrar::getRegistered('user');
diff --git a/inc/managers/LoginManager.php b/inc/managers/LoginManager.php
index 39930db..5e0e37b 100644
--- a/inc/managers/LoginManager.php
+++ b/inc/managers/LoginManager.php
@@ -143,7 +143,7 @@
 					'hint'	=> 'Have a referral code? Paste it here!'
 				];
 			}
-			$canRegister = Registrar::getFeatured('can_register', 'user');
+			$canRegister = Registrar::withFeature('can_register', 'user');
 			if (!empty($canRegister)) {
 				foreach ($canRegister as $role) {
 					$registrar = Registrar::getInstance($role);
@@ -456,6 +456,7 @@
 	protected function customStyles():void
 	{
 		$logo = get_theme_mod('custom_logo');
+		$small = $large = '';
 		if ($logo) {
 			$small = wp_get_attachment_image_src($logo, 'medium')[0]??'';
 			$large = wp_get_attachment_image_src($logo, 'large')[0]??'';
diff --git a/inc/managers/Notifications/EmailDigests.php b/inc/managers/Notifications/EmailDigests.php
index 8ab699e..841ffaf 100644
--- a/inc/managers/Notifications/EmailDigests.php
+++ b/inc/managers/Notifications/EmailDigests.php
@@ -43,7 +43,7 @@
 		protected function registerUserIndex():void
 		{
 			$table = CustomTable::for('user_notification_email_digest');
-//		$types = implode(',',array_map(function($item) { return "'{$item}'"; }, Registrar::getFeatured('favouritable')));
+//		$types = implode(',',array_map(function($item) { return "'{$item}'"; }, Registrar::withFeature('favouritable')));
 			$table->setColumns([
 				'id'			=> 'bigint(20) unsigned NOT NULL AUTO_INCREMENT',
 				'user_id'		=> "{$table->getUserIDType()} NOT NULL",
@@ -71,7 +71,7 @@
 		protected function registerTermIndex():void
 		{
 			$table = CustomTable::for('user_notification_email_digest');
-			$types = implode(',',array_map(function($item) { return "'{$item}'"; }, Registrar::getFeatured('favouritable', 'term')));
+			$types = implode(',',array_map(function($item) { return "'{$item}'"; }, Registrar::withFeature('favouritable', 'term')));
 			$table->setColumns([
 				'id'			=> 'bigint(20) unsigned NOT NULL AUTO_INCREMENT',
 				'term_id'		=> "{$table->getTermIDType()} NOT NULL",
@@ -187,8 +187,8 @@
 		$content = '';
 		foreach ($subscription as $item) {
 			$temp = match ($item['item_type']) {
-				array_merge(['user'], Registrar::getFeatured('favouritable', 'user')) => $this->getUserUpdates($item['item_id'], $frequency),
-				Registrar::getFeatured('favouritable', 'term') => $this->getTermUpdates($item['item_id'], $item['item_type'], $frequency),
+				array_merge(['user'], Registrar::withFeature('favouritable', 'user')) => $this->getUserUpdates($item['item_id'], $frequency),
+				Registrar::withFeature('favouritable', 'term') => $this->getTermUpdates($item['item_id'], $item['item_type'], $frequency),
 				default => false,
 			};
 			if ($temp) {
diff --git a/inc/managers/Notifications/Notifications.php b/inc/managers/Notifications/Notifications.php
index 4700c1d..61ee88c 100644
--- a/inc/managers/Notifications/Notifications.php
+++ b/inc/managers/Notifications/Notifications.php
@@ -46,8 +46,8 @@
 				]
 			]);
 		}
-		$contentTax = Registrar::getFeatured('is_content', 'term');
-		$verifyEntry = Registrar::getFeatured('verify_entry', 'term');
+		$contentTax = Registrar::withFeature('is_content', 'term');
+		$verifyEntry = Registrar::withFeature('verify_entry', 'term');
 		if (!empty(array_intersect($contentTax, $verifyEntry))) {
 			$types = array_merge($types, [
 				'entry_requested'  => [
@@ -69,7 +69,7 @@
 				]
 			]);
 		}
-		$invitable = Registrar::getFeatured('invitable');
+		$invitable = Registrar::withFeature('invitable');
 		if (!empty($invitable)) {
 			$types = array_merge($types, [
 				'invitation_requested' => [
@@ -97,12 +97,12 @@
 			]);
 		}
 
-		$approvals = Registrar::getFeatured('approve_new');
+		$approvals = Registrar::withFeature('approve_new');
 		if (!empty($approvals)) {
 			$tmp = ['user', 'term', 'post'];
 			$app = [];
 			foreach ($tmp as $t) {
-				$approvals = Registrar::getFeatured('approve_new', $t);
+				$approvals = Registrar::withFeature('approve_new', $t);
 				if (!empty($approvals)) {
 					$app = array_merge($app, [
 						$t.'_new' => [
diff --git a/inc/managers/RoleManager.php b/inc/managers/RoleManager.php
index b275f12..a22b585 100644
--- a/inc/managers/RoleManager.php
+++ b/inc/managers/RoleManager.php
@@ -24,7 +24,7 @@
 		   return strtolower(str_replace(' ', '_', $registrar->getPlural()??$registrar->getSingular().'s'));
 	   },array_merge(
 		   Registrar::getRegistered('post'),
-		   Registrar::getFeatured('is_content', 'term')
+		   Registrar::withFeature('is_content', 'term')
 	   ));
 	   add_action('set_user_role', [$this, 'updateRoles'], 10, 3);
 
@@ -470,7 +470,7 @@
 		protected function addAdminCaps():void
 		{
 			$users = get_users(['role' => 'administrator']);
-			foreach (array_merge(Registrar::getRegistered('post'), Registrar::getFeatured('is_content')) as $slug) {
+			foreach (array_merge(Registrar::getRegistered('post'), Registrar::withFeature('is_content')) as $slug) {
 				$this->grantRoleCapabilities('administrator', $slug);
 				$this->grantRoleOthersCapabilities('administrator', $slug);
 
@@ -785,7 +785,7 @@
 		if ($ownable === null) {
 			$ownable = array_map(function ($instance) {
 				return $instance->slug;
-			}, Registrar::getFeatured('is_ownable', 'term'));
+			}, Registrar::withFeature('is_ownable', 'term'));
 		}
 
 		return $ownable;
@@ -803,7 +803,7 @@
 		if ($invitable === null) {
 			$invitable = array_map(function ($instance) {
 				return $instance->slug;
-			}, Registrar::getFeatured('invitable', 'term'));
+			}, Registrar::withFeature('invitable', 'term'));
 		}
 
 		return $invitable;
diff --git a/inc/managers/SEO/render/SchemaOutput.php b/inc/managers/SEO/render/SchemaOutput.php
index a6cdc55..25ac320 100644
--- a/inc/managers/SEO/render/SchemaOutput.php
+++ b/inc/managers/SEO/render/SchemaOutput.php
@@ -64,7 +64,7 @@
 		}
 		$isContent = array_values(array_filter(array_map(function($item) {
 			return intval(get_option(BASE.$item.'_archive', false));
-		},Registrar::getFeatured('is_content', 'term'))));
+		},Registrar::withFeature('is_content', 'term'))));
 
 		if (!empty($isContent) && is_page($isContent)){
 			$type = get_post_meta(get_the_id(), BASE.'for_type', true);
diff --git a/inc/managers/SEO/render/Thing/Product/Product.php b/inc/managers/SEO/render/Thing/Product/Product.php
index b1ff016..b0c0a63 100644
--- a/inc/managers/SEO/render/Thing/Product/Product.php
+++ b/inc/managers/SEO/render/Thing/Product/Product.php
@@ -2,6 +2,7 @@
 namespace JVBase\managers\SEO\render\Thing\Product;
 
 
+use JVBase\managers\SEO\render\Thing\Thing;
 use JVBase\managers\SEO\render\Traits\_Properties\additionalPropertyTrait;
 use JVBase\managers\SEO\render\Traits\_Properties\aggregateRatingTrait;
 use JVBase\managers\SEO\render\Traits\_Properties\audienceTrait;
@@ -41,15 +42,13 @@
 use JVBase\managers\SEO\render\Traits\_Properties\sloganTrait;
 use JVBase\managers\SEO\render\Traits\_Properties\weightTrait;
 use JVBase\managers\SEO\render\Traits\_Properties\widthTrait;
-use JVBase\managers\SEO\render\Traits\ThingSchema;
 
 if (!defined('ABSPATH')) {
 	exit;
 }
 
-class Product  {
-	use ThingSchema,
-		additionalPropertyTrait, aggregateRatingTrait, audienceTrait,
+class Product  extends Thing {
+	use additionalPropertyTrait, aggregateRatingTrait, audienceTrait,
 		awardTrait, brandTrait, categoryTrait, colorTrait, countryOfAssemblyTrait,
 		countryOfOriginTrait, depthTrait, displayLocationTrait, hasAdultConsiderationTrait,
 		hasCertificationTrait, hasMeasurementTrait, hasMerchantReturnPolicyTrait,
diff --git a/inc/managers/VerifyEntryManager.php b/inc/managers/VerifyEntryManager.php
index 69bfb01..01fb039 100644
--- a/inc/managers/VerifyEntryManager.php
+++ b/inc/managers/VerifyEntryManager.php
@@ -17,7 +17,7 @@
 
 	protected function defineTables():void
 	{
-		$types = implode(',', array_map(function($item) { return "`{$item}`"; },Registrar::getFeatured('verify_entry')));
+		$types = implode(',', array_map(function($item) { return "`{$item}`"; },Registrar::withFeature('verify_entry')));
 
 		$table = CustomTable::for('verify_entry');
 
diff --git a/inc/managers/_setup.php b/inc/managers/_setup.php
index a2ca4ec..d55098a 100644
--- a/inc/managers/_setup.php
+++ b/inc/managers/_setup.php
@@ -49,7 +49,7 @@
 		require(JVB_DIR . '/inc/managers/UserTermsManager.php');
 	}
 
-	if (!empty(Registrar::getFeatured('approve_new'))) {
+	if (!empty(Registrar::withFeature('approve_new'))) {
 		require(JVB_DIR . '/inc/managers/ApprovalManager.php');
 	}
 
@@ -63,7 +63,7 @@
 			require(JVB_DIR . '/inc/managers/Notifications/Preferences.php');
 			require(JVB_DIR . '/inc/managers/NotificationManager.php');
 		}
-		if ($membership->has('forum') && !empty(Registrar::getFeatured('is_content', 'term'))) {
+		if ($membership->has('forum') && !empty(Registrar::withFeature('is_content', 'term'))) {
 			require(JVB_DIR . '/inc/managers/NewsRelationships.php');
 		}
 		if ($membership->has('invitable')) {
@@ -83,10 +83,10 @@
 		require(JVB_DIR . '/inc/managers/ReferralManager.php');
 	}
 
-	if (!empty(Registrar::getFeatured('karma'))) {
+	if (!empty(Registrar::withFeature('karma'))) {
 		require(JVB_DIR . '/inc/managers/KarmaManager.php');
 	}
-//	if (Site::has('favourites') && !empty(Registrar::getFeatured('favouritable'))) {
+//	if (Site::has('favourites') && !empty(Registrar::withFeature('favouritable'))) {
 	if (Site::has('favourites')) {
 		require(JVB_DIR . '/inc/managers/FavouritesManager.php');
 	}
diff --git a/inc/registrar/Fields.php b/inc/registrar/Fields.php
index 522b5d1..5635c0c 100644
--- a/inc/registrar/Fields.php
+++ b/inc/registrar/Fields.php
@@ -17,7 +17,7 @@
 
 class Fields {
 	protected array $fields;
-	protected Registrar $registrar;
+	private Registrar $registrar;
 
 	public function __construct(?string $type = null, ?Registrar $registrar = null) {
 		$this->registrar = $registrar;
diff --git a/inc/registrar/Registrar.php b/inc/registrar/Registrar.php
index 19b92fd..6b5cf2c 100644
--- a/inc/registrar/Registrar.php
+++ b/inc/registrar/Registrar.php
@@ -468,7 +468,8 @@
 	{
 		return $this->integrationConfigs;
 	}
-	public function hasIntegration(string $integration) {
+	public function hasIntegration(string $integration):bool
+	{
 		return array_key_exists($integration, $this->integrationConfigs);
 	}
     public function hasAnyIntegrations(array $integrations = []):bool
@@ -562,6 +563,24 @@
 		}
 		return $this;
 	}
+	public function unsetAll(array $flags):self
+	{
+		$flags = array_filter($flags, function($flag) {
+			return in_array($flag, static::$allFlags);
+		});
+		foreach ($flags as $flag) {
+			$this->$flag = false;
+			switch ($flag) {
+				case 'is_content':
+					remove_action('init', [$this, 'setupContent'], 20);
+					break;
+				case 'is_glossary':
+					$this->hide_single = false;
+					break;
+			}
+		}
+		return $this;
+	}
 	public function prefixWith(string $prefix):self
 	{
 		$this->prefix_with = sanitize_title($prefix);
@@ -654,7 +673,7 @@
 		protected function getBreadcrumbs():Breadcrumbs
 		{
 			if (!isset($this->breadcrumbs)) {
-				$this->breadcrumbs = new Breadcrumbs($this->slug, $this);
+				$this->breadcrumbs = new Breadcrumbs($this->slug);
 			}
 
 			return $this->breadcrumbs;
@@ -672,7 +691,7 @@
 		protected function getDashboard():Dashboard
 		{
 			if (!isset($this->dashboard)) {
-				$this->dashboard = new Dashboard($this->plural, $this);
+				$this->dashboard = new Dashboard($this->plural);
 			}
 
 			return $this->dashboard;
@@ -715,11 +734,42 @@
 	}
 	public function addSection(string $title):Section
 	{
-		$section = new Section($title, $this);
-		$this->sections[] = $section;
-		return $section;
+		$slug = sanitize_title($title);
+		if (!array_key_exists($slug, $this->sections)) {
+			$section = new Section($title, $this);
+			$this->sections[$slug] = $section;
+		}
+
+		return $this->sections[$slug];
 	}
 
+	public static function maybeBuildSections():void
+	{
+		foreach (self::$instances as $inst) {
+			$inst->buildSections();
+		}
+	}
+		protected function buildSections():void
+		{
+			$fields = $this->getFields();
+			$sections = array_unique(array_values(array_map(function ($f) {
+				return array_key_exists('section', $f) && !is_null($f['section']) ? $f['section'] : 'main';
+			}, $fields)));
+
+			foreach ($sections as $s) {
+				$section = new Section($s, $this);
+				$section->setTitle(ucwords(implode(' ', explode('-', $s))));
+				$sectionFields = array_map(function ($f) {
+					return $f['name'];
+				}, array_filter($fields, function ($f) use ($s) {
+					$tmp = array_key_exists('section', $f) && !is_null($f['section']) ? $f['section'] : 'main';
+					return $s === $tmp;
+				}));
+				$section->setFields($sectionFields);
+				$this->sections[$s] = $section;
+			}
+		}
+
 	public function setSectionOrder(array $sections):self
 	{
 		$allSections = array_map(function($section) {
@@ -767,7 +817,7 @@
 				$this->hideSingleHandler = new HideSingle($this->slug, $this);
 			}
 			if ($this->is_timeline) {
-				$this->isTimelineHandler = new MakeTimelineType($this->slug, $this);
+				$this->isTimelineHandler = new MakeTimelineType($this->slug);
 				$this->registrar->hierarchical = true;
 			}
 			if ($this->is_calendar) {
@@ -1104,8 +1154,8 @@
 	public static function ensureInstanced():void
 	{
 		if (empty(self::$instances)) {
-			do_action('jvbDefineRegistrar');
-			do_action('jvbDefineRegistrarFields');
+			do_action('jvb_define_registrar');
+			do_action('jvb_define_fields');
 		}
 	}
 
diff --git a/inc/registrar/config/Integration.php b/inc/registrar/config/Integration.php
index a25324d..8a829d5 100644
--- a/inc/registrar/config/Integration.php
+++ b/inc/registrar/config/Integration.php
@@ -38,6 +38,7 @@
 		$this->service_name = $service;
 	}
 
+
 	public function getService_name():string
 	{
 		return $this->service_name;
@@ -49,7 +50,12 @@
 	 */
 	public function setContentType(string $content):self
 	{
-		$allowed = JVB()->connect($this->service_name)->getAllowedContent();
+		$connection = JVB()->connect($this->service_name);
+		if (!$connection){
+			error_log('[Integration]::setContentType Service is not setup. '.$this->service_name);
+			return $this;
+		}
+		$allowed = $connection->getAllowedContent();
 		if (!in_array($content, $allowed)) {
 			error_log($this->service_name.' Connection does not support this content: '.$content);
 			return $this;
diff --git a/inc/registrar/config/Section.php b/inc/registrar/config/Section.php
index d5d6c51..10ac615 100644
--- a/inc/registrar/config/Section.php
+++ b/inc/registrar/config/Section.php
@@ -13,11 +13,10 @@
 	protected string $description = '';
 	protected string $icon = '';
 	protected array $fields = [];
-	protected Registrar $registrar;
+	private Registrar $registrar;
 
-	public function __construct(string $title, Registrar $registrar) {
-		$this->title = $title;
-		$this->slug = sanitize_title($title);
+	public function __construct(string $slug, Registrar $registrar) {
+		$this->slug = sanitize_title($slug);
 		$this->registrar = $registrar;
 	}
 
@@ -27,7 +26,7 @@
 	}
 	public function getTitle():string
 	{
-		return $this->title;
+		return $this->title ?? ucwords(implode(' ', explode('-', $this->slug)));
 	}
 
 	public function setDescription(string $description):self
@@ -45,6 +44,10 @@
 		$this->icon = $icon;
 		return $this;
 	}
+	public function getIcon():string
+	{
+		return $this->icon;
+	}
 
 	protected function checkFields(string|array $fields):string|array
 	{
diff --git a/inc/registrar/fields/Field.php b/inc/registrar/fields/Field.php
index c1d5e33..f24de84 100644
--- a/inc/registrar/fields/Field.php
+++ b/inc/registrar/fields/Field.php
@@ -21,6 +21,10 @@
 	protected int $maxLength;			// of characters
 	protected int $min;
 	protected int $max;
+	/**
+	 * @var float $step For number fields. Indicates the amount the number increases/decreases with the plus/minus buttons
+	 */
+	protected float $step;
 	protected string $subtype;
 	protected array $condition;
 	protected array $allowedSubtype = ['text', 'url','number','tel','email','number'];
@@ -64,6 +68,11 @@
 		}
 	}
 
+	public function getName():string
+	{
+		return $this->name;
+	}
+
 	public function setDescription(string $description):void
 	{
 		$this->description = $description;
@@ -144,6 +153,14 @@
 	{
 		return $this->max??null;
 	}
+	public function setStep(float $step):void
+	{
+		$this->step = $step;
+	}
+	public function getStep():?float
+	{
+		return $this->step??null;
+	}
 	public function setMaxLength(int $maxLength):void
 	{
 		$this->maxLength = $maxLength;
diff --git a/inc/registrar/helpers/AddIntegrationFields.php b/inc/registrar/helpers/AddIntegrationFields.php
index 29fe741..1f3fd11 100644
--- a/inc/registrar/helpers/AddIntegrationFields.php
+++ b/inc/registrar/helpers/AddIntegrationFields.php
@@ -11,13 +11,13 @@
 
 class AddIntegrationFields {
 	protected string $service_name;
-	protected Registrar $registrar;
+	private Registrar $registrar;
 	protected Integration $config;
 	protected array $allowed;
 
 	public function __construct(string $service_name, ?Registrar $registrar = null) {
 		$this->initAllowed();
-		if (!in_array($service_name, $this->allowed)) {
+		if (!array_key_exists($service_name, $this->allowed)) {
 			return;
 		}
 
@@ -28,6 +28,7 @@
 
 		$this->config = $registrar->getIntegration($service_name);
 
+		add_action('jvb_define_integrations', [$this, 'addIntegrationFields'],20);
 	}
 	protected function initAllowed():void
 	{
@@ -56,6 +57,7 @@
 	public function addIntegrationFields():void
 	{
 		$fields = $this->getIntegrationFields();
+//		error_log('[AddIntegrationFields] adding fields for '.$this->service_name.': '.print_r($fields, true));
 		foreach ($fields as $fieldName => $fieldConfig) {
 			$this->registrar->fields()->addField($fieldName, $fieldConfig);
 		}
diff --git a/inc/registrar/helpers/HideSingle.php b/inc/registrar/helpers/HideSingle.php
index 20ef320..9c00ca8 100644
--- a/inc/registrar/helpers/HideSingle.php
+++ b/inc/registrar/helpers/HideSingle.php
@@ -12,15 +12,14 @@
 class HideSingle {
 	protected string $slug;
 	protected string $postType;
-	protected Registrar $registrar;
 	public function __construct(string $slug, Registrar $registrar) {
 		$this->slug = $slug;
 		$this->postType = jvbCheckBase($slug);
-		$this->registrar = $registrar;
 
-		if ($this->registrar->hasFeature('hide_single')) {
+
+		if ($registrar->hasFeature('hide_single')) {
 			add_filter('is_post_type_viewable', [$this, 'hideFromPublic']);
-			if ($this->registrar->hasFeature('redirect_to_author')) {
+			if ($registrar->hasFeature('redirect_to_author')) {
 				add_filter('post_type_link', [$this, 'redirectSingleToAuthor'], 15, 2);
 				add_action('template_redirect', [$this, 'actuallyRedirectToAuthor']);
 			} else {
diff --git a/inc/registrar/helpers/MakeCalendarType.php b/inc/registrar/helpers/MakeCalendarType.php
index 9ad4d76..be83235 100644
--- a/inc/registrar/helpers/MakeCalendarType.php
+++ b/inc/registrar/helpers/MakeCalendarType.php
@@ -12,7 +12,7 @@
 class MakeCalendarType {
 	protected string $slug;
 	protected string $postType;
-	protected Registrar $registrar;
+	private Registrar $registrar;
 	public function __construct(string $slug, Registrar $registrar) {
 		$this->slug = $slug;
 		$this->postType = jvbCheckBase($slug);
@@ -25,6 +25,13 @@
 		add_action('init', [$this, 'addCalendarRewrites']);
 	}
 
+
+	public function __debugInfo() {
+		$vars = get_object_vars($this);
+		unset($vars['registrar']);
+		return $vars;
+	}
+
 	protected function addCalendarFields():void
 	{
 
diff --git a/inc/registrar/helpers/MakeTimelineType.php b/inc/registrar/helpers/MakeTimelineType.php
index 84ea959..f8e2e49 100644
--- a/inc/registrar/helpers/MakeTimelineType.php
+++ b/inc/registrar/helpers/MakeTimelineType.php
@@ -12,11 +12,9 @@
 class MakeTimelineType {
 	protected string $slug;
 	protected string $postType;
-	protected Registrar $registrar;
-	public function __construct(string $slug, Registrar $registrar) {
+	public function __construct(string $slug) {
 		$this->slug = $slug;
 		$this->postType = jvbCheckBase($slug);
-		$this->registrar = $registrar;
 
 		add_action('template_redirect', [$this, 'redirectChildToParent']);
 	}
diff --git a/inc/rest/Rest.php b/inc/rest/Rest.php
index dd6c9cb..557929d 100644
--- a/inc/rest/Rest.php
+++ b/inc/rest/Rest.php
@@ -224,7 +224,7 @@
 
 		// Keep existing author filtering logic
 		$authorQuery = [];
-		foreach (Registrar::getFeatured('can_create', 'user') as $type) {
+		foreach (Registrar::withFeature('can_create', 'user') as $type) {
 			if (array_key_exists($type, $data)) {
 				$artist_ids = array_map(
 					'absint',
@@ -537,7 +537,7 @@
 			return false;
 		}
 		$post_types = is_array($args['post_type']) ? $args['post_type'] : [$args['post_type']];
-		$hasTimeline = array_map(function($item) { return jvbCheckBase($item); },Registrar::getFeatured('is_timeline', 'post'));
+		$hasTimeline = array_map(function($item) { return jvbCheckBase($item); },Registrar::withFeature('is_timeline', 'post'));
 		return !empty(array_intersect($post_types, $hasTimeline));
 	}
 	// =========================================================================
diff --git a/inc/rest/RestRouteManager.php b/inc/rest/RestRouteManager.php
index ff72f13..91778c7 100644
--- a/inc/rest/RestRouteManager.php
+++ b/inc/rest/RestRouteManager.php
@@ -323,7 +323,7 @@
 
 		// Keep existing author filtering logic
 		$authorQuery = [];
-		foreach (Registrar::getFeatured('can_create', 'user') as $type) {
+		foreach (Registrar::withFeature('can_create', 'user') as $type) {
 			if (array_key_exists($type, $data)) {
 				$artist_ids = array_map(
 					'absint',
@@ -479,7 +479,7 @@
 	protected function isTimeline($args, $data):bool
 	{
 		$post_types = is_array($args['post_type']) ? $args['post_type'] : [$args['post_type']];
-		$areTimeline = array_map(function($type) { return BASE.$type; },Registrar::getFeatured('is_timeline', 'post'));
+		$areTimeline = array_map(function($type) { return BASE.$type; },Registrar::withFeature('is_timeline', 'post'));
 		return !empty(array_intersect($post_types, $areTimeline));
 	}
 
diff --git a/inc/rest/_setup.php b/inc/rest/_setup.php
index 89dcf34..f1e28bb 100644
--- a/inc/rest/_setup.php
+++ b/inc/rest/_setup.php
@@ -51,11 +51,11 @@
 //if (Site::has('referrals')) {
 	require(JVB_DIR . '/inc/rest/routes/ReferralRoutes.php');
 //}
-//if (!empty(Registrar::getFeatured('has_responses'))) {
+//if (!empty(Registrar::withFeature('has_responses'))) {
 	require(JVB_DIR . '/inc/rest/routes/ResponseRoutes.php');
 //}
 
-//if (!empty(Registrar::getFeatured('karma'))) {
+//if (!empty(Registrar::withFeature('karma'))) {
 	require(JVB_DIR . '/inc/rest/routes/VoteRoutes.php');
 //}
 
diff --git a/inc/rest/routes/ApprovalRoutes.php b/inc/rest/routes/ApprovalRoutes.php
index a051459..b35e485 100644
--- a/inc/rest/routes/ApprovalRoutes.php
+++ b/inc/rest/routes/ApprovalRoutes.php
@@ -41,11 +41,11 @@
         $this->termTypes = [];
 		$this->allTypes = [];
         if ($this->hasMemberApproval) {
-            $this->userTypes = Registrar::getFeatured('approve_new', 'user');
+            $this->userTypes = Registrar::withFeature('approve_new', 'user');
             $this->allTypes = $this->userTypes;
         }
         if (Site::has('term_approval')) {
-            $this->termTypes = Registrar::getFeatured('approve_new', 'term');
+            $this->termTypes = Registrar::withFeature('approve_new', 'term');
             $this->allTypes[] = 'term';
         }
     }
diff --git a/inc/rest/routes/ContentTermsRoutes.php b/inc/rest/routes/ContentTermsRoutes.php
index ce50632..37c9d03 100644
--- a/inc/rest/routes/ContentTermsRoutes.php
+++ b/inc/rest/routes/ContentTermsRoutes.php
@@ -55,7 +55,7 @@
 	{
 		$registry = JVB()->queue()->registry();
 		$executor = new ContentTermExecutor();
-		$taxonomies = Registrar::getFeatured('is_content', 'term');
+		$taxonomies = Registrar::withFeature('is_content', 'term');
 
 		foreach($taxonomies as $taxonomy) {
 			$registry->register("{$taxonomy}_update", new TypeConfig(
diff --git a/inc/rest/routes/FeedRoutes.php b/inc/rest/routes/FeedRoutes.php
index 6abb894..f4e0ab1 100644
--- a/inc/rest/routes/FeedRoutes.php
+++ b/inc/rest/routes/FeedRoutes.php
@@ -501,7 +501,7 @@
 					: explode(',', $args['post_type']);
 
 				// Check if filtering global feed content
-				if (in_array(jvbNoBase($context['type']), Registrar::getFeatured('is_content', 'term'))) {
+				if (in_array(jvbNoBase($context['type']), Registrar::withFeature('is_content', 'term'))) {
 					// Global: show posts from any content type with this taxonomy
 					$for_content = Registrar::getInstance($context['type'])->registrar->for ?? [];
 
@@ -509,7 +509,7 @@
 					$post_types = array_map(fn($type) => jvbCheckBase($type), $for_content);
 
 					// Filter to only show_feed content types
-					$show_feed_types = Registrar::getFeatured('show_feed', 'post');
+					$show_feed_types = Registrar::withFeature('show_feed', 'post');
 					$args['post_type'] = array_intersect(
 						$post_types,
 						array_map(fn($type) => jvbCheckBase($type), $show_feed_types)
@@ -1147,7 +1147,7 @@
 				$config = [];
 
 				// Get content types with show_feed
-				$contentTypes = Registrar::getFeatured('show_feed', 'post');
+				$contentTypes = Registrar::withFeature('show_feed', 'post');
 				foreach ($contentTypes as $slug) {
 					$this->cache->tag('content:'.$slug);
 					$registrar = Registrar::getInstance($slug);
@@ -1163,7 +1163,7 @@
 				}
 
 				// Get taxonomies with show_feed (content taxonomies)
-				$taxonomies = Registrar::getFeatured('show_feed', 'term');
+				$taxonomies = Registrar::withFeature('show_feed', 'term');
 				foreach ($taxonomies as $slug) {
 					$registrar = Registrar::getInstance($slug);
 					if (!$registrar || !($registrar->hasFeature('is_content') ?? false)) {
diff --git a/inc/rest/routes/LoginRoutes.php b/inc/rest/routes/LoginRoutes.php
index 2e863ee..b4563aa 100644
--- a/inc/rest/routes/LoginRoutes.php
+++ b/inc/rest/routes/LoginRoutes.php
@@ -136,18 +136,23 @@
 	 */
 	public function handleLogin(WP_REST_Request $request): WP_REST_Response
 	{
+		error_log('Handling login...');
 		$email = sanitize_email($request->get_param('user_email'));
 		$password = $request->get_param('user_password');
 		$remember = (bool) $request->get_param('remember_me');
 		$redirect_to = $request->get_param('redirect_to');
 
 		// Verify Turnstile
+
 		if (!$this->verifyTurnstile($request->get_param('cf-turnstile-response') ?? '')) {
+			error_log('[handleLogin]Turnstile failed');
 			return $this->error(
 				'Security verification failed. Please try again.',
 				'turnstile_failed',
 				403
 			);
+		} else {
+			error_log('[handleLogin]Turnstile succeeded');
 		}
 
 		// Attempt authentication
@@ -720,22 +725,20 @@
 	protected function buildAuth(?int $user = null): array
 	{
 		$userId = $user ?? (is_user_logged_in() ? get_current_user_id() : 0);
-		$cacheKey = $userId ?: 'guest';
 
-		return Cache::for('auth', 300)->remember($cacheKey, function() use ($userId) {
-			if ($userId) {
-				return [
-					'authenticated' => true,
-					'user'          => $userId,
-					'nonces'        => $this->getUserNonces($userId),
-				];
-			}
+		if ($userId) {
 			return [
-				'authenticated' => false,
-				'user'          => false,
-				'nonces'        => ['wp_rest' => wp_create_nonce('wp_rest')],
+				'authenticated' => true,
+				'user'          => $userId,
+				'nonces'        => $this->getUserNonces($userId),
 			];
-		});
+		}
+
+		return [
+			'authenticated' => false,
+			'user'          => false,
+			'nonces'        => ['wp_rest' => wp_create_nonce('wp_rest')],
+		];
 	}
 	protected function getUserNonces(int $userID):array {
 		$nonces = [
@@ -747,7 +750,7 @@
 		if (Site::has('favourites')) {
 			$nonces['favourites'] = wp_create_nonce('favourites-'.$userID);
 		}
-		if (!empty(Registrar::getFeatured('karma'))) {
+		if (!empty(Registrar::withFeature('karma'))) {
 			$nonces['votes'] = wp_create_nonce('votes-'.$userID);
 		}
 		if (Site::has('notifications')) {
diff --git a/inc/rest/routes/NotificationsRoutes.php b/inc/rest/routes/NotificationsRoutes.php
index ff84cdc..eaf3e7f 100644
--- a/inc/rest/routes/NotificationsRoutes.php
+++ b/inc/rest/routes/NotificationsRoutes.php
@@ -555,7 +555,7 @@
 				$statusCondition = $wpdb->prepare("a.status = %s", $status);
 			}
 
-			$approvals = Registrar::getFeatured('approve_new');
+			$approvals = Registrar::withFeature('approve_new');
 			foreach ($approvals as $type => $config) {
 				$table = $wpdb->prefix . BASE . 'approval_' . $type . 'requests';
 				$votes = $wpdb->prefix . BASE . 'approval_' . $type . 'votes';
diff --git a/jvb.php b/jvb.php
index 3987ea3..16816ed 100644
--- a/jvb.php
+++ b/jvb.php
@@ -4,7 +4,7 @@
 Plugin URI: https://jakevan.ca
 Description: The Base Plugin for JakeVan clients
 Author: Jake Vanderwerf
-Version: 1.0.0
+Version: 1.1.0
 Author URI: https://jakevan.ca/
 Textdomain: jvb
 */
@@ -88,6 +88,7 @@
 }, 10, 3);
 
 
+
 function jvbIgnoredPostTypes():array
 {
 	return [BASE.'directory', BASE.'dash', 'attachment', 'revision', 'nav_menu_item'];
@@ -248,11 +249,54 @@
 require(JVB_DIR . '/inc/admin/_setup.php');
 
 require(JVB_DIR . '/JVBase.php');
+
+/**
+ * After moving to the Registrar::based registration, we need to carefully time
+ * 	when Site gets defined, as well as Registrar initial definitions, field definitions,
+ * 	and integration config
+ * These custom actions should simplify the timing for us.
+ */
+add_action('plugins_loaded', 'jvb_site_definitions',1);
+add_action('plugins_loaded', 'jvb_registrar_definitions',2);
+add_action('plugins_loaded', 'jvb_field_definitions', 3);
 add_action('init', 'jvbLoadBase', 1);
+add_action('init', 'jvb_integration_definitions',3);
+add_action('init', 'jvb_field_section_definitions', 5);
+/**
+ * Can define the Site settings
+ * @return void
+ */
+function jvb_site_definitions():void
+{
+	do_action('jvb_define_site');
+}
+function jvb_registrar_definitions():void
+{
+	do_action('jvb_define_registrar');
+}
+function jvb_field_definitions():void
+{
+	do_action('jvb_define_fields');
+}
+
+
 function jvbLoadBase():void
 {
 	JVB::getInstance();
 }
+
+function jvb_integration_definitions():void
+{
+	do_action('jvb_define_integrations');
+}
+
+function jvb_field_section_definitions():void
+{
+	do_action('jvb_define_field_sections');
+	Registrar::maybeBuildSections();
+}
+
+
 function JVB(): JVB
 {
 	return JVB::getInstance();
@@ -317,7 +361,7 @@
 	if (Site::has('favourites')) {
 		$interactions[] = 'favourites';
 	}
-	if (!empty(Registrar::getFeatured('karma'))) {
+	if (!empty(Registrar::withFeature('karma'))) {
 		$interactions[] = 'karma';
 	}
 	if (Site::has('notifications')) {
@@ -372,7 +416,7 @@
 		}';
 	}
 
-	if (!empty(Registrar::getFeatured('karma'))) {
+	if (!empty(Registrar::withFeature('karma'))) {
 		wp_enqueue_script('jvb-votes');
 		$initUserSettings .= '// Fetch user votes
         try {

--
Gitblit v1.10.0