From 32ce5c542c90be348895328078e392dde2052957 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Fri, 04 Sep 2026 19:15:16 +0000
Subject: [PATCH] =Working at adding defined fields to a dedicated panel in the gutenberg editor. Registrar now has AddCustomFields.php, which currently only supports post fields. Added a @wordpress/plugins base _meta/fields in /build and /src that successfully creates a panel. Next steps: determine sections and fields, group fields by section (each section to a panel), and save output

---
 inc/managers/SEO/render/SchemaOutput.php |  179 +++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 155 insertions(+), 24 deletions(-)

diff --git a/inc/managers/SEO/render/SchemaOutput.php b/inc/managers/SEO/render/SchemaOutput.php
index 4619d94..87c2e7c 100644
--- a/inc/managers/SEO/render/SchemaOutput.php
+++ b/inc/managers/SEO/render/SchemaOutput.php
@@ -1,17 +1,30 @@
 <?php
 namespace JVBase\managers\SEO\render;
 
+use JVBase\base\SchemaHelper;
 use JVBase\inc\managers\SEO\render\Thing\Intangible\ItemList\OfferCatalog;
+use JVBase\Instance;
 use JVBase\managers\Cache;
 use JVBase\managers\SEO\BreadcrumbManager;
+use JVBase\managers\SEO\render\Thing\CreativeWork\Menu;
+use JVBase\managers\SEO\render\Thing\CreativeWork\MenuSection;
+use JVBase\managers\SEO\render\Thing\Intangible\MenuItem;
+use JVBase\managers\SEO\render\Thing\Intangible\Offer;
 use JVBase\managers\SEO\render\Thing\Intangible\Service;
 use JVBase\managers\SEO\render\Thing\Organization\LocalBusiness\LocalBusiness;
+use JVBase\managers\SEO\render\Thing\Thing;
+use JVBase\meta\Meta;
 use JVBase\registrar\config\seo\Resolver;
 use JVBase\registrar\Registrar;
+use WP_Query;
 
+if (!defined('ABSPATH')) {
+	exit;
+}
 class SchemaOutput {
+	use Instance;
 	protected array $types;
-	public function __construct() {
+	protected function __construct() {
 		add_action('wp_head', [$this, 'outputSchema'], 0);
 		$this->init();
 	}
@@ -23,23 +36,28 @@
 	{
 		$schema = [];
 
-
+		$registrar = false;
 		if (is_front_page()) {
-			$schema[] = $this->buildWebsiteSchema(true);
+			$schema[] = $this->buildWebsiteSchema();
 			$test = $this->buildOrganizationSchema();
 			if (!empty($test)) {
 				$schema[] = $test;
 			}
 		}
+
 		if (is_singular($this->types)) {
 			$type = get_post_type();
 			$registrar = Registrar::getInstance($type);
-			if ($registrar) {
+
+			$function = BASE.'build_singular_'.jvbNoBase($type).'_schema';
+			if (function_exists($function)) {
+				$schema = $function(get_the_ID());
+			} else if ($registrar) {
 				$seo = $registrar->getSEO();
 				$schema[] = $seo->schema()->outputSingularSchema();
 			}
 		}elseif (is_post_type_archive($this->types)) {
-			error_log('It is a post type archive');
+
 			$type = get_queried_object();
 			$type = $type->name;
 			$registrar = Registrar::getInstance($type);
@@ -54,17 +72,19 @@
 			$registrar = Registrar::getInstance($type);
 			if ($registrar ) {
 				$seo = $registrar->getSEO();
-				error_log('SEO: '.print_r($seo->schema(), true));
+//				error_log('SEO: '.print_r($seo->schema(), true));
 				$schema[] = $seo->schema()->outputArchiveSchema();
 			}
+		} elseif (is_post_type_archive('product')) {
+			$schema[] = $this->buildProductSchema();
 		}
 		$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 (is_page($isContent)){
+		if (!empty($isContent) && is_page($isContent)){
 			$type = get_post_meta(get_the_id(), BASE.'for_type', true);
-			error_log('Type: '.print_r($type, true));
+//			error_log('Type: '.print_r($type, true));
 			if (!empty($type)) {
 				$registrar = Registrar::getInstance($type);
 				if ($registrar) {
@@ -74,6 +94,10 @@
 
 		}
 
+		if ($registrar && !empty($registrar->getSEO()->schema()->extra())) {
+			$schema = array_merge($schema, $registrar->getSEO()->schema()->extra());
+		}
+
 
 
 		$breadcrumbs = $this->buildBreadcrumbs();
@@ -83,11 +107,9 @@
 
 		if (!empty($schema)) {
 			if (!is_front_page()) {
-				$website = JVB()->schemaHelper()::schema('website');
+				$website = SchemaHelper::getInstance()::schema('website');
 				if (!empty($website)) {
-					if (JVB_TESTING) {
-						Cache::for('websiteSchema')->flush();
-					}
+
 					$website = Cache::for('websiteSchema')->remember(
 						'schema',
 						function () {
@@ -103,13 +125,14 @@
 				'@graph'		=> $schema
 			];
 		}
+
 		return $schema;
 	}
 
 	protected function websiteSchema():array
 	{
-		$stored = JVB()->schemaHelper()::schema('website');
-		$website = JVB()->schemaHelper()::classFromConfig($stored);
+		$stored = SchemaHelper::getInstance()::schema('website');
+		$website = SchemaHelper::getInstance()::classFromConfig($stored);
 
 		if (!$website->getUrl() || empty($website->getUrl())){
 			$website->setUrl(get_home_url());
@@ -132,7 +155,7 @@
 		}
 //		$encoded =  wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
 //		$encoded =  wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT, 1024);
-		$encoded = wp_json_encode($schema, JSON_UNESCAPED_SLASHES, 512);
+		$encoded = wp_json_encode($schema, JSON_UNESCAPED_SLASHES, 2048);
 		if ($encoded === false) {
 			error_log('wp_json_encode failed: ' . json_last_error_msg());
 			return;
@@ -155,7 +178,7 @@
 		if (JVB_TESTING){
 			Cache::for('websiteSchema')->flush();
 		}
-		$storedWebsite = JVB()->schemaHelper()::schema('website');
+		$storedWebsite = SchemaHelper::getInstance()::schema('website');
 
 		if (!$full) {
 			return Cache::for('websiteSchema')->remember(
@@ -166,7 +189,7 @@
 						return in_array($key, $allowed);
 					}, ARRAY_FILTER_USE_KEY);
 
-					$website = JVB()->schemaHelper()::classFromConfig($storedWebsite);
+					$website = SchemaHelper::getInstance()::classFromConfig($storedWebsite);
 					if (!$website->getName() || empty($website->getName())) {
 						$website->setName(get_bloginfo('name'));
 					}
@@ -198,7 +221,7 @@
 		return Cache::for('websiteSchema')->remember(
 			'full',
 			function () use ($storedWebsite) {
-				$website = JVB()->schemaHelper()::classFromConfig($storedWebsite);
+				$website = SchemaHelper::getInstance()::classFromConfig($storedWebsite);
 				if (!$website->getName() || empty($website->getName())) {
 					$website->setName(get_bloginfo('name'));
 				}
@@ -298,9 +321,9 @@
 		if ($reference) {
 			return $this->getOptionSchemaReference('organization');
 		}
-		$config = JVB()->schemaHelper()::schema('organization');
+		$config = SchemaHelper::getInstance()::schema('organization');
 
-		return JVB()->schemaHelper()::classFromConfig($config);
+		return SchemaHelper::getInstance()::classFromConfig($config);
 	}
 
 	public function getOptionSchemaReference(string $option):mixed
@@ -314,7 +337,7 @@
 			return null;
 		}
 
-		$stored = JVB()->schemaHelper()::reference($option);
+		$stored = SchemaHelper::getInstance()::reference($option);
 
 		if (empty($stored)){
 			error_log('Attempted to get schema reference for: '.$option.', but defaults not set.');
@@ -345,10 +368,118 @@
 
 	public function buildOrganizationSchema():array
 	{
-		$config = JVB()->schemaHelper()::schema('organization');
+		$config = SchemaHelper::getInstance()::schema('organization');
 
-		$class = JVB()->schemaHelper()::classFromConfig($config);
+		$class = SchemaHelper::getInstance()::classFromConfig($config);
 		return ($class)? $class->outputSchema() : [];
 	}
+
+	public function buildProductSchema():array
+	{
+		$sections = aneb_menu_sections();
+		if (empty($sections)) {
+			$sections = [];
+		}
+
+		$menuSections = [];
+
+		foreach ($sections as $s) {
+			if (empty($s['id'])) {
+				continue;
+			}
+			$items = new WP_Query([
+				'post_type'         => 'product',
+				'order'             => 'ASC',
+				'posts_per_page'    => -1,
+				'post_status'       => 'publish',
+				'tax_query'         => [
+					[
+						'taxonomy'  => 'product_cat',
+						'terms'     => (int)$s['id']
+					]
+				],
+				'fields'            => 'ids',
+			]);
+			if (!$items->have_posts())  {
+				continue;
+			}
+
+			$section = new MenuSection();
+
+			$section->setName($s['name']);
+			$section->setId(get_post_type_archive_link('product').'#'.sanitize_title($s['name']));
+			if (!empty($s['description'])) {
+				$section->setDescription($s['description']);
+			}
+
+			$menuItems = [];
+			foreach ($items->posts as $ID) {
+				$meta = Meta::forPost($ID);
+				$fields = $meta->getAll();
+				if (empty($fields['variations'])) {
+					$item = $this->buildMenuItem($ID, $fields);
+					if ($item) {
+						$menuItems[] = $item;
+					}
+				} else {
+					foreach ($fields['variations'] as $variation) {
+						$item = $this->buildMenuItem($ID, $variation);
+						if ($item) {
+							$menuItems[] = $item;
+						}
+					}
+				}
+			}
+
+			if (!empty($menuItems)) {
+				$section->setHasMenuItem($menuItems);
+				$menuSections[] = $section;
+			}
+
+
+		}
+
+		if (!empty($menuSections)) {
+			$schema = new Menu();
+			$schema->setName(get_bloginfo('name') . ' | Alberta\'s Best Food Truck Menu');
+			$schema->setId(get_post_type_archive_link('product').'#menu');
+			$schema->setDescription('Southern style barbeque with Northern flair from Meeting Creek, Alberta');
+			$schema->setUrl(get_post_type_archive_link('product'));
+
+			$schema->setHasMenuSection($menuSections);
+
+			return $schema->outputSchema();
+		}
+
+		return [];
+	}
+
+		protected function buildMenuItem(int $ID, array $fields):MenuItem|false
+		{
+			$item = new MenuItem();
+			$item->setUrl(get_the_permalink($ID));
+			$base = get_post_type_archive_link('product').'#'.$ID.'-'.sanitize_title($fields['post_title']);
+			$item->setId($base);
+			$doit = false;
+			if (!empty($fields['post_thumbnail']??'')) {
+				$doit = true;
+				$item->setImage(Thing::createImageFromID($fields['post_thumbnail']));
+			}
+
+			if (!empty($fields['post_excerpt']??'')) {
+				$doit = true;
+				$item->setDescription(wp_strip_all_tags($fields['post_excerpt']));
+			}
+
+			if (!empty($fields['price']??'')) {
+				$doit = true;
+				$offer = new Offer();
+				$offer->setId($base.'-price');
+				$offer->setPrice($fields['price']);
+				$offer->setPriceCurrency('CAD');
+				$item->setOffers($offer);
+			}
+			return $doit ? $item : false;
+		}
 }
 

--
Gitblit v1.10.0