From ccf5e61a075c35d24befc175994b5cb8957ca322 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Wed, 26 Aug 2026 21:45:53 +0000
Subject: [PATCH] =Extra JVB() calls replaced, minor tweaks

---
 inc/integrations/services/UmamiOld.php                     |    4 
 inc/managers/CustomTable.php                               |    2 
 inc/blocks/SummaryBlock.php                                |   19 
 inc/managers/SEO/render/SchemaOutput.php                   |    4 
 inc/managers/Dashboard/DashboardPage.php                   |    6 
 jvb.php                                                    |   39 -
 inc/rest/routes/TermRoutes.php                             |    9 
 inc/integrations/_Base.php                                 |    3 
 inc/managers/OperationQueue.php                            |   12 
 inc/managers/DashboardManager.php                          |   13 
 inc/rest/routes/ContentRoutes.php                          |   16 
 inc/blocks/CustomBlocks.php                                |   16 
 inc/rest/routes/FeedRoutes.php                             |    4 
 inc/registrar/config/seo/Schema.php                        |   12 
 inc/rest/routes/ResponseRoutes.php                         |    2 
 inc/blocks/DrawerMenuBlock.php                             |    4 
 inc/blocks/TimelineBlock.php                               |    5 
 inc/managers/queue/executors/ContentExecutor.php           |    3 
 inc/managers/TaxonomyRelationships.php                     |    4 
 inc/rest/routes/ShopRoutes.php                             |   11 
 src/forms/render.php                                       |   54 -
 inc/managers/Referrals.php                                 |    7 
 inc/managers/IconsManager.php                              |   74 +
 inc/rest/routes/NewsRoutes.php                             |    8 
 inc/managers/queue/executors/IntegrationExecutor.php       |   14 
 inc/integrations/ServiceMap.php                            |    9 
 inc/managers/Responses.php                                 |   13 
 inc/managers/DirectoryManager.php                          |    7 
 inc/blocks/FeedBlock.php                                   |    6 
 inc/registrar/Registrar.php                                |    7 
 inc/managers/UserTermsManager.php                          |    2 
 inc/forms/PostSelector.php                                 |    6 
 inc/helpers/renderFields.php                               |    4 
 inc/meta/Storage.php                                       |   27 
 inc/integrations/services/GoogleMyBusiness.php             |  361 +++++++++++++
 inc/registrar/Posts.php                                    |    2 
 inc/rest/routes/ContentTermsRoutes.php                     |    9 
 templates/dashboard/sections/favourites.php                |   12 
 inc/integrations/services/InstagramOld.php                 |    7 
 inc/rest/routes/UploadRoutes.php                           |    2 
 inc/managers/queue/Queue.php                               |    3 
 inc/blocks/MenuBlock.php                                   |  100 ++-
 inc/rest/routes/QueueRoutes.php                            |    4 
 inc/managers/Login.php                                     |    2 
 checks.php                                                 |    2 
 inc/blocks/FeedBlockOld.php                                |    6 
 inc/utility/Image.php                                      |   14 
 inc/managers/Dashboard/Dashboard.php                       |    4 
 inc/rest/routes/Invitations.php                            |    8 
 inc/managers/MagicLinks.php                                |   13 
 inc/integrations/services/GoogleMyBusinessOld.php          |    4 
 /dev/null                                                  |  359 -------------
 inc/rest/Rest.php                                          |    8 
 inc/utility/Video.php                                      |   10 
 inc/rest/RestRouteManager.php                              |   10 
 inc/rest/routes/LoginRoutes.php                            |  139 +----
 inc/integrations/services/GoogleMapsOld.php                |   10 
 inc/blocks/FormBlock.php                                   |    4 
 inc/managers/InvitationsManager.php                        |    2 
 inc/managers/Favourites.php                                |    4 
 inc/managers/SEO/render/Traits/_Properties/reviewTrait.php |    4 
 61 files changed, 700 insertions(+), 829 deletions(-)

diff --git a/checks.php b/checks.php
index 242bf4c..4339047 100644
--- a/checks.php
+++ b/checks.php
@@ -37,7 +37,7 @@
 
 function jvbTermHasPosts(int $termID, string $taxonomy):bool
 {
-	$cache = Cache::for('termUtility', 30*60)->connect('taxonomy');
+	$cache = Cache::for('termUtility', 'term', 30*60);
 	return $cache->remember(
 		$termID,
 		function() use($taxonomy, $termID) {
diff --git a/inc/blocks/CustomBlocks.php b/inc/blocks/CustomBlocks.php
index 2612fbd..20085fe 100644
--- a/inc/blocks/CustomBlocks.php
+++ b/inc/blocks/CustomBlocks.php
@@ -1405,9 +1405,6 @@
 
 		if (!static::$currentLoop) {
 
-			if (JVB_TESTING) {
-				jvbDump('No loop stored');
-			}
 			return $content;
 		}
 		if (static::$currentLoop->have_posts()) {
@@ -1943,9 +1940,7 @@
 			);
 
 		}
-		if (JVB_TESTING) {
-			jvbDump('Could not create template part block for '.$block['blockName']);
-		}
+
 		return $content;
 
 //		$isHeaderTemplate = (
@@ -2792,6 +2787,9 @@
 					);
 				}
 				return $classes;
+			case 'anchor':
+				//TODO: What's this doing?
+				return '';
             default:
 				if (JVB_TESTING && !is_admin() &&!in_array($key, $this->ignore)) {
 //					TESTING
@@ -3154,7 +3152,9 @@
 					break;
 				}
 				return $this->getColorStyle($value, $type);
-
+			case 'anchor':
+				//TODO: What should we do here?
+				break;
             // Any other attributes that need direct styling
             default:
 				if (JVB_TESTING && !is_admin() && !in_array($key, $this->ignore)) {
@@ -3184,7 +3184,7 @@
 						break;
 					default:
 						if (JVB_TESTING) {
-							jvbDump($value, 'No preset found for size: '.print_r($value, true));
+							error_log('No preset found for size: '.print_r($value, true));
 						}
 				}
 			}
diff --git a/inc/blocks/DrawerMenuBlock.php b/inc/blocks/DrawerMenuBlock.php
index 0ec9f1d..0a30975 100644
--- a/inc/blocks/DrawerMenuBlock.php
+++ b/inc/blocks/DrawerMenuBlock.php
@@ -49,9 +49,7 @@
 		}
 
 		$cache = Cache::for('drawer');
-		if (JVB_TESTING) {
-			$cache->flush();
-		}
+
 
 		if (!is_front_page()) {
 			$menu_items[] = [
diff --git a/inc/blocks/FeedBlock.php b/inc/blocks/FeedBlock.php
index 3cc10ba..2cf593c 100644
--- a/inc/blocks/FeedBlock.php
+++ b/inc/blocks/FeedBlock.php
@@ -32,12 +32,6 @@
 
 	public function __construct()
 	{
-//		// Initialize cache with connections
-//		$this->cache = Cache::for('feed_block','post', WEEK_IN_SECONDS);
-//		if (JVB_TESTING) {
-//			$this->cache->flush();
-//		}
-
 		add_action('init', [$this, 'registerBlock']);
 	}
 
diff --git a/inc/blocks/FeedBlockOld.php b/inc/blocks/FeedBlockOld.php
index d56cc1c..fcc482d 100644
--- a/inc/blocks/FeedBlockOld.php
+++ b/inc/blocks/FeedBlockOld.php
@@ -22,9 +22,7 @@
 	{
 		// Initialize cache with connections
 		$this->cache = Cache::for('feed_block', WEEK_IN_SECONDS);
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+
 
 		add_action('init', [$this, 'registerBlock']);
 	}
@@ -117,7 +115,7 @@
 
 		$this->config = $this->buildParams($attributes);
 		return $this->cache->remember(
-			$this->cache->generateKey($this->config),
+			$this->config,
 			function() {
 				return $this->renderBlock();
 			}
diff --git a/inc/blocks/FormBlock.php b/inc/blocks/FormBlock.php
index 5cd1b22..1bb5115 100644
--- a/inc/blocks/FormBlock.php
+++ b/inc/blocks/FormBlock.php
@@ -36,9 +36,7 @@
 	{
 		$this->cache = Cache::for('forms', null, WEEK_IN_SECONDS);
 
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+
 		// Initialize forms from filter
 		$this->forms = $this->registerForms();
 		$this->form_contact = apply_filters('jvb_form_contact', '');
diff --git a/inc/blocks/MenuBlock.php b/inc/blocks/MenuBlock.php
index 24d3759..a623d7c 100644
--- a/inc/blocks/MenuBlock.php
+++ b/inc/blocks/MenuBlock.php
@@ -215,54 +215,78 @@
 						<div>
 							<h4>%s — %s</h4>
 							%s
-						</div>', //Note: we had 3 %s%s%s before the last </div> last time. This was to add optional ingredients or preparation time duration, not default in WooCommerce
+						</div><a href="?add-to-cart=%d&variation_id=%d"
+   data-quantity="1"
+   data-product_id="%d"
+   data-variation_id="%d"
+   class="add_to_cart_button ajax_add_to_cart add-to-cart">
+   %s
+   <span>Add to Cart</span>
+</a>', //Note: we had 3 %s%s%s before the last </div> last time. This was to add optional ingredients or preparation time duration, not default in WooCommerce
 						$row['title'],
 						jvbCurrency($row['price']),
 						empty($row['description']) ? '' : wpautop($row['description']),
+						$ID,
+						$row['id'],
+						$ID,
+						$row['id'],
+						jvbIcon('plus-square')
 				);
 
-				$out .= Form::render(
-					$row['id'],
-					'',
-					[
-						'type'	=> 'quantity',
-						'label'	=> $row['title'],
-						'min'	=> 0,
-						'max'	=> 30,
-						'data'	=> [
-							'price'	=> $row['price'],
-							'id'	=> $row['id'],
-							'sku'	=> $row['sku'],
-							'name'	=> $row['title'],
-							'add-to-cart'	=> ''
-						],
-						'add'	=> 'Add 1 '.$row['title'].' to cart',
-						'remove'	=> 'Remove 1 '.$row['title']. ' from cart',
-					]
-				);
+//				$out .= Form::render(
+//					$row['id'],
+//					'',
+//					[
+//						'type'	=> 'quantity',
+//						'label'	=> $row['title'],
+//						'min'	=> 0,
+//						'max'	=> 30,
+//						'data'	=> [
+//							'price'	=> $row['price'],
+//							'id'	=> $row['id'],
+//							'sku'	=> $row['sku'],
+//							'name'	=> $row['title'],
+//							'add-to-cart'	=> ''
+//						],
+//						'add'	=> 'Add 1 '.$row['title'].' to cart',
+//						'remove'	=> 'Remove 1 '.$row['title']. ' from cart',
+//					]
+//				);
 				$out .= '</div>';
 			}
 		} else {
-			$out .= Form::render(
+			$out .= sprintf(
+				'<a href="?add-to-cart=%d"
+				   data-quantity="1"
+				   data-product_id="%d"
+				   class="add_to_cart_button ajax_add_to_cart add-to-cart">
+				   %s
+   					<span>Add to Cart</span>
+				</a>',
 				$ID,
-				'',
-				[
-					'type'	=> 'quantity',
-					'label'	=> 'Add to Order',
-					'min'	=> 0,
-					'max'	=> 30,
-					'step'	=> 1,
-					'data'	=> [
-						'price'	=> $fields['_price'],
-						'id'	=> $ID,
-						'name'	=> $fields['post_title'],
-						'step'	=> 1,
-						'add-to-cart'	=> '',
-					],
-					'add'	=> 'Add 1 '.$fields['post_title'].' to cart',
-					'remove'	=> 'Remove 1 '.$fields['title']. ' from cart',
-				]
+				$ID,
+				jvbIcon('plus-square')
 			);
+//			$out .= Form::render(
+//				$ID,
+//				'',
+//				[
+//					'type'	=> 'quantity',
+//					'label'	=> 'Add to Order',
+//					'min'	=> 0,
+//					'max'	=> 30,
+//					'step'	=> 1,
+//					'data'	=> [
+//						'price'	=> $fields['_price'],
+//						'id'	=> $ID,
+//						'name'	=> $fields['post_title'],
+//						'step'	=> 1,
+//						'add-to-cart'	=> '',
+//					],
+//					'add'	=> 'Add 1 '.$fields['post_title'].' to cart',
+//					'remove'	=> 'Remove 1 '.$fields['title']. ' from cart',
+//				]
+//			);
 		}
 
 		$out .= '</div></div>';
diff --git a/inc/blocks/SummaryBlock.php b/inc/blocks/SummaryBlock.php
index 186ebbd..9ea9fd8 100644
--- a/inc/blocks/SummaryBlock.php
+++ b/inc/blocks/SummaryBlock.php
@@ -28,9 +28,7 @@
         $this->cache = Cache::for('summary_block', 'post', WEEK_IN_SECONDS);
         add_action('init', [ $this, 'registerBlock' ]);
 		add_action('wp_enqueue_scripts', [$this, 'enqueueScripts']);
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+
     }
 
     public function registerBlock()
@@ -50,21 +48,10 @@
         return (is_tax()) ? 'tax' : 'content';
     }
 
-    protected function generateKey():string
-    {
-        $obj = get_queried_object();
-        return match (true) {
-            is_tax() => jvbNoBase($obj->taxonomy) . $obj->term_id,
-            is_a($obj, 'WP_Post_type') => jvbNoBase($obj->name),
-            is_a($obj, 'WP_User') => jvbUserRole($obj->ID),
-            default => jvbNoBase($obj->post_type) . $obj->ID,
-        };
-    }
-
     public function render(array $attributes, string $content, WP_Block $block)
     {
         $this->config = $this->getConfig();
-        $key = $this->generateKey();
+
 		if (is_tax()) {
 			$this->cache = Cache::for('summary_tax', 'term', WEEK_IN_SECONDS);
 		} elseif (is_author()) {
@@ -138,7 +125,7 @@
         ob_start();
         $this->renderBlock();
         $content = ob_get_clean();
-        $this->cache->set($key, $content);
+        $this->cache->set(get_queried_object_id(), $content);
         return $content;
     }
 
diff --git a/inc/blocks/TimelineBlock.php b/inc/blocks/TimelineBlock.php
index 3bf86e2..39d074c 100644
--- a/inc/blocks/TimelineBlock.php
+++ b/inc/blocks/TimelineBlock.php
@@ -4,6 +4,7 @@
 use JVBase\managers\Cache;
 use JVBase\meta\Meta;
 use JVBase\registrar\Registrar;
+use JVBase\rest\routes\ContentRoutes;
 use WP_Block;
 
 if (!defined('ABSPATH')) {
@@ -86,7 +87,7 @@
     protected function renderHeader():void
     {
 		$meta = Meta::forPost($this->parentID);
-		$sharedFields = JVB()->routes('content')->getTimelineSharedFields($this->content);
+		$sharedFields = ContentRoutes::getInstance()->getTimelineSharedFields($this->content);
 		$fields = $meta->getAll($sharedFields);
 		$extra = $meta->getAll();
         ?>
@@ -170,7 +171,7 @@
 	{
 		$all = $this->children;
 		array_unshift($all, $this->parentID);
-		$uniqueFields = JVB()->routes('content')->getTimelineUniqueFields($this->content);
+		$uniqueFields = ContentRoutes::getInstance()->getTimelineUniqueFields($this->content);
 
 		foreach ($all as $i => $ID) {
 			$meta = Meta::forPost($ID);
diff --git a/inc/forms/PostSelector.php b/inc/forms/PostSelector.php
index f6f564f..c68191d 100644
--- a/inc/forms/PostSelector.php
+++ b/inc/forms/PostSelector.php
@@ -185,8 +185,8 @@
 		}
 
 		// Check cache
-		$cache_key = $this->cache->generateKey($args);
-		$cached_result = $this->cache->get($cache_key);
+
+		$cached_result = $this->cache->get($args);
 		if ($cached_result) {
 			return new WP_REST_Response($cached_result);
 		}
@@ -224,7 +224,7 @@
 		];
 
 		// Cache the result
-		$this->cache->set($cache_key, $result, 300); // 5 minute cache
+		$this->cache->set($args, $result, 300); // 5 minute cache
 
 		return new WP_REST_Response($result);
 	}
diff --git a/inc/helpers/renderFields.php b/inc/helpers/renderFields.php
index ec892dd..718b66d 100644
--- a/inc/helpers/renderFields.php
+++ b/inc/helpers/renderFields.php
@@ -603,8 +603,8 @@
 	}
 
 	$cache = Cache::for('tax_locations', 'term');
-	$key = $cache->generateKey($location);
 
+	$cached = $cache->get($location);
 	$cached = false;
 	if ($cached) {
 		return $cached;
@@ -636,7 +636,7 @@
 	);
 
 	$cached = '<p class="find-us">'.jvbIcon('map-pin').'Find us here: '.$google.$apple.'</p>';
-	$cache->set($key, $cached);
+	$cache->set($location, $cached);
 
 	return $cached;
 }
diff --git a/inc/integrations/ServiceMap.php b/inc/integrations/ServiceMap.php
index 9386ea3..7cc2069 100644
--- a/inc/integrations/ServiceMap.php
+++ b/inc/integrations/ServiceMap.php
@@ -26,6 +26,15 @@
 			: false;
 	}
 
+	public function getServiceUser(string $service, ?int $userID = null):Integrations|false
+	{
+		$service = $this->getService($service);
+		if ($service->userID !== $userID && method_exists($service, 'switchUser')) {
+			$service->switchUser($userID);
+		}
+		return $service;
+	}
+
 	public function getAvailableServices():array
 	{
 		return array_filter(array_keys($this->serviceMap), function ($service) {
diff --git a/inc/integrations/_Base.php b/inc/integrations/_Base.php
index 03996ca..cc61055 100644
--- a/inc/integrations/_Base.php
+++ b/inc/integrations/_Base.php
@@ -2,6 +2,7 @@
 namespace JVBase\integrations;
 
 use JVBase\managers\Cache;
+use JVBase\managers\Errors;
 use JVBase\managers\IconsManager;
 
 if (!defined('ABSPATH')) {
@@ -108,7 +109,7 @@
 	protected function logError(string $method, string $message, array $context = []):void
 	{
 		$context['service'] = $this->service_name;
-		JVB()->error()->log('['.self::class.']'.$method, $message, $context);
+		Errors::getInstance()->log('['.self::class.']'.$method, $message, $context);
 	}
 
 	protected function getReturnURL():string
diff --git a/inc/integrations/services/GoogleMapsOld.php b/inc/integrations/services/GoogleMapsOld.php
index aebaf87..0f87b97 100644
--- a/inc/integrations/services/GoogleMapsOld.php
+++ b/inc/integrations/services/GoogleMapsOld.php
@@ -202,7 +202,7 @@
 			'key' => $this->private_key
 		];
 
-		$key = $this->cache->generateKey(['geocode', $address]);
+		$key =['geocode', $address];
 		$cached = $this->cache->get($key);
 		if ($cached) {
 			return $cached;
@@ -256,7 +256,7 @@
 			'key' => $this->private_key
 		];
 
-		$key = $this->cache->generateKey(['reverse', $lat, $lng]);
+		$key = ['reverse', $lat, $lng];
 		$cached = $this->cache->get($key);
 		if ($cached) {
 			return $cached;
@@ -302,7 +302,7 @@
 		$default_fields = ['name', 'formatted_address', 'geometry', 'rating', 'formatted_phone_number'];
 		$fields = empty($fields) ? $default_fields : $fields;
 
-		$key = $this->cache->generateKey(['place', $place_id, $fields]);
+		$key = ['place', $place_id, $fields];
 		$cached = $this->cache->get($key);
 		if ($cached) {
 			return $cached;
@@ -355,7 +355,7 @@
 			$params['type'] = $type;
 		}
 
-		$key = $this->cache->generateKey(['nearby', $lat, $lng, $radius, $type]);
+		$key = ['nearby', $lat, $lng, $radius, $type];
 		$cached = $this->cache->get($key);
 		if ($cached) {
 			return $cached;
@@ -406,7 +406,7 @@
 			'key' => $this->private_key
 		];
 
-		$key = $this->cache->generateKey(['distance', $origin_str, $dest_str, $mode]);
+		$key = ['distance', $origin_str, $dest_str, $mode];
 		$cached = $this->cache->get($key);
 		if ($cached) {
 			return $cached;
diff --git a/inc/integrations/services/GoogleMyBusiness.php b/inc/integrations/services/GoogleMyBusiness.php
index 25e98bb..8d374ea 100644
--- a/inc/integrations/services/GoogleMyBusiness.php
+++ b/inc/integrations/services/GoogleMyBusiness.php
@@ -9,7 +9,9 @@
 use JVBase\integrations\OAuthURLs;
 use JVBase\integrations\Requests;
 use JVBase\integrations\SyncTo;
+use JVBase\integrations\SyncToPost;
 use JVBase\integrations\UserConnection;
+use WP_Error;
 
 
 if (!defined('ABSPATH')) {
@@ -18,10 +20,10 @@
 
 class GoogleMyBusiness extends Integrations
 {
-	use Admin, Instance, OAuth, Requests, UserConnection, SyncTo;
+	use Admin, Instance, OAuth, Requests, UserConnection, SyncToPost;
 
 	protected string $readMask = 'name,title,storefrontAddress,metadata,openInfo,storeCode,categories,phoneNumbers,labels,specialHours';
-
+	protected string $businessV4;
 	protected function __construct()
 	{
 		$this->service_name = 'gmb';
@@ -35,6 +37,9 @@
 		];
 		$this->supportsWebp = false;
 
+		$this->baseUrl = 'https://mybusinessbusinessinformation.googleapis.com';
+		$this->businessV4 = 'https://mybusiness.googleapis.com/v4';
+
 		$this->defineFields();
 		$this->defineInstructions();
 		$this->defineOAuth();
@@ -140,7 +145,12 @@
 
 	protected function getRequestHeaders(): array
 	{
-		// TODO: Implement getRequestHeaders() method.
+
+		return [
+			'Authorization' => 'Bearer ' . $this->getAccessToken(),
+			'Content-Type' => 'application/json',
+			'Accept' => 'application/json'
+		];
 	}
 
 	protected function handleResponse(\WP_Error|array $response, string $method, string $endpoint): array
@@ -151,14 +161,16 @@
 
 		return match($endpoint) {
 			'https://mybusinessaccountmanagement.googleapis.com/v1/accounts' => $this->handleGetAccountsResponse($response, $method),
+			sprintf('%s/%s/%s/reviews', $this->businessV4, $this->getAccountID()??'', $this->getLocationID()??'') => $this->handleGetReviewResponse($response, $method),
 			sprintf('https://mybusinessbusinessinformation.googleapis.com/v1/%s/locations', $this->getAccountID()??'') => $this->handleGetLocationsResponse($response, $method),
+			sprintf('%s/v1/%s', $this->baseUrl,$this->getLocationID()??'') => $this->handleGetLocationResponse($response, $method),
 			default => $this->response(false, 'Unhandled response for '.$endpoint.' endpoint, with method: '.$method)
 		};
 	}
 
 	protected function refreshAccessToken(OAuthCredentials $credentials): array
 	{
-		// TODO: Implement refreshAccessToken() method.
+
 	}
 
 	/*********************************************************
@@ -177,6 +189,31 @@
 		return $stored;
 	}
 
+	protected function getLocation(bool $force = false):?array
+	{
+		$location_name = $this->getLocationID();
+		if (empty($location_name)) {
+			return null;
+		}
+		$params = [
+			'readMask'	=> $this->readMask
+		];
+
+		return $this->getRequest(
+			sprintf(
+				'%s/v1/%s',
+				$this->baseUrl,
+				$location_name,
+			),
+			$params,
+			$force
+		);
+
+	}
+		protected function handleGetLocationResponse(WP_Error|array $response, string $method):?array
+		{
+			return $response??null;
+		}
 	protected function getLocationID():string|false
 	{
 		return $this->loadCredentials()['location_id']??false;
@@ -254,11 +291,323 @@
 
 	protected function setContentTypes(): void
 	{
-		// TODO: Implement setContentTypes() method.
+		$this->contentTypes = [
+			'menu_item'	=> $this->buildMenuItemContentType(),
+			'post'		=> $this->buildPostContentType(),
+			'event'		=> $this->buildEventContentType(),
+			'offer'		=> $this->buildOfferContentType(),
+		];
 	}
-
+		protected function buildMenuItemContentType():array
+		{
+			return [
+				'nutritionFacts'	=> [
+					'type'	=> 'repeater',
+					'label'	=> 'Nutrition',
+					'fields'	=> [
+						'name'	=> [
+							'type'	=> 'select',
+							'label'	=> 'Name',
+							'options'	=> [
+								'calories' => 'Calories',
+								'totalFat'	=> 'Total Fat',
+								'cholesterol' => 'Cholesterol',
+								'sodium'	=> 'Sodium',
+								'totalCarbohydrate' => 'Total Carbohydrates',
+								'protein'	=> 'Protein'
+							]
+						],
+						'amount'	=> [
+							'type'	=> 'number',
+							'label'	=> 'Amount',
+						],
+						'unit'	=> [
+							'type' => 'select',
+							'label'	=> 'Unit',
+							'options'	=> [
+								'MILLIGRAM' => 'Milligram',
+								'GRAM'	=> 'Gram',
+								'CALORIE'	=> 'Calorie'
+							]
+						]
+					],
+					'description'	=> 'Recommended. Example: Total Fat: 3g',
+					'section'	=> 'gmb',
+				],
+				'servesNumPeople'	=> [
+					'type'	=> 'number',
+					'label'	=> 'Number of People this Serves',
+					'bulkEdit'	=> true,
+					'section'	=> 'gmb',
+				],
+				'portionSize'	=> [
+					'type'	=> 'text',
+					'label'	=> 'Portion size',
+					'description' => 'Example: 8-piece of nuggets',
+					'bulkEdit'	=> true,
+					'section'	=> 'gmb',
+				],
+				'preparationMethods' => [
+					'type'	=> 'textarea',
+					'label'	=> 'Preparation Methods',
+					'description'	=> 'Specific methods that the food can be prepared in',
+					'bulkEdit'	=> true,
+					'section'	=> 'gmb',
+				],
+				'cuisines'	=> [
+					'type'	=> 'text',
+					'label'	=> 'Cuisines',
+					'description'	=> 'Recommended. The specific cuisine of the food item',
+					'bulkEdit'	=> true,
+					'section'	=> 'gmb',
+				],
+				'spiciness'	=> [
+					'type'	=> 'select',
+					'label'	=> 'Spiciness',
+					'options'	=> [
+						'none'	=> 'None',
+						'mild'	=> 'Mild',
+						'medium'	=> 'Medium',
+						'hot'	=> 'Hot',
+					],
+					'bulkEdit'	=> true,
+					'section'	=> 'gmb',
+				],
+				'allergen'	=> [
+					'type'	=> 'checkbox',
+					'label'	=> 'Allergens',
+					'options'	=> [
+						'dairy'	=> 'Dairy',
+						'egg'	=> 'Egg',
+						'fish'	=> 'Fish',
+						'peanut'	=> 'Peanut',
+						'shellfish'	=> 'Shellfish',
+						'soy'		=> 'Soy',
+						'tree nut'	=> 'Tree Nut',
+						'wheat'		=> 'Wheat'
+					],
+					'description'	=> 'Recommended',
+					'bulkEdit'	=> true,
+					'section'	=> 'gmb',
+				],
+				'dietaryRestriction'	=> [
+					'type'	=> 'checkbox',
+					'label'	=> 'Dietary Restrictions',
+					'description' => 'Recommended.',
+					'options'	=> [
+						'halal' => 'Halal',
+						'kosher'	=> 'Kosher',
+						'organic'	=> 'Organic',
+						'vegan'		=> 'Vegan',
+						'vegetarian'	=> 'Vegetarian',
+						'gluten-free'	=> 'Gluten Free'
+					],
+					'bulkEdit'	=> true,
+					'section'	=> 'gmb',
+				]
+			];
+		}
+		protected function buildPostContentType():array
+		{
+			return [
+				'summary' => [
+					'type' => 'textarea',
+					'label' => 'Post Summary',
+					'required' => true
+				],
+				'language_code' => [
+					'type' => 'text',
+					'label' => 'Language',
+					'default' => 'en-CA'
+				],
+				'media' => [
+					'type' => 'image',
+					'label' => 'Photo',
+				],
+				'call_to_action' => [
+					'type' => 'group',
+					'fields' => [
+						'type' => [
+							'type' => 'select',
+							'options' =>
+								[
+									'BOOK' => 'Book Now',
+									'ORDER' => 'Order Now',
+									'SHOP' => 'Shop Now',
+									'LEARN_MORE' => 'Learn More',
+									'SIGN_UP' => 'Sign up',
+									'CALL' => 'Call'
+								]
+						],
+						'url' => [
+							'type' => 'url',
+							'label' => 'Action URL'
+						]
+					]
+				]
+			];
+		}
+		protected function buildEventContentType():array
+		{
+			return [
+				'summary' => [
+					'type' => 'textarea',
+					'label' => 'Event Description',
+					'required' => true
+				],
+				'event' => [
+					'title' => [
+						'type' => 'text',
+						'label' => 'Event Title',
+						'required' => true
+					],
+					'start_date' => [
+						'type' => 'date',
+						'label' => 'Start Date',
+						'required' => true
+					],
+					'end_date' => [
+						'type' => 'date',
+						'label' => 'End Date'
+					],
+					'start_time' => [
+						'type' => 'time',
+						'label' => 'Start Time'
+					],
+					'end_time' => [
+						'type' => 'time',
+						'label' => 'End Time'
+					]
+				],
+				'media' => [
+					'type' => 'image',
+					'label' => 'Event Photo'
+				]
+			];
+		}
+		protected function buildOfferContentType():array
+		{
+			return [
+				'summary' => [
+					'type' => 'textarea',
+					'label' => 'Offer Description',
+					'required' => true
+				],
+				'offer' => [
+					'coupon_code' => [
+						'type' => 'text',
+						'label' => 'Coupon Code'
+					],
+					'redeem_online_url' => [
+						'type' => 'url',
+						'label' => 'Redemption URL'
+					],
+					'terms_conditions' => [
+						'type' => 'textarea',
+						'label' => 'Terms & Conditions']
+				],
+				'media' => ['type' => 'image', 'label' => 'Offer Photo']
+			];
+		}
 	protected function formatForService(int $itemID, string $type = 'post'): array
 	{
 		// TODO: Implement formatForService() method.
 	}
+
+
+	public function getReviews(int $number = 5):array
+	{
+		if (!$this->getLocationID() || !$this->getAccountID()){
+			return [];
+		}
+		return $this->cache->remember(
+			['reviews', $this->getLocationID(), $number],
+			function() use ($number) {
+				try {
+					return $this->getRequest(
+						sprintf(
+							"%s/{$this->getAccountID()}/{$this->getLocationID()}/reviews",
+							$this->businessV4
+						),
+						[
+							'orderBy'	=> 'updateTime desc'
+						],
+					);
+				} catch (Exception $e) {
+					$this->logError(
+						'getReviews',
+					'Failed to fetch Reviews',
+					[
+						'error'	=> $e->getMessage()
+					]);
+					return [];
+				}
+			}
+		);
+	}
+		protected function handleGetReviewResponse(WP_Error|array $response, string $method):array
+		{
+			return $response;
+		}
+
+		/**********************************************************************
+		 * REVIEW UTILITY
+		**********************************************************************/
+		/**
+		 * Get the URL to view all Google reviews for the current location
+		 * @return string|null The reviews viewing URL or null if not available
+		 */
+		public function getReviewsViewUrl():?string
+		{
+			$location = $this->getLocation();
+			if (!$location) {
+				return null;
+			}
+
+			if (!empty($location['metadata']['mapsUrl']??'')) {
+				return $location['metadata']['mapsUrl'];
+			}
+
+			if (!empty($location['metadata']['placeId']??'')) {
+				return sprintf(
+					'https://search.google.com/local/reviews?placeid=%s',
+					urlencode($location['metadata']['placeId'])
+				);
+			}
+
+			return null;
+		}
+
+	/**
+	 * Get the URL to leave a review for the current location
+	 * @return string|null The review URL or null if not available
+	 */
+		public function getReviewUrl():?string
+		{
+			$location = $this->getLocation();
+			if (!$location) {
+				return null;
+			}
+
+			if (!empty($location['metadata']['placeId']??'')) {
+				return sprintf(
+					'https://search.google.com/local/writereview?placeid=%s',
+					urlencode($location['metadata']['placeId'])
+				);
+			}
+
+			if (!empty($location['metadata']['mapsUrl']??'')) {
+				return sprintf(
+					'%s/reviews',
+					$location['metadata']['mapsUrl']
+				);
+			}
+
+			return null;
+		}
+
+
+	/**************************************************************************
+	 * FOOD MENU HELPERS
+	**************************************************************************/
 }
diff --git a/inc/integrations/services/GoogleMyBusinessOld.php b/inc/integrations/services/GoogleMyBusinessOld.php
index 7a33151..111845f 100644
--- a/inc/integrations/services/GoogleMyBusinessOld.php
+++ b/inc/integrations/services/GoogleMyBusinessOld.php
@@ -143,9 +143,7 @@
 			]
 		);
 
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+
 	}
 
 	protected function initialize(): void
diff --git a/inc/integrations/services/InstagramOld.php b/inc/integrations/services/InstagramOld.php
index a09aa47..378cb7b 100644
--- a/inc/integrations/services/InstagramOld.php
+++ b/inc/integrations/services/InstagramOld.php
@@ -7,6 +7,7 @@
 namespace JVBase\integrations\services;
 use JVBase\integrations\Integrations;
 use JVBase\meta\Meta;
+use WP_Error;
 
 if (!defined('ABSPATH')) {
 	exit;
@@ -165,14 +166,14 @@
 	}
 
 	public function isSetUp():bool {
-		$fb = JVB()->connect('facebook');
+		$fb = Facebook::getInstance();
 		return $fb->isSetUp();
 	}
 
 	protected function getOAuthCredentials(): array
 	{
 		// Get Facebook integration
-		$facebook = JVB()->connect('facebook');
+		$facebook = Facebook::getInstance();
 
 		if (!$facebook || !$facebook->isSetUp()) {
 			return [];
@@ -190,7 +191,7 @@
 	public function getCredentials():array {
 		$credentials = parent::getCredentials();
 		if (empty($credentials)) {
-			$facebook = JVB()->connect('facebook');
+			$facebook = Facebook::getInstance();
 
 			if (!$facebook || !$facebook->isSetUp()) {
 				return [];
diff --git a/inc/integrations/services/UmamiOld.php b/inc/integrations/services/UmamiOld.php
index eb1df1e..bf4df17 100644
--- a/inc/integrations/services/UmamiOld.php
+++ b/inc/integrations/services/UmamiOld.php
@@ -145,10 +145,6 @@
 	 */
 	public function renderTrackingScript(): void
 	{
-		// Skip on local environments
-		if (JVB_TESTING) {
-			return;
-		}
 		if (!$this->isSetUp() || is_admin()) {
 			return;
 		}
diff --git a/inc/managers/CustomTable.php b/inc/managers/CustomTable.php
index c8a9171..bbe261f 100644
--- a/inc/managers/CustomTable.php
+++ b/inc/managers/CustomTable.php
@@ -1178,7 +1178,7 @@
 	private function logError(string $operation, array $context = []): void
 	{
 		if (function_exists('JVB')) {
-			JVB()->error()->log(
+			Errors::getInstance()->log(
 				$this->tableName,
 				"CustomTable {$operation} failed: " . $this->wpdb->last_error,
 				$context,
diff --git a/inc/managers/Dashboard/Dashboard.php b/inc/managers/Dashboard/Dashboard.php
index 43d6c52..0b4b4fb 100644
--- a/inc/managers/Dashboard/Dashboard.php
+++ b/inc/managers/Dashboard/Dashboard.php
@@ -19,9 +19,7 @@
 	private function __construct() {
 		self::$based = BASE.$this->slug;
 		$this->cache = Cache::for('dashboard', 'post');
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+
 		$this->registerDashboard();
 		$this->buildPages();
 		$this->buildSections();
diff --git a/inc/managers/Dashboard/DashboardPage.php b/inc/managers/Dashboard/DashboardPage.php
index bc0c040..af4145c 100644
--- a/inc/managers/Dashboard/DashboardPage.php
+++ b/inc/managers/Dashboard/DashboardPage.php
@@ -24,10 +24,8 @@
 	protected Cache $cache;
 
 	public function __construct(string $title, string $slug = '', string $icon ='', int $parent = 0) {
-		$this->cache = Cache::for('dashboard');
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+		$this->cache = Cache::for('dash_pages');
+
 		$this->title = $title;
 		$this->setSlug(empty($slug) ? $title : $slug);
 		$this->icon = $icon;
diff --git a/inc/managers/DashboardManager.php b/inc/managers/DashboardManager.php
index 35cad18..fc91ddf 100644
--- a/inc/managers/DashboardManager.php
+++ b/inc/managers/DashboardManager.php
@@ -28,9 +28,7 @@
     public function __construct()
     {
         $this->cache = Cache::for('dashboard', WEEK_IN_SECONDS)->user();
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+
 
         add_action('init', [$this, 'registerDashboard']);
 
@@ -964,10 +962,11 @@
 		if ($connection !== 'integrations') {
 
 			$userID = (Site::has('has_membership')) ? $this->user->ID : null;
-			$integration = JVB()->connect($connection, $userID);
-
-			echo '<h1>Managing '.$integration->title.'</h1>';
-			$integration->renderDefaults();
+			$integration = $this->getServiceUser($connection, $userID);
+			if (method_exists($integration, 'renderDefaults')) {
+				echo '<h1>Managing '.$integration->title.'</h1>';
+				$integration->renderDefaults();
+			}
 		} else {
 			?>
 			<section class="item-grid integrations">
diff --git a/inc/managers/DirectoryManager.php b/inc/managers/DirectoryManager.php
index 23bd63b..4f46e0f 100644
--- a/inc/managers/DirectoryManager.php
+++ b/inc/managers/DirectoryManager.php
@@ -6,6 +6,7 @@
 }
 
 use JVBase\Instance;
+use JVBase\integrations\services\Umami;
 use JVBase\registrar\Registrar;
 use JVBase\base\Site;
 use WP_Block;
@@ -31,9 +32,7 @@
 		$this->perPage = $perPage;
         $this->cache = Cache::for('directory', WEEK_IN_SECONDS);
 
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+
 
 		jvb_register_do_once('buildDirectories', [$this, 'activate']);
 		add_action('init', [$this, 'registerDirectories']);
@@ -680,7 +679,7 @@
     public function renderLettersList(array $list, string $type):string
     {
 
-        $umami = JVB()->connect('umami');
+        $umami = Umami::getInstance();
 
         $out = '<ul class="list-none">';
         foreach ($list as $letter => $items) {
diff --git a/inc/managers/Favourites.php b/inc/managers/Favourites.php
index c48e42d..66370a0 100644
--- a/inc/managers/Favourites.php
+++ b/inc/managers/Favourites.php
@@ -812,7 +812,7 @@
 				'item_id'	=> $post_id
 			])->deleteResults();
 		} catch (Exception $e) {
-			JVB()->error()->log('cleanupPostFavourites', $e->getMessage(), [
+			Errors::getInstance()->log('cleanupPostFavourites', $e->getMessage(), [
 				'post_id' => $post_id
 			]);
 		}
@@ -835,7 +835,7 @@
 				'item_id'	=> $term_id
 			])->deleteResults();
 		} catch (Exception $e) {
-			JVB()->error()->log('cleanupTermFavourites', $e->getMessage(), [
+			Errors::getInstance()->log('cleanupTermFavourites', $e->getMessage(), [
 				'term_id' => $term_id,
 				'taxonomy'=> $taxonomy
 			]);
diff --git a/inc/managers/IconsManager.php b/inc/managers/IconsManager.php
index cf48409..b3b5d62 100644
--- a/inc/managers/IconsManager.php
+++ b/inc/managers/IconsManager.php
@@ -26,6 +26,15 @@
 	protected array $map = [];
 	protected const MAX_VERSIONS = 5;
 
+	protected string $timestampKey;
+	protected string $iconKey;
+	protected string $iconHistoryKey;
+	protected static string $allIcons = 'icons_all_used';
+	protected static string $updateIcons = 'icons_needs_update';
+	protected static string $iconMap = 'icons_map';
+
+
+
 	/**
 	 * Factory method - get or create instance for a source
 	 */
@@ -34,6 +43,9 @@
 		if (!isset(self::$instances[$source])) {
 			self::$instances[$source] = new self($source);
 		}
+		self::$instances[$source]->setTimestampKey(BASE.'icons_'.$source.'_timestamp');
+		self::$instances[$source]->setIconKey(BASE.'icons_'.$source);
+		self::$instances[$source]->setIconHistoryKey(BASE.'icons_history_'.$source);
 		return self::$instances[$source];
 	}
 
@@ -72,6 +84,19 @@
 		$this->registerInstanceHooks();
 	}
 
+	protected function setIconKey(string $key):void
+	{
+		$this->iconKey = $key;
+	}
+	protected function setTimestampKey(string $key):void
+	{
+		$this->timestampKey = $key;
+	}
+	protected function setIconHistoryKey(string $key):void
+	{
+		$this->iconHistoryKey = $key;
+	}
+
 
 
 	/**
@@ -124,7 +149,7 @@
 	 */
 	protected function loadStoredIcons(): void
 	{
-		$allIcons = get_option(BASE.'usedIcons', []);
+		$allIcons = get_option(BASE.self::$allIcons, []);
 		$storedIcons = $allIcons[$this->source] ?? [];
 
 		// Merge stored icons with any existing icons (like custom icons)
@@ -304,20 +329,19 @@
 	 */
 	protected function saveIcons(): void
 	{
-		$allIcons = [];
-		foreach (self::$instances as $source => $instance) {
-			$allIcons[$source] = $instance->icons;
-		}
+		$allIcons = array_map(function ($instance) {
+			return $instance->icons;
+		}, self::$instances);
 
-		update_option(BASE.'usedIcons', $allIcons);
+		update_option(BASE.self::$allIcons, $allIcons);
 
 		// Track WHICH source needs updating
-		$needsUpdate = get_option(BASE.'icons_needs_update', []);
+		$needsUpdate = get_option(BASE.self::$updateIcons, []);
 		if (!is_array($needsUpdate)) {
 			$needsUpdate = [];
 		}
 		$needsUpdate[$this->source] = true;
-		update_option(BASE.'icons_needs_update', $needsUpdate);
+		update_option(BASE.self::$updateIcons, $needsUpdate);
 	}
 
 	/**
@@ -345,7 +369,7 @@
 
 	protected function addMap(): void
 	{
-		$map = get_option(BASE.'iconMap');
+		$map = get_option(BASE.self::$iconMap);
 		if (!$map) {
 			$map = [
 				'seo'	=> 'robot'
@@ -362,7 +386,7 @@
 			if (Site::hasAnyIntegration()) {
 				$map['integrations'] = 'plugs-connected';
 			}
-			update_option(BASE.'iconMap', $map);
+			update_option(BASE.self::$iconMap, $map);
 		}
 
 		$this->map = apply_filters('jvbMapIcons', $map);
@@ -404,10 +428,13 @@
 
 	public static function checkCSS(): void
 	{
-		$needsUpdate = get_option(BASE.'icons_needs_update', []);
+		$needsUpdate = get_option(BASE.self::$updateIcons, []);
+		$needsUpdate = array_filter($needsUpdate, function ($item) {
+			return $item === true;
+		});
 		if (!empty($needsUpdate)) {
 			error_log('Regenerating CSS for sources: ' . implode(', ', array_keys($needsUpdate)));
-			delete_option(BASE.'icons_needs_update');
+			delete_option(BASE.self::$updateIcons);
 			self::regenerateAllCSS($needsUpdate);
 		}
 	}
@@ -422,7 +449,7 @@
 		}
 
 		// Load all icons from database option
-		$allIcons = get_option(BASE.'usedIcons', []);
+		$allIcons = get_option(BASE.self::$allIcons, []);
 
 		// If no specific sources provided, regenerate all
 		if (empty($sourcesToUpdate)) {
@@ -535,7 +562,7 @@
 		}
 
 		// Track usage - only if not already tracked
-		if (!isset($this->icons[$style])) {
+		if (!array_key_exists($style, $this->icons)) {
 			$this->icons[$style] = [];
 		}
 
@@ -649,7 +676,7 @@
 
 	public function registerStyle(): void
 	{
-		$timestamp = Cache::for('icons_'.$this->source)->getTimestamp();
+		$timestamp = get_option($this->timestampKey);
 		$handle = 'jvb-icons-' . $this->source;
 
 		wp_register_style(
@@ -687,7 +714,7 @@
 				}
 			}
 		}
-
+		update_option($this->timestampKey, time());
 		return $this->minifyCss($css);
 	}
 
@@ -743,9 +770,8 @@
 	 */
 	public function clearIconCache(): void
 	{
-		delete_option(BASE . 'icon_usage_list'); // Legacy
-		delete_option(BASE.'usedIcons');
-		delete_option(BASE.'iconMap');
+		delete_option(self::$allIcons);
+		delete_option(self::$iconMap);
 
 		// Clear cache for all sources
 		foreach (self::$instances as $source => $instance) {
@@ -777,12 +803,12 @@
 			$history = array_slice($history, 0, self::MAX_VERSIONS);
 		}
 
-		update_option(BASE.'icon_css_history_' . $this->source, $history);
+		update_option($this->iconHistoryKey, $history);
 	}
 
 	public function getVersionHistory(): array
 	{
-		return get_option(BASE.'icon_css_history_' . $this->source, []);
+		return get_option($this->iconHistoryKey, []);
 	}
 
 	public function restoreVersion(int $timestamp): bool
@@ -818,12 +844,12 @@
 	public function forceRefresh(): void
 	{
 		$this->clearIconCache();
-		$needsUpdate = get_option(BASE.'icons_needs_update', []);
+		$needsUpdate = get_option(BASE.self::$updateIcons, []);
 		if (!is_array($needsUpdate)) {
 			$needsUpdate = [];
 		}
 		$needsUpdate[$this->source] = true;
-		update_option(BASE.'icons_needs_update', $needsUpdate);
+		update_option(BASE.self::$updateIcons, $needsUpdate);
 
 		Cache::for('icons_'.$this->source)->flush();
 	}
@@ -834,7 +860,7 @@
 			return false;
 		}
 
-		$history = get_option(BASE.'icon_css_history_' . $this->source, []);
+		$history = get_option($this->iconHistoryKey, []);
 		$merged_icons = [];
 
 		// Collect icons from selected versions
diff --git a/inc/managers/InvitationsManager.php b/inc/managers/InvitationsManager.php
index 45178b4..0f95ad8 100644
--- a/inc/managers/InvitationsManager.php
+++ b/inc/managers/InvitationsManager.php
@@ -390,7 +390,7 @@
 		} catch (Exception $e) {
 			$this->table->rollback();
 
-			JVB()->error()->log(
+			Errors::getInstance()->log(
 				'invitation_create',
 				'Error processing invitations: ' . $e->getMessage(),
 				['user_id' => $userID],
diff --git a/inc/managers/Login.php b/inc/managers/Login.php
index c344023..77e3d2b 100644
--- a/inc/managers/Login.php
+++ b/inc/managers/Login.php
@@ -771,7 +771,7 @@
 		if (!Site::hasIntegration('cloudflare')) {
 			return;
 		}
-		JVB()->connect('cloudflare')->renderTurnstile();
+		Cloudflare::getInstance()->renderTurnstile();
 	}
 
 	protected function maybeTurnstileScripts(): void
diff --git a/inc/managers/MagicLinks.php b/inc/managers/MagicLinks.php
index 3217948..4846d4a 100644
--- a/inc/managers/MagicLinks.php
+++ b/inc/managers/MagicLinks.php
@@ -6,6 +6,7 @@
 use JVBase\Instance;
 use JVBase\integrations\services\Cloudflare;
 use JVBase\meta\Form;
+use JVBase\rest\routes\LoginRoutes;
 use JVBase\ui\Tabs;
 use WP_User;
 use WP_Error;
@@ -380,7 +381,7 @@
 	#[NoReturn] protected function processSignup(array $token_data): void
 	{
 		if (!array_key_exists('email', $token_data) || !array_key_exists('name', $token_data)) {
-			JVB()->error()->log('MagicLinkManager', 'Could not process Signup');
+			Errors::getInstance()->log('MagicLinkManager', 'Could not process Signup');
 			$this->cleanURL();
 		}
 		$user_id = wp_create_user(
@@ -427,7 +428,7 @@
 	protected function processReferralSignup(array $token_data): void
 	{
 		if (!array_key_exists('email', $token_data) || !array_key_exists('name', $token_data)) {
-			JVB()->error()->log('[MagicLinkManager]Could not process Referral Signup');
+			Errors::getInstance()->log('[MagicLinkManager]Could not process Referral Signup');
 			return;
 		}
 
@@ -447,13 +448,13 @@
 			'role'			=> $role
 		]);
 		if (!is_wp_error($user_id)) {
-			$response = JVB()->routes('login')->login($email, $pass, true);
-			if ($response) {
+			$response = LoginRoutes::getInstance()->login($email, $pass, true);
+			if (!is_wp_error($response)) {
 				wp_safe_redirect(home_url('/dash?welcome=1&referral=1'));
 				exit;
 			}
 		} else {
-			JVB()->error()->log(
+			Errors::getInstance()->log(
 				'[MagicLinkManager]',
 				$user_id->get_error_message(),
 				$token_data
@@ -470,7 +471,7 @@
 		$user = get_user_by('ID', $token_data['user_id']);
 
 		if (!$user) {
-			JVB()->error()->log(
+			Errors::getInstance()->log(
 				'MagicLinkManager',
 				'Invalid user, could not reset password',
 			);
diff --git a/inc/managers/OperationQueue.php b/inc/managers/OperationQueue.php
index 949e5c6..77ba35a 100644
--- a/inc/managers/OperationQueue.php
+++ b/inc/managers/OperationQueue.php
@@ -547,7 +547,7 @@
 			];
 
 		} catch (Exception $e) {
-			JVB()->error()->log('queue', $e->getMessage(), $data, 'high');
+			Errors::getInstance()->log('queue', $e->getMessage(), $data, 'high');
 			return new WP_Error('queue_failed', $e->getMessage());
 		}
 	}
@@ -1029,7 +1029,7 @@
                 );
 
                 // Log this as a critical error
-                JVB()->error()->log(
+                Errors::getInstance()->log(
                     '[OperationQueue]:restartStuckOperations',
                     "Operation failed after maximum retries",
                     [
@@ -1057,7 +1057,7 @@
                 );
 
                 // Log the backoff
-                JVB()->error()->log(
+                Errors::getInstance()->log(
                     '[OperationQueue]:restartStuckOperations',
                     "Operation requeued with exponential backoff",
                     [
@@ -1184,7 +1184,7 @@
 			if (!is_array($filterResult) || !isset($filterResult['success'])) {
 				// Log invalid filter response and quit early
 				$invalid_response = is_object($filterResult) ? get_class($filterResult) : gettype($filterResult);
-				JVB()->error()->log(
+				Errors::getInstance()->log(
 					'[OperationQueue]:processOperation',
 					"Invalid filter response format - expected array with 'success' key",
 					[
@@ -1348,7 +1348,7 @@
 
 		} catch (Exception $e) {
 			// Handle exception...
-			JVB()->error()->log(
+			Errors::getInstance()->log(
 				'[OperationQueue]:processOperation',
 				"Exception during operation processing: " . $e->getMessage(),
 				[
@@ -1887,7 +1887,7 @@
 
             return $value;
         } catch (Exception $e) {
-            JVB()->error()->log(
+            Errors::getInstance()->log(
                 '[OperationQueue]:getOperationValue',
                 'Error retrieving operation value: ' . $e->getMessage(),
                 [
diff --git a/inc/managers/Referrals.php b/inc/managers/Referrals.php
index 71769f7..3fc2f45 100644
--- a/inc/managers/Referrals.php
+++ b/inc/managers/Referrals.php
@@ -66,11 +66,6 @@
 		$this->cache = Cache::for('referrals', WEEK_IN_SECONDS);
 //		$this->requestCache = Cache::for('referral_requests', WEEK_IN_SECONDS)->connect('referrals', true);
 		$this->statsCache = Cache::for('referral_stats', WEEK_IN_SECONDS)->connect('referrals', true)->user();
-		if (JVB_TESTING) {
-			$this->cache->flush();
-//			$this->requestCache->flush();
-			$this->statsCache->flush();
-		}
 
 		$this->referralPage = $this->getReferralPageId();
 		$this->settings = $this->getRewardSettings();
@@ -852,7 +847,7 @@
 	public function getTopReferrers(int $limit = 10, string $period = 'all'): array
 	{
 		return $this->statsCache->remember(
-			$this->statsCache->generateKey(['per_page' => $limit, 'period' => $period]),
+			['per_page' => $limit, 'period' => $period],
 			function() use ($limit, $period) {
 				$where = '';
 				if ($period !== 'all') {
diff --git a/inc/managers/Responses.php b/inc/managers/Responses.php
index 73bf4dc..555c688 100644
--- a/inc/managers/Responses.php
+++ b/inc/managers/Responses.php
@@ -157,6 +157,11 @@
 				'message'	=> 'Response content is empty'
 			];
 		}
+
+		$registrar = Registrar::getInstance($type);
+		if ($registrar) {
+			$type = $registrar->getBased();
+		}
 		$created = $this->responses->insert([
 			'item_id'	=> $item_id,
 			'user_id'	=> $user_id,
@@ -337,15 +342,19 @@
 		return $responses;
 	}
 
-	public function getAllItemResponses(int $itemID, array $args = [], bool $includeChildren = true):array
+	public function getAllItemResponses(int $itemID, array $oldArgs = [], bool $includeChildren = true):array
 	{
-		$args = wp_parse_args($args, [
+		$args = wp_parse_args($oldArgs, [
 			'orderby'	=> 'created_at',
 			'order'		=> 'DESC',
 			'page'		=> 1,
 			'per_page'	=> 20,
 		]);
 
+		if (array_key_exists('type', $oldArgs) || array_key_exists('content', $oldArgs) || array_key_exists('post_type', $oldArgs)) {
+			$args['type'] = jvbCheckBase($oldArgs['type']??$oldArgs['content']??$oldArgs['post_type']);
+		}
+
 		$where = [
 			'item_id'	=> $itemID,
 			'parent_id'	=> null
diff --git a/inc/managers/SEO/render/SchemaOutput.php b/inc/managers/SEO/render/SchemaOutput.php
index 41ce0c8..c26af60 100644
--- a/inc/managers/SEO/render/SchemaOutput.php
+++ b/inc/managers/SEO/render/SchemaOutput.php
@@ -98,9 +98,7 @@
 			if (!is_front_page()) {
 				$website = SchemaHelper::getInstance()::schema('website');
 				if (!empty($website)) {
-					if (JVB_TESTING) {
-						Cache::for('websiteSchema')->flush();
-					}
+
 					$website = Cache::for('websiteSchema')->remember(
 						'schema',
 						function () {
diff --git a/inc/managers/SEO/render/Traits/_Properties/reviewTrait.php b/inc/managers/SEO/render/Traits/_Properties/reviewTrait.php
index 4c677b7..5e0ddc3 100644
--- a/inc/managers/SEO/render/Traits/_Properties/reviewTrait.php
+++ b/inc/managers/SEO/render/Traits/_Properties/reviewTrait.php
@@ -1,6 +1,7 @@
 <?php
 namespace JVBase\managers\SEO\render\Traits\_Properties;
 
+use JVBase\integrations\services\GoogleMyBusiness;
 use JVBase\managers\SEO\render\Thing\CreativeWork\Review;
 use JVBase\managers\SEO\render\Thing\Intangible\Rating\Rating;
 use JVBase\managers\SEO\render\Thing\Person\Person;
@@ -169,7 +170,8 @@
 	{
 		$userID = (int) get_post_meta($meta->id(), BASE.'profile_link', true);
 		if ($userID && $userID > 0) {
-			$integration = JVB()->connect('gmb', $userID);
+			$integration = GoogleMyBusiness::getInstance();
+			$integration->switchUser($userID);
 			if ($integration && $integration->isSetUp()){
 				$fetched = $integration->getReviews(20);
 
diff --git a/inc/managers/TaxonomyRelationships.php b/inc/managers/TaxonomyRelationships.php
index 1462dd2..dc7a2d0 100644
--- a/inc/managers/TaxonomyRelationships.php
+++ b/inc/managers/TaxonomyRelationships.php
@@ -197,7 +197,7 @@
     {
 
         $term_posts = $this->cache->remember(
-			$this->cache->generateKey(['id' => $term_id, 'taxonomy' => $taxonomy]),
+			['id' => $term_id, 'taxonomy' => $taxonomy],
 			function () use ($term_id, $taxonomy) {
 				global $wpdb;
 				return $wpdb->get_col($wpdb->prepare(
@@ -212,7 +212,7 @@
 
 
         $related_term_posts = $this->cache->remember(
-			$this->cache->generateKey(['id' => $related_term_id, 'taxonomy' => $related_taxonomy]),
+			['id' => $related_term_id, 'taxonomy' => $related_taxonomy],
 			function () use($related_term_id, $related_taxonomy) {
 				global $wpdb;
 				return $wpdb->get_col($wpdb->prepare(
diff --git a/inc/managers/UserTermsManager.php b/inc/managers/UserTermsManager.php
index 80995cc..5ce2829 100644
--- a/inc/managers/UserTermsManager.php
+++ b/inc/managers/UserTermsManager.php
@@ -318,7 +318,7 @@
 				'result'	=> $results
             ];
         } catch (Exception $e) {
-            JVB()->error()->log(
+            Errors::getInstance()->log(
                 '[UserTermsManager]:processOperation',
                 "Exception during operation processing: " . $e->getMessage(),
                 [
diff --git a/inc/managers/queue/Queue.php b/inc/managers/queue/Queue.php
index c668f4c..6fb6242 100644
--- a/inc/managers/queue/Queue.php
+++ b/inc/managers/queue/Queue.php
@@ -5,6 +5,7 @@
 }
 
 use JVBase\Instance;
+use JVBase\managers\Errors;
 use JVBase\rest\routes\QueueRoutes;
 use WP_Error;
 use WP_REST_Request;
@@ -103,7 +104,7 @@
 			];
 
 		} catch (\Exception $e) {
-			JVB()->error()->log('queue', $e->getMessage(), $data, 'high');
+			Errors::getInstance()->log('queue', $e->getMessage(), $data, 'high');
 			return new WP_Error('queue_failed', $e->getMessage());
 		}
 	}
diff --git a/inc/managers/queue/executors/ContentExecutor.php b/inc/managers/queue/executors/ContentExecutor.php
index 2755eb9..bc6ee4b 100644
--- a/inc/managers/queue/executors/ContentExecutor.php
+++ b/inc/managers/queue/executors/ContentExecutor.php
@@ -2,6 +2,7 @@
 namespace JVBase\managers\queue\executors;
 
 use JVBase\managers\queue\{Executor, Operation, Progress, Result, Storage};
+use JVBase\managers\Errors;
 use JVBase\meta\Meta;
 use JVBase\registrar\Registrar;
 use Exception;
@@ -43,7 +44,7 @@
 			};
 
 		} catch (Exception $e) {
-			JVB()->error()->log(
+			Errors::getInstance()->log(
 				'[ContentExecutor]:execute',
 				$e->getMessage(),
 				[
diff --git a/inc/managers/queue/executors/IntegrationExecutor.php b/inc/managers/queue/executors/IntegrationExecutor.php
index 9af8556..3896fa5 100644
--- a/inc/managers/queue/executors/IntegrationExecutor.php
+++ b/inc/managers/queue/executors/IntegrationExecutor.php
@@ -3,6 +3,9 @@
 
 use JVBase\managers\queue\{Executor, Operation, Progress, Result};
 use Exception;
+use JVBase\integrations\Integrations;
+use JVBase\integrations\ServiceMap;
+use JVBase\managers\Errors;
 
 if (!defined('ABSPATH')) {
 	exit;
@@ -28,11 +31,8 @@
  */
 final class IntegrationExecutor implements Executor
 {
-	/**
-	 * Map of integration service names to class identifiers.
-	 * Populated on first use from JVB()->connect().
-	 */
-	private array $integrationCache = [];
+	use ServiceMap;
+
 
 	public function execute(Operation $operation, Progress $progress): Result
 	{
@@ -60,7 +60,7 @@
 			};
 
 		} catch (Exception $e) {
-			JVB()->error()->log(
+			Errors::getInstance()->log(
 				'[IntegrationExecutor]:execute',
 				$e->getMessage(),
 				[
@@ -105,7 +105,7 @@
 		if ($userId === 0) {
 			$userId = null;
 		}
-		return JVB()->connect($serviceName, $userId);
+		return $this->getServiceUser($serviceName, $userId);
 	}
 
 	/*****************************************************************
diff --git a/inc/meta/Storage.php b/inc/meta/Storage.php
index 2cb37cf..f5b24a2 100644
--- a/inc/meta/Storage.php
+++ b/inc/meta/Storage.php
@@ -3,6 +3,7 @@
 
 use Exception;
 use JVBase\managers\Cache;
+use JVBase\managers\Errors;
 
 if (!defined('ABSPATH')) {
 	exit;
@@ -163,14 +164,13 @@
 			$this->wpdb->query('COMMIT');
 
 			// Update post modified timestamp
-			Cache::invalidateItem($item->objectType, $item->id);
 			$this->clearCache($item);
 
 			return true;
 
 		} catch (Exception $e) {
 			$this->wpdb->query('ROLLBACK');
-			JVB()->error()->log('meta_storage', $e->getMessage(), [
+			Errors::getInstance()->log('meta_storage', $e->getMessage(), [
 				'item_id' => $item->id,
 				'object_type' => $item->objectType,
 				'fields' => array_keys($dirty)
@@ -326,7 +326,7 @@
 				$results[$meta->item()->id ?? 'options'] = false;
 			}
 
-			JVB()->error()->log('meta_storage', 'Bulk save failed: ' . $e->getMessage(), [], 'error');
+			Errors::getInstance()->log('meta_storage', 'Bulk save failed: ' . $e->getMessage(), [], 'error');
 
 			return $results;
 		}
@@ -609,12 +609,21 @@
 
 	public function clearCache(Item $item): void
 	{
-		match ($item->objectType) {
-			'post' => clean_post_cache($item->id),
-			'term' => clean_term_cache($item->id),
-			'user', 'integrations' => clean_user_cache($item->id),
-			default => null
-		};
+		switch ($item->objectType) {
+			case 'post':
+				Cache::clearPost($item->id);
+				clean_post_cache($item->id);
+				break;
+			case 'term':
+				Cache::clearTerm($item->id);
+				clean_term_cache($item->id);
+				break;
+			case 'user':
+			case 'integrations':
+				Cache::clearUser($item->id);
+				clean_user_cache($item->id);
+				break;
+		}
 	}
 
 	// ─────────────────────────────────────────────────────────────
diff --git a/inc/registrar/Posts.php b/inc/registrar/Posts.php
index de0f72a..8922af7 100644
--- a/inc/registrar/Posts.php
+++ b/inc/registrar/Posts.php
@@ -356,7 +356,7 @@
 		}
 
 		if (is_wp_error($registered)) {
-			JVB()->error()->log('JVBase\registrar\Posts', 'Could not register post type', $registered->get_error_messages());
+			Errors::getInstance()->log('JVBase\registrar\Posts', 'Could not register post type', $registered->get_error_messages());
 		}
 	}
 
diff --git a/inc/registrar/Registrar.php b/inc/registrar/Registrar.php
index 3cc1b10..821c6db 100644
--- a/inc/registrar/Registrar.php
+++ b/inc/registrar/Registrar.php
@@ -1070,9 +1070,6 @@
 		if ($block['blockName'] !== 'core/post-content') {
 			return $content;
 		}
-		if (JVB_TESTING) {
-			Cache::for($this->slug)->flush();
-		}
 
         $per_page = 10;
         $page = $_GET['tp']??1;
@@ -1089,7 +1086,7 @@
 			'order'		=> 'desc',
         ]);
 
-        $cache = Cache::for($this->slug)->connect('taxonomy');
+        $cache = Cache::for($this->slug, 'term');
 		$max = $cache->remember(
 			'max',
 			function () {
@@ -1131,7 +1128,7 @@
 
 
 		$out = $nav. Cache::for($this->slug)->remember(
-			$cache->generateKey(['type' =>'contentArchive', ... $args]),
+			['type' =>'contentArchive', ... $args],
 			function() use ($args) {
 
 
diff --git a/inc/registrar/config/seo/Schema.php b/inc/registrar/config/seo/Schema.php
index c87147d..e12796f 100644
--- a/inc/registrar/config/seo/Schema.php
+++ b/inc/registrar/config/seo/Schema.php
@@ -158,9 +158,7 @@
 		public function outputContentTaxArchiveSchema():array
 		{
 			$ID = get_the_ID();
-			if (JVB_TESTING) {
-				$this->cache->flush();
-			}
+
 			return $this->cache->remember(
 				$ID,
 				function() use ($ID) {
@@ -264,13 +262,7 @@
 					$itemList->setItemListElement($itemListItems);
 					$class->setMainEntity($itemList);
 
-					$schema = $class->outputSchema();
-
-					if (JVB_TESTING) {
-//						error_log('Generated archive schema: '.print_r($schema, true));
-					}
-
-					return $schema;
+					return $class->outputSchema();
 				}
 			);
 		}
diff --git a/inc/rest/RegisterRoutes.php b/inc/rest/RegisterRoutes.php
deleted file mode 100644
index 76c0710..0000000
--- a/inc/rest/RegisterRoutes.php
+++ /dev/null
@@ -1,359 +0,0 @@
-<?php
-namespace JVBase\rest;
-
-if (!defined('ABSPATH')) {
-	exit;
-}
-use JVBase\meta\Meta;
-use WP_Error;
-use WP_REST_Request;
-use WP_REST_Response;
-
-/**
- * @deprecated
- */
-class RegisterRoutes extends RestRouteManager {
-
-	protected array $config;
-	protected array $tables = [];
-	protected $wpdb;
-	public function __construct(
-		string $content,
-		array $config
-	) {
-		$this->route = $content;
-		$this->config = $config;
-		$this->cache_name = $content;
-
-
-		parent::__construct();
-
-		global $wpdb;
-		$this->wpdb = $wpdb;
-
-		if (jvbCheck('invitable', $this->config)) {
-			foreach ($this->config['for_content'] as $c) {
-				$this->tables[$c] = BASE .'invitations_'.$c;
-			}
-		}
-
-		$this->action = 'dash-';
-		add_filter(BASE.'handle_bulk_operation', [$this, 'processOperation'], 10, 3);
-	}
-
-	public function registerRoutes()
-	{
-		register_rest_route($this->namespace, "/{$this->route}", [
-			[
-				'methods'				=> 'GET',
-				'callback'				=> [$this, 'handleGET'],
-				'permission_callback'	=> [$this, 'checkPermission'],
-			],
-			[
-				'methods'				=> 'POST',
-				'callback'				=> [$this, 'handlePOST'],
-				'permission_callback'	=> [$this, 'checkPermission'],
-			]
-		]);
-
-		if (jvbCheck('invitable', $this->config)) {
-			register_rest_route($this->namespace, "/{$this->route}/members", [
-				[
-					'methods'				=> 'GET',
-					'callback'				=> [$this, 'getInvitations'],
-					'permission_callback'	=> [$this, 'checkPermission'],
-				],
-				[
-					'methods'				=> 'POST',
-					'callback'				=> [$this, 'handleActions'],
-					'permission_callback'	=> [$this, 'checkPermission'],
-				]
-			]);
-		}
-
-		if (jvbCheck('verify_entry', $this->config)) {
-			register_rest_Route($this->namespace, "/{$this->route}/requests", [
-				[
-					'methods'				=> 'POST',
-					'callback'				=> [$this, 'handleInvite'],
-					'permission_callback'	=> [$this, 'checkPermission']
-				]
-			]);
-		}
-
-	}
-
-	public function checkPermission(WP_REST_Request $request):bool
-	{
-		if ($this->route === 'options' && !current_user_can('manage_options')) {
-			return false;
-		} elseif (array_key_exists('is_owned_by', $this->config)) {
-			$term = $request->get_param('term_id');
-			if (!$this->checkTerm([
-				'term_id'	=> $term,
-				'taxonomy'	=> $this->route
-			])) {
-				return false;
-			}
-			if (!current_user_can('manage_'.$this->route.'_'.$term)) {
-				return false;
-			}
-		}
-		return parent::checkPermission($request);
-	}
-
-	public function handleGET(WP_REST_Request $request):WP_REST_Response
-	{
-
-	}
-
-	public function handlePOST(WP_REST_Request $request):WP_REST_Response
-	{
-		$data = $request->get_params();
-		$user = $data['user'];
-		if (!$this->checkUser($user) || !$this->userCheck($user)) {
-			return new WP_REST_Response([
-				'success'   => false,
-				'message'   => 'Looks like you may not be who you say you are...'
-			]);
-		}
-		if ($this->route === 'shop' && !$this->checkTerm([
-			'term_id'	=> $data['shop'],
-			'taxonomy'	=> $this->route
-		])) {
-			return new WP_REST_Response([
-				'success'   => false,
-				'message'   => 'This shop doesn\'t exist?'
-			]);
-		}
-		$queue = Queue::getInstance();
-		unset($data['user']);
-		$operationID = $data['id'];
-		unset($data['id']);
-
-		$queue->queueOperation(
-			$this->route.'_update',
-			$user,
-			$data,
-			[
-				'operation_id'	=> $operationID,
-				'priority'		=> 'high',
-			]
-		);
-		return new WP_REST_Response([
-			'success'	=> true,
-			'message'	=> 'Successfully queued for processing'
-		]);
-	}
-
-	public function processOperation(WP_Error|array $result, object $operation, array $data):WP_Error|array
-	{
-		switch ($operation->type) {
-			case $this->route.'_update':
-				return $this->handleUpdateOperation($operation->user_id, $data);
-			default:
-				return $result;
-		}
-	}
-	protected function handleUpdateOperation(int $userID, array $data):WP_Error|array
-	{
-		if ($this->route === 'options') {
-			if (!user_can($userID, 'manage_options')) {
-				return [
-					'success'   => false,
-					'error'     => 'User cannot change options'
-				];
-			}
-			$meta = Meta::forOptions($this->route);
-		} else {
-			$termID = (int) $data['term_id'];
-			if (!user_can($userID, 'manage_'.$this->route.'_'.$termID)) {
-				return [
-					'success'   => false,
-					'error'     => 'User cannot manage this '.$this->route
-				];
-			}
-			$meta = Meta::forTerm($termID);
-		}
-
-		$results = [];
-
-		$allowed = array_filter($data, function ($v, $k) {
-			return array_key_exists($v, $this->config['fields']??[]);
-		}, ARRAY_FILTER_USE_BOTH);
-
-
-		foreach ($allowed as $name => $value) {
-			if (empty($value)) {
-				$results[] = $meta->delete($name);
-			} else {
-				$results[] = $meta->set($name, $value);
-			}
-		}
-		//Allow plugins & themes to process extra data here
-		//Example: custom image generation logic
-		$results = array_merge($results, apply_filters('jvb_'.$this->route.'_update_extra', [], $data));
-
-		return [
-			'success'	=> true,
-			'message'	=> $this->route.' successfully updated',
-			'results'	=> $results
-		];
-	}
-	public function getInvitations(WP_REST_Request $request):WP_REST_Response
-	{
-		$termID = (int) $request->get_param('term_id');
-		if (!$this->checkTerm(['term_id' => $termID, 'taxonomy' => $this->route])) {
-			return new WP_REST_Response([
-				'success'   => false,
-				'message'   => 'Invalid shop'
-			]);
-		}
-		$status = $request->get_param('status') ?? 'all';
-		$page = $request->get_param('page') ?? 1;
-		$role = $request->get_param('content') ?? $this->config['for_content'][0];
-		return JVB()->routes('invites')->getTermInvitations(['to_term' => $termID, 'status' => $status, 'page' => $page, 'taxonomy' => $this->route, 'role' => $role]);
-	}
-
-	public function handleActions(WP_REST_Request $request):WP_REST_Response
-	{
-		$action = $request->get_param('action');
-		$termID = (int)$request->get_param('term_id');
-		$userID = (int)$request->get_param('user');
-		if (!$this->checkTerm(['term_id' => $termID, 'taxonomy' => $this->route]) || !$this->checkUser($userID)) {
-			return new WP_REST_Response([
-				'success'   => false,
-				'message'   => 'Invalid shop or user'
-			]);
-		}
-
-		switch ($action) {
-			case 'add_user':
-				$return = $this->addUserToTerm($userID, $termID);
-				break;
-			case 'remove_user':
-				$return = $this->removeUserFromTerm($userID, $termID);
-				break;
-			case 'add_invitation':
-				$invitation = JVB()->routes('invites')->createInvitation(
-					sanitize_text_field($request->get_param('name')),
-					sanitize_email($request->get_param('email')),
-					$userID,
-					sanitize_text_field($request->get_param('role')) ?? $this->config['for_content'][0],
-					$termID,
-					$this->route
-				);
-				if (is_wp_error($invitation)) {
-					$return = [
-						'success'	=> false,
-						'message'	=> $invitation->get_error_message()
-					];
-				}else {
-					$return = [
-						'success'	=> true,
-						'message'	=> 'Invitation sent successfully'
-					];
-				}
-				break;
-			case 'remove_invitation':
-
-				$targetUser = sanitize_text_field($request->get_param('target_user'));
-				$return = $this->removeTermInvite($userID, $termID, $targetUser);
-				break;
-			case 'process_request':
-				$request_id = sanitize_text_field($request->get_param('request_id'));
-				$decision = $request->get_param('decision');
-				$notes = $request->get_param('notes');
-				$return = $this->processTermRequest($request_id, $decision, $notes, $userID);
-				break;
-			default:
-				$return = [
-					'success'	=> false,
-					'message'	=> 'invalid action'
-				];
-		}
-		return new WP_REST_Response($return);
-	}
-
-
-	public function handleInvite(WP_REST_Request $request):WP_REST_Response
-	{
-
-	}
-
-	public function requestEntry(int $userID, string $role, int $termID, string $taxonomy):bool
-	{
-		if (!$this->checkUser($userID) || !$this->checkTerm(['term_id' => $termID, 'taxonomy' => $taxonomy])) {
-			return false;
-		}
-
-		$tableName = $this->wpdb->prefix . BASE . $role . '_' . $taxonomy . '_requests';
-
-		//Check if request already exists
-		$existing = $this->wpdb->get_var($this->wpdb->prepare(
-			"SELECT id FROM {$tableName} WHERE user_id = %d AND term_id = %d",
-			$userID,
-			$termID
-		));
-
-		if ($existing) {
-			return false;
-		}
-
-		//get the user's profile id
-		$profileID = get_user_meta($userID, BASE.'profile_link', true);
-		if (!$profileID) {
-			return false;
-		}
-
-		$result = $this->wpdb->insert(
-			$tableName,
-			[
-				'user_id' 		=> $userID,
-				'content_id'	=> $profileID,
-				'term_id'		=> $termID,
-				'status'		=> 'requested',
-				'created_date'	=> current_time('mysql')
-			]
-		);
-
-		if ($result === false) {
-			return false;
-		}
-
-		$this->notifyManagers($termID, $userID, $profileID);
-		return true;
-	}
-
-	protected function notifyManagers(int $termID, int $userID, int $profileID):void
-	{
-		if (!$this->checkTerm(['term_id' => $termID, 'taxonomy' => $this->route]) || !$this->checkUser($userID)) {
-			return;
-		}
-
-		$termMeta = Meta::forTerm($termID);
-		$managers = explode(',', $termMeta->get('managers'));
-		$owner = explode(',', $termMeta->get('owner'));
-
-		$owners = array_unique(array_merge($managers, $owner));
-
-		//Get requester's info
-		$userName = get_the_title($profileID);
-		$termName = get_term($termID, BASE.$this->route)->name;
-
-
-		//Notify managers
-		NotificationManager::getInstance()->addNotification(
-			$owners,
-			'entry_request',
-			[
-				'profile_id'	=> $profileID,
-				'user_name'		=> $userName,
-				'user_id'		=> $userID,
-				'term_id'		=> $termID,
-				'term_name'		=> $termName
-			]
-		);
-
-	}
-}
diff --git a/inc/rest/Rest.php b/inc/rest/Rest.php
index 4741e66..621329e 100644
--- a/inc/rest/Rest.php
+++ b/inc/rest/Rest.php
@@ -4,9 +4,11 @@
 use JVBase\Instance;
 use JVBase\integrations\services\Cloudflare;
 use JVBase\managers\Cache;
+use JVBase\managers\Errors;
 use JVBase\meta\Meta;
 use JVBase\registrar\Registrar;
 use JVBase\base\Site;
+use JVBase\rest\routes\TermRoutes;
 use WP_REST_Request;
 use WP_REST_Response;
 use Exception;
@@ -634,7 +636,7 @@
 		]);
 
 		try {
-			JVB()->error()->log('security_audit', $event, $context, 'info');
+			Errors::getInstance()->log('security_audit', $event, $context, 'info');
 		} catch (Exception $e) {
 			error_log("Security Audit: {$event} - " . json_encode($context));
 		}
@@ -646,7 +648,7 @@
 	protected function logError(string $message, array $context = [], string $severity = 'error'): void
 	{
 		try {
-			JVB()->error()->log(static::class, $message, $context, $severity);
+			Errors::getInstance()->log(static::class, $message, $context, $severity);
 		} catch (Exception $e) {
 			error_log(static::class . " Error: {$message} - " . json_encode($context));
 		}
@@ -898,7 +900,7 @@
 							'name'	=> $term->name,
 							'slug'	=> $term->slug,
 							'parent'	=> $term->parent,
-							'path'	=> JVB()->routes('term')->getTermPath($term->term_id, $term->name, $taxonomy),
+							'path'	=> TermRoutes::getInstance()->getTermPath($term->term_id, $term->name, $taxonomy),
 							'taxonomy'	=> jvbNoBase($term->taxonomy),
 							'count'	=> $term->count,
 						];
diff --git a/inc/rest/RestRouteManager.php b/inc/rest/RestRouteManager.php
index e2efa84..a474aaa 100644
--- a/inc/rest/RestRouteManager.php
+++ b/inc/rest/RestRouteManager.php
@@ -3,6 +3,8 @@
 
 use DateTime;
 use DateTimeZone;
+use JVBase\integrations\services\Cloudflare;
+use JVBase\managers\Errors;
 use JVBase\registrar\Registrar;
 use JVBase\managers\OperationQueue;
 use JVBase\managers\Cache;
@@ -208,7 +210,7 @@
     protected function logError(string $message, array $context = [], string $severity = 'error')
     {
         try {
-            JVB()->error()->log(
+            Errors::getInstance()->log(
                 'artist_invitations', // component
                 $message,
                 $context,
@@ -917,7 +919,7 @@
 
 		// Use existing error handler
 		try {
-			JVB()->error()->log(
+			Errors::getInstance()->log(
 				'security_audit',
 				$event,
 				$context,
@@ -1045,7 +1047,7 @@
 
 	protected function verifyTurnstile(string $token): bool
 	{
-		if (!Site::hasIntegration('cloudflare') || !JVB()->connect('cloudflare')->isSetUp()) {
+		if (!Site::hasIntegration('cloudflare') || !Cloudflare::getInstance()->isSetUp()) {
 			return true;
 		}
 
@@ -1053,6 +1055,6 @@
 			return false;
 		}
 
-		return JVB()->connect('cloudflare')->verifyTurnstile($token);
+		return Cloudflare::getInstance()->verifyTurnstile($token);
 	}
 }
diff --git a/inc/rest/routes/ContentRoutes.php b/inc/rest/routes/ContentRoutes.php
index 7d5ef42..8f5f5de 100644
--- a/inc/rest/routes/ContentRoutes.php
+++ b/inc/rest/routes/ContentRoutes.php
@@ -49,9 +49,7 @@
 		$this->termCache->user();
 
 
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+
 		add_action('init', [$this, 'registerContentExecutors'], 5);
 	}
 
@@ -279,8 +277,8 @@
 			$args['s'] = sanitize_text_field($params['search']);
 		}
 
-		$key = $this->cache->generateKey($args);
-		$cached = $this->cache->get($key);
+
+		$cached = $this->cache->get($args);
 		if ($cached) {
 			return $cached;
 		}
@@ -308,7 +306,7 @@
 		];
 
 
-		$this->cache->set($key, $data);
+		$this->cache->set($args, $data);
 
 		return Response::success($data);
 	}
@@ -343,14 +341,14 @@
 			$args['s'] = sanitize_text_field($params['search']);
 		}
 
-		$key = $this->cache->generateKey($args);
+
 		// Check HTTP cache headers with the specific content type
 //		$cache_check = $this->checkHeaders($request, $key);
 //		if ($cache_check) {
 //			return $cache_check;
 //		}
 
-		$cache = $this->cache->get($key);
+		$cache = $this->cache->get($args);
 		if ($cache) {
 			return Response::success($cache);
 		}
@@ -389,7 +387,7 @@
 		$this->taxonomies = [];
 		$data['items'] =array_map([$this, 'prepareTerm'], $terms);
 
-		$this->cache->set($key, $data);
+		$this->cache->set($args, $data);
 
 		return Response::success($data);
 	}
diff --git a/inc/rest/routes/ContentTermsRoutes.php b/inc/rest/routes/ContentTermsRoutes.php
index 8886996..8f2270a 100644
--- a/inc/rest/routes/ContentTermsRoutes.php
+++ b/inc/rest/routes/ContentTermsRoutes.php
@@ -261,9 +261,8 @@
 		$status = $request->get_param('status');
 		$page = (int)$request->get_param('page');
 
-		$cacheKey = $this->cache->generateKey(compact('termID', 'status', 'page'));
 
-		return $this->cache->remember($cacheKey, function() use ($termID, $status, $page) {
+		return $this->cache->remember(compact('termID', 'status', 'page'), function() use ($termID, $status, $page) {
 			$perPage = 20;
 			$offset = ($page - 1) * $perPage;
 
@@ -272,7 +271,7 @@
 			if ($status === 'active') {
 				$query = $query->where(['end_date' => null]);
 			} elseif ($status === 'inactive') {
-				$query = $query->whereNotNull('end_date');
+				$query = $query->where(['end_date'=> ['NOT NULL', null]]);
 			}
 
 			$total = $query->countResults();
@@ -334,9 +333,7 @@
 		$status = $request->get_param('status');
 		$page = (int)$request->get_param('page');
 
-		$cacheKey = $this->cache->generateKey(compact('termID', 'status', 'page'));
-
-		return $this->cache->remember($cacheKey, function() use ($termID, $status, $page) {
+		return $this->cache->remember(compact('termID', 'status', 'page'), function() use ($termID, $status, $page) {
 			$perPage = 20;
 			$offset = ($page - 1) * $perPage;
 
diff --git a/inc/rest/routes/FeedRoutes.php b/inc/rest/routes/FeedRoutes.php
index 5d43c6a..01c0585 100644
--- a/inc/rest/routes/FeedRoutes.php
+++ b/inc/rest/routes/FeedRoutes.php
@@ -36,9 +36,7 @@
 		parent::__construct();
 		$this->cache = Cache::for('feed');
 
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+
 
 	}
 
diff --git a/inc/rest/routes/Invitations.php b/inc/rest/routes/Invitations.php
index 90f0385..9dbb49f 100644
--- a/inc/rest/routes/Invitations.php
+++ b/inc/rest/routes/Invitations.php
@@ -88,8 +88,8 @@
 		];
 
 		// Check cache
-		$key = $this->cache->generateKey($args);
-		if ($cached = $this->cache->get($key)) {
+
+		if ($cached = $this->cache->get($args)) {
 			return $this->success($cached);
 		}
 
@@ -99,7 +99,7 @@
 			: $this->getUserInvitations($args);
 
 		// Cache result
-		$this->cache->set($key, $result);
+		$this->cache->set($args, $result);
 
 		return $this->success($result);
 	}
@@ -107,7 +107,7 @@
 	/**
 	 * Get invitations for a specific term
 	 */
-	protected function getTermInvitations(array $args): array
+	public function getTermInvitations(array $args): array
 	{
 		// Check permission
 		if (!Roles::getInstance()()->isManager($args['user'], $args['to_term'])) {
diff --git a/inc/rest/routes/LoginRoutes.php b/inc/rest/routes/LoginRoutes.php
index 47fa450..67f209d 100644
--- a/inc/rest/routes/LoginRoutes.php
+++ b/inc/rest/routes/LoginRoutes.php
@@ -159,15 +159,8 @@
 			error_log('[handleLogin]Turnstile succeeded');
 		}
 
-		// Attempt authentication
-		$user = wp_authenticate($email, $password);
-
+		$user = $this->login($email, $password, $remember);
 		if (is_wp_error($user)) {
-			$this->auditLog('login_failed', [
-				'email' => $email,
-				'error' => $user->get_error_code(),
-			]);
-
 			return $this->error(
 				$this->getLoginErrorMessage($user),
 				$user->get_error_code(),
@@ -175,21 +168,6 @@
 			);
 		}
 
-		// Set auth cookie
-		wp_clear_auth_cookie();
-		wp_set_current_user($user->ID);
-		wp_set_auth_cookie($user->ID, $remember);
-
-		// Store session fingerprint
-		$this->storeSessionFingerprint($user->ID, $request);
-
-		do_action('wp_login', $user->user_login, $user);
-
-		$this->auditLog('login_success', [
-			'user_id' => $user->ID,
-			'email' => $email,
-		]);
-
 		// Get redirect URL
 		$redirect = $this->getRedirectUrl($user, $redirect_to);
 
@@ -201,6 +179,40 @@
 		]);
 	}
 
+	public function login(string $email, string $password, bool $remember, ?WP_REST_Request $request = null):WP_User|WP_Error
+	{
+		// Attempt authentication
+		$user = wp_authenticate($email, $password);
+
+		if (is_wp_error($user)) {
+			$this->auditLog('login_failed', [
+				'email' => $email,
+				'error' => $user->get_error_code(),
+			]);
+
+			return $user;
+		}
+
+		// Set auth cookie
+		wp_clear_auth_cookie();
+		wp_set_current_user($user->ID);
+		wp_set_auth_cookie($user->ID, $remember);
+
+		// Store session fingerprint
+		if ($request) {
+			$this->storeSessionFingerprint($user->ID, $request);
+		}
+
+
+		do_action('wp_login', $user->user_login, $user);
+
+		$this->auditLog('login_success', [
+			'user_id' => $user->ID,
+			'email' => $email,
+		]);
+		return $user;
+	}
+
 	/**
 	 * Handle user registration
 	 */
@@ -506,87 +518,6 @@
 		]);
 	}
 
-	/************************************************************
-	 * SESSION FINGERPRINTING
-	 *
-	 * Detects session hijacking by validating that session hasn't
-	 * moved to a different device/network. Uses IP class (not full IP)
-	 * to allow mobile network changes without breaking sessions.
-	 ************************************************************/
-
-	/**
-	 * Store session fingerprint for hijacking detection
-	 */
-	protected function storeSessionFingerprint(int $user_id, WP_REST_Request $request): void
-	{
-		if (!defined('JVB_SESSION_FINGERPRINT') || !JVB_SESSION_FINGERPRINT) {
-			return;
-		}
-
-		$fingerprint = $this->generateSessionFingerprint($request);
-		update_user_meta($user_id, BASE . 'session_fingerprint', $fingerprint);
-		update_user_meta($user_id, BASE . 'session_timestamp', time());
-	}
-
-	/**
-	 * Generate session fingerprint for hijacking detection
-	 */
-	protected function generateSessionFingerprint(WP_REST_Request $request): string
-	{
-		return hash('sha256', implode('|', [
-			$request->get_header('User-Agent') ?? '',
-			// Use IP class instead of full IP to allow for mobile network changes
-			$this->getIPClass(
-				$request->get_header('X-Forwarded-For')
-					?: $request->get_header('X-Real-IP')
-					?: $_SERVER['REMOTE_ADDR'] ?? ''
-			)
-		]));
-	}
-
-	/**
-	 * Get IP class (first 3 octets) for session validation
-	 * Allows for minor IP changes (common with mobile networks)
-	 */
-	protected function getIPClass(string $ip): string
-	{
-		$parts = explode('.', $ip);
-		return implode('.', array_slice($parts, 0, 3));
-	}
-
-	/**
-	 * Validate session fingerprint against stored value
-	 */
-	protected function validateSessionFingerprint(int $user_id, WP_REST_Request $request): bool
-	{
-		// Only enforce if enabled in config
-		if (!defined('JVB_SESSION_FINGERPRINT') || !JVB_SESSION_FINGERPRINT) {
-			return true;
-		}
-
-		$stored = get_user_meta($user_id, BASE . 'session_fingerprint', true);
-		$current = $this->generateSessionFingerprint($request);
-
-		if (empty($stored)) {
-			// First request - store fingerprint
-			update_user_meta($user_id, BASE . 'session_fingerprint', $current);
-			update_user_meta($user_id, BASE . 'session_timestamp', time());
-			return true;
-		}
-
-		// Compare using timing-safe comparison
-		return hash_equals($stored, $current);
-	}
-
-	/**
-	 * Clear session fingerprint (call on logout)
-	 */
-	protected function clearSessionFingerprint(int $user_id): void
-	{
-		delete_user_meta($user_id, BASE . 'session_fingerprint');
-		delete_user_meta($user_id, BASE . 'session_timestamp');
-	}
-
 	/**************************************************************
 	 * HELPERS
 	 **************************************************************/
diff --git a/inc/rest/routes/NewsRoutes.php b/inc/rest/routes/NewsRoutes.php
index 5040862..3c626d8 100644
--- a/inc/rest/routes/NewsRoutes.php
+++ b/inc/rest/routes/NewsRoutes.php
@@ -108,8 +108,8 @@
     public function getNews(WP_REST_Request $request):WP_REST_Response
     {
         $args = $this->buildQueryArgs($request);
-        $key = $this->cache->generateKey($args);
-        $cache = $this->cache->get($key);
+
+        $cache = $this->cache->get($args);
         if ($cache) {
              return $this->success($cache);
         }
@@ -125,7 +125,7 @@
             'total_pages'   => $query->max_num_pages
         ];
 
-        $this->cache->set($key, $results);
+        $this->cache->set($args, $results);
 
         return $this->success($results);
     }
@@ -325,7 +325,7 @@
         $artist = jvbContentFromUser($post->post_author);
         $upvotes = (int) get_post_meta($post->ID, BASE.'upvotes', true);
         $downvotes = (int) get_post_meta($post->ID, BASE.'downvotes', true);
-        $comments = JVB()->routes('comments')->getItemResponse($post->ID, BASE.'news');
+        $comments = ResponseRoutes::getInstance()->getItemResponse($post->ID, ['post_type' => BASE.'news']);
 
         return [
             'id'            => $post->ID,
diff --git a/inc/rest/routes/QueueRoutes.php b/inc/rest/routes/QueueRoutes.php
index 3540edc..f9a8142 100644
--- a/inc/rest/routes/QueueRoutes.php
+++ b/inc/rest/routes/QueueRoutes.php
@@ -25,9 +25,7 @@
 		parent::__construct();
 		$this->cache = Cache::for($this->cacheName, 'custom', $this->cacheTtl)->user();
 
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+
 	}
 
 	/**
diff --git a/inc/rest/routes/ResponseRoutes.php b/inc/rest/routes/ResponseRoutes.php
index 0e8589d..967e9c6 100644
--- a/inc/rest/routes/ResponseRoutes.php
+++ b/inc/rest/routes/ResponseRoutes.php
@@ -119,7 +119,7 @@
 	/**
 	 * Get responses with karma calculations
 	 */
-	protected function getItemResponse(int $item_id, array $args = []): array|WP_Error
+	public function getItemResponse(int $item_id, array $args = []): array|WP_Error
 	{
 		$responses = Responses::getInstance()->getAllItemResponses($item_id, $args);
 		// Format responses
diff --git a/inc/rest/routes/ShopRoutes.php b/inc/rest/routes/ShopRoutes.php
index 26b9dfa..5c9b3ac 100644
--- a/inc/rest/routes/ShopRoutes.php
+++ b/inc/rest/routes/ShopRoutes.php
@@ -3,6 +3,7 @@
 
 use JVBase\JVB;
 use JVBase\managers\Emails;
+use JVBase\managers\Errors;
 use JVBase\managers\ImageGenerator;
 use JVBase\managers\UploadManager;
 use JVBase\registrar\Registrar;
@@ -164,7 +165,7 @@
 
 		foreach ($setData as $name => $value) {
 			if ($name === 'shop') {
-				JVB()->routes('shop')->requestShopAdmission($operation->user_id, $value);
+				$this->requestShopAdmission($operation->user_id, $value);
 				$setData['requested_shop'] = $value;
 				unset($setData['shop']);
 			}
@@ -1007,7 +1008,7 @@
             return true;
         } catch (Exception $e) {
             $wpdb->query('ROLLBACK');
-            JVB()->error()->log(
+            Errors::getInstance()->log(
                 'shop',
                 "Error accepting artist invitation: " . $e->getMessage(),
                 [
@@ -1075,7 +1076,7 @@
 
             return true;
         } catch (Exception $e) {
-            JVB()->error()->log(
+            Errors::getInstance()->log(
                 'shop',
                 "Error declining artist invitation: " . $e->getMessage(),
                 [
@@ -1157,7 +1158,7 @@
             return true;
         } catch (Exception $e) {
             $wpdb->query('ROLLBACK');
-            JVB()->error()->logError("Error adding artist to shop: " . $e->getMessage(), [
+            Errors::getInstance()->logError("Error adding artist to shop: " . $e->getMessage(), [
                 'user_id' => $user_id,
                 'shop_id' => $shop_id
             ]);
@@ -1241,7 +1242,7 @@
             return true;
         } catch (Exception $e) {
             $wpdb->query('ROLLBACK');
-            JVB()->error()->log(
+            Errors::getInstance()->log(
                 'shop',
                 "Error removing artist from shop: " . $e->getMessage(),
                 [
diff --git a/inc/rest/routes/TermRoutes.php b/inc/rest/routes/TermRoutes.php
index 8178cad..38772cb 100644
--- a/inc/rest/routes/TermRoutes.php
+++ b/inc/rest/routes/TermRoutes.php
@@ -3,6 +3,7 @@
 
 use JVBase\Instance;
 use JVBase\managers\Cache;
+use JVBase\managers\Errors;
 use JVBase\managers\TaxonomyRelationships;
 use JVBase\registrar\Registrar;
 use JVBase\rest\Rest;
@@ -27,9 +28,7 @@
         $this->cacheName = 'terms';
         parent::__construct();
 		$this->cache = Cache::for('terms', 'term');
-		if (JVB_TESTING) {
-			$this->cache->flush();
-		}
+
 
         $this->per_page = 20;
 
@@ -559,7 +558,7 @@
 
 			$membership = Site::membership();
 			if ($membership && $membership->has('term_approval')) {
-				$approval_routes = JVB()->routes('approvals');
+				$approval_routes = ApprovalRoutes::getInstance();
 				$request_id = $approval_routes->createTermApprovalRequest(
 					$user_id,
 					$taxonomy,
@@ -602,7 +601,7 @@
 			], 201); // 201 Created
 
 		} catch (Exception $e) {
-			JVB()->error()->log(
+			Errors::getInstance()->log(
 				'terms',
 				'Term creation failed: ' . $e->getMessage(),
 				['user_id' => $user_id, 'taxonomy' => $taxonomy, 'name' => $name]
diff --git a/inc/rest/routes/UploadRoutes.php b/inc/rest/routes/UploadRoutes.php
index 0187f75..23d2fd0 100644
--- a/inc/rest/routes/UploadRoutes.php
+++ b/inc/rest/routes/UploadRoutes.php
@@ -708,7 +708,7 @@
 
 			return $this->queued($ID['operation_id'], 'Files uploaded and posts queued for creation');
 		} catch (Exception $e) {
-			JVB()->error()->log(
+			Errors::getInstance()->log(
 				'[UploadRoutes]:handleGroupingRequest',
 				$e->getMessage(),
 				[
diff --git a/inc/utility/Image.php b/inc/utility/Image.php
index 384a699..23e2844 100644
--- a/inc/utility/Image.php
+++ b/inc/utility/Image.php
@@ -17,18 +17,14 @@
 
 	public function __construct()
 	{
-		$this->cache = Cache::for('images')->connect('post');
-		$this->imgData = Cache::for('imageData')->connect('post');
-		if (JVB_TESTING) {
-			$this->cache->flush();
-			$this->imgData->flush();
-		}
+		$this->cache = Cache::for('images', 'post');
+		$this->imgData = Cache::for('imageData', 'post');
 	}
 
 	public function formatImage(int $ID, string $start = 'tiny', string $replace = 'large', bool $addLink = true, ?string $postSlug = null):string
 	{
 		$return = $this->cache->remember(
-			$this->cache->generateKey(['ID' => $ID, 'start' => $start, 'replace' => $replace]),
+			['ID' => $ID, 'start' => $start, 'replace' => $replace],
 			function() use ($ID, $start, $replace) {
 				// Define size order for progressive enhancement
 				$sizeOrder = ['tiny', 'directory-preview', 'thumbnail', 'medium', 'large', 'full'];
@@ -188,9 +184,7 @@
 	public static function SVG(string $slug):string
 	{
 		$cache = Cache::for('svgs');
-		if (JVB_TESTING) {
-			$cache->flush();
-		}
+
 		return $cache->remember(
 			$slug,
 			function() use ($slug) {
diff --git a/inc/utility/Video.php b/inc/utility/Video.php
index f71c050..0feffeb 100644
--- a/inc/utility/Video.php
+++ b/inc/utility/Video.php
@@ -15,12 +15,8 @@
 
 	public function __construct()
 	{
-		$this->cache = Cache::for('videos')->connect('post');
-		$this->vidData = Cache::for('vidData')->connect('post');
-		if (JVB_TESTING) {
-			$this->cache->flush();
-			$this->vidData->flush();
-		}
+		$this->cache = Cache::for('videos', 'post');
+		$this->vidData = Cache::for('vidData', 'post');
 	}
 	public static function get(int $ID, array $args = []):string
 	{
@@ -29,7 +25,7 @@
 	public function formatVideo(int $ID, array $args = []):string
 	{
 		return $this->cache->remember(
-			$this->cache->generateKey(array_merge(['id' => $ID], $args)),
+			array_merge(['id' => $ID], $args),
 			function() use ($ID, $args) {
 				$url = wp_get_attachment_url($ID);
 				$meta = wp_get_attachment_metadata($ID);
diff --git a/jvb.php b/jvb.php
index 6494ea5..d7df5f8 100644
--- a/jvb.php
+++ b/jvb.php
@@ -121,11 +121,7 @@
 	add_filter('show_admin_bar', '__return_false');
 //}
 
-//if (JVB_TESTING) {
-//	error_log('In testing mode...');
-//} else {
-//	error_log('Not in testing mode...');
-//}
+
 
 const JVB_DIR = WP_PLUGIN_DIR . '/jvb';
 define('JVB_URL', plugin_dir_url(__FILE__));
@@ -514,15 +510,15 @@
 {
     echo '<div class="screen-reader-text live-region" aria-live="polite" role="status"></div>';
 }
+/*
+add_action('wp_head', 'jvbFrontendBase',1);
+function jvbFrontendBase():void
+{
 
-//add_action('wp_head', 'jvbFrontendBase',1);
-//function jvbFrontendBase():void
-//{
-//	?>
-<!--	<script type="text/javascript">window.jvbBase = '--><?php //= BASE ?>//';</script>
-//	<?php
-//}
-
+	<script type="text/javascript">window.jvbBase = '<?= BASE ?>';</script>
+	<?php
+}
+*/
 
 
 add_action('after_setup_theme', 'jvbImageSize');
@@ -549,23 +545,6 @@
 //	return $result;
 //}, 10, 3);
 
-add_filter('rest_authentication_errors', function($result) {
-
-	// Don't override existing authentication
-	if (is_wp_error($result) || $result === true) {
-		return $result;
-	}
-
-	// Try to authenticate from cookie
-	$cookie_user = wp_validate_auth_cookie('', 'logged_in');
-
-	if ($cookie_user) {
-		wp_set_current_user($cookie_user);
-		return true;
-	}
-	return $result;
-}, 99);
-
 
 add_action('wp_footer', 'jvb_back_to_top');
 function jvb_back_to_top():void
diff --git a/src/forms/render.php b/src/forms/render.php
index 9865bf3..14a5bb2 100644
--- a/src/forms/render.php
+++ b/src/forms/render.php
@@ -1,55 +1,7 @@
 <?php
+
+use JVBase\meta\Form;
+
 if (!defined('ABSPATH')) {
     exit; // Exit if accessed directly
 }
-/**
- * Form Block Render
- *
- * @package Edmonton_Ink
- */
-
-/**
- * Renders the form block on the frontend
- *
- * @param array    $attributes The block attributes.
- * @param string   $content    The block content.
- * @param WP_Block $block      The block instance.
- * @return string The rendered output.
- */
-function jvbRenderFormBlock(array $attributes, string $content, WP_Block $block):string
-{
-    // Get form type from attributes
-    $form_type = isset($attributes['formType']) ? $attributes['formType'] : '';
-
-    // If no form type selected, return a message
-    if (empty($form_type)) {
-        return '<div class="jvb-form-error">No form type selected. Please edit this block and select a form type.</div>';
-    }
-
-    // Get other attributes
-    $show_labels = isset($attributes['showLabels']) ? $attributes['showLabels'] : true;
-    $custom_email_to = isset($attributes['customEmailTo']) ? $attributes['customEmailTo'] : '';
-
-    // Set custom options for the form
-    $form_options = array();
-
-    // Set custom email recipient if provided
-    if (!empty($custom_email_to)) {
-        $form_options['email_to'] = $custom_email_to;
-    }
-
-    // Render the form with the specified options
-    $form_output = JVB()->forms()->renderForm($form_type);
-
-    // Get block classes
-    $wrapper_attributes = get_block_wrapper_attributes([
-        'class' => 'jvb-forms'
-    ]);
-
-    // Return the wrapped form
-    return sprintf(
-        '<div %1$s>%2$s</div>',
-        $wrapper_attributes,
-        $form_output
-    );
-}
diff --git a/templates/dashboard/sections/favourites.php b/templates/dashboard/sections/favourites.php
index 78f756a..238d78e 100644
--- a/templates/dashboard/sections/favourites.php
+++ b/templates/dashboard/sections/favourites.php
@@ -1,4 +1,7 @@
 <?php
+
+use JVBase\managers\Favourites;
+
 if (!defined('ABSPATH')) {
     exit; // Exit if accessed directly
 }
@@ -8,10 +11,11 @@
 }
 
 $user_id = get_current_user_id();
-$JVB = JVB();
-$favourites = $JVB->routes('favourites');
-$counts =$favourites->getFavouriteCounts($user_id, false);
-$lists =get_user_meta($user_id, BASE.'favourite_lists', true)?:[];
+
+$favourites = Favourites::getInstance();
+$counts =$favourites->getFavouriteCounts($user_id);
+$lists = $favourites->getLists(['user_id' => $user_id]);
+
 
 global $types;
 global $feed_types;

--
Gitblit v1.10.0