From c19264ac916707096fe294d996a1b7fb85206b34 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 08 Mar 2026 19:55:31 +0000
Subject: [PATCH] =Furthering along the complete refactor. Added some basic setup for is_content taxonomies, including a page for an archive of the terms.

---
 inc/registrar/config/seo/Schema.php |  207 ++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 171 insertions(+), 36 deletions(-)

diff --git a/inc/registrar/config/seo/Schema.php b/inc/registrar/config/seo/Schema.php
index 91f03cb..b48b8de 100644
--- a/inc/registrar/config/seo/Schema.php
+++ b/inc/registrar/config/seo/Schema.php
@@ -34,7 +34,10 @@
 		'description' => '{{post_excerpt}}',
 	];
 
-	protected array $defaultArchive = [];
+	protected array $defaultArchive = [
+		'type'	=> 'JVBase\managers\SEO\render\Thing\CreativeWork\WebPage\CollectionPage',
+		'title' => '{{registrar.plural}}'
+	];
 
 	public function __construct(string $slug, string $type)
 	{
@@ -52,6 +55,16 @@
 			$this->cache->connect($registrar->getType());
 			$this->referenceCache->connect($registrar->getType());
 			$this->archiveCache->connect($registrar->getType());
+
+			switch ($registrar->getType()) {
+				case 'term':
+					$this->defaultSchema['type'] = 'JVBase\managers\SEO\render\Thing\CreativeWork\WebPage\CollectionPage';
+					break;
+				case 'user':
+					$this->defaultSchema['type'] = 'JVBase\managers\SEO\render\Thing\CreativeWork\WebPage\ProfilePage';
+					break;
+			}
+			$this->defaultArchive['description'] = '{{registrar.'.$slug.'.description}}';
 		}
 		$this->initFilters();
 		$this->registerHooks();
@@ -75,6 +88,8 @@
 	{
 		add_action('wp_head', [$this, 'outputSchema'], 1);
 		add_filter('the_seo_framework_schema_graph_data', [$this, 'filterTSFSchema'], 10, 2);
+		add_filter('the_seo_framework_title_from_custom_field', [$this, 'filterTSFOGTitle'], 10, 2);
+
 		$this->maybeExcludeSingles();
 	}
 		protected function maybeExcludeSingles(): void
@@ -119,67 +134,120 @@
 		}
 	public function filterTSFSchema(array $graph, ?array $args):array
 	{
-		if (jvbTSFDoIt($this->slug, $args)){
+		$based = jvbCheckBase($this->slug);
+		if (is_front_page() || is_singular($based) || is_post_type_archive($based) || is_tax($based)) {
 			return [];
 		}
+
+//		if (jvbTSFDoIt($this->slug, $args)){
+//			return [];
+//		}
 		return $graph;
 	}
 
 	public function outputSchema():void
 	{
+		$registrar = Registrar::getInstance($this->slug);
 		if (is_singular()) {
 			$this->outputSingularSchema();
 		} elseif (is_post_type_archive(jvbCheckBase($this->slug) || is_tax(jvbCheckBase($this->slug)))) {
 			$this->outputArchiveSchema();
+		} if ($registrar && $registrar->hasFeature('is_content') && is_single(get_option(BASE.$this->slug.'_archive'))) {
+			$this->outputContentTaxArchiveSchema();
 		}
 	}
 		public function outputSingularSchema():array
 		{
 			$ID = get_the_ID();
-			$this->cache->flush();
+			if (JVB_TESTING){
+				$this->cache->flush();
+			}
+
 			return $this->cache->remember(
 				$ID,
 				function () use ($ID) {
 					$meta = Meta::forPost($ID);
 					$config = $this->getConfig();
 
-					$class = new $config['type']();
-					unset($config['type']);
-					foreach ($config as $property => $value){
-						$value = Resolver::resolveForSchema($property, $value, $config, $meta);
-						$method = 'set'.ucfirst($property);
-						$class->$method($value);
-					}
+					$class = $this->classFromConfig($config, $meta);
 
 					$class->setAuthor(JVB()->seo()->getCreator(true));
-					$schema = $class->outputSchema();
-					error_log('Generated archive schema: '.print_r($schema, true));
-					return $schema;
+					return $class->outputSchema();
 				}
 			);
 
 		}
 
+		public function outputContentTaxArchiveSchema():array
+		{
+			$ID = get_the_ID();
+			if (JVB_TESTING) {
+				$this->cache->flush();
+			}
+			return $this->cache->remember(
+				$ID,
+				function() use ($ID) {
+					$action = BASE.ucfirst($this->slug).'Schema';
+					$config = get_option($action, apply_filters($action, $this->defaultSchema));
+					if (!array_key_exists('type', $config)) {
+						$config['type'] = 'JVBase\managers\SEO\render\Thing\CreativeWork\WebPage\CollectionPage';
+					}
+					if (!class_exists($config['type'])) {
+						error_log('No class found for archive schema output: '.$config['type']);
+						return [];
+					}
+					$class = $this->classFromConfig($config);
+
+					$class->setIsPartOf(get_home_url().'/#website');
+					$itemList = new render\Thing\Intangible\ItemList\ItemList();
+					$items = get_terms([
+						'taxonomy'	=> jvbCheckBase($this->slug),
+//						'hide_empty' => true,
+						'fields'	=> 'ids',
+					]);
+
+					$pos = 1;
+					$itemListItems = [];
+					foreach ($items as $ID) {
+						$item = $this->outputReferenceSchema($ID, 'term',false);
+						$listItem = new render\Thing\Intangible\ListItem();
+						$listItem->setPosition($pos);
+						$listItem->setItem($item);
+						$itemListItems[] = $listItem;
+						$pos++;
+					}
+					wp_reset_postdata();
+					$itemList->setItemListElement($itemListItems);
+					$class->setMainEntity($itemList);
+
+					return $class->outputSchema();
+				}
+			);
+		}
+
 		public function outputArchiveSchema():array
 		{
-			$this->archiveCache->flush();
+			if (JVB_TESTING){
+				$this->archiveCache->flush();
+			}
+
 			return $this->archiveCache->remember(
 				$this->slug,
 				function() {
 					$action = BASE.ucfirst($this->slug).'Archive';
 					$config = get_option($action, apply_filters($action, $this->defaultArchive));
-
+					if (!array_key_exists('type', $config)) {
+						$config['type'] = 'JVBase\managers\SEO\render\Thing\CreativeWork\WebPage\CollectionPage';
+					}
 					if (!class_exists($config['type'])) {
 						error_log('No class found for archive schema output: '.$config['type']);
 						return [];
 					}
+					$obj = get_queried_object();
+					$meta = (property_exists($obj, 'taxonomy')) ? Meta::forTerm($obj->term_id) : null;
 
-					$class = new $config['type'];
-					unset($config['type']);
-					foreach ($config as $property=>$value) {
-						$method = 'set'.ucfirst($property);
-						$class->$method($value);
-					}
+					$class = $this->classFromConfig($config, $meta);
+
 					$class->setIsPartOf(get_home_url().'/#website');
 					$itemList = new render\Thing\Intangible\ItemList\ItemList();
 					$items = new WP_Query([
@@ -191,7 +259,7 @@
 					$pos = 1;
 					$itemListItems = [];
 					foreach ($items->posts as $ID) {
-						$item = $this->outputReferenceSchema($ID, false);
+						$item = $this->outputReferenceSchema($ID, 'post',false);
 						$listItem = new render\Thing\Intangible\ListItem();
 						$listItem->setPosition($pos);
 						$listItem->setItem($item);
@@ -209,24 +277,43 @@
 			);
 		}
 
-	public function outputReferenceSchema(int $ID, bool $outputSchema = true):mixed
+	public function outputReferenceSchema(int $ID, string $type, bool $outputSchema = true):mixed
 	{
-		$this->referenceCache->flush();
+		if (JVB_TESTING){
+			$this->referenceCache->flush();
+		}
+
 		$cached = $this->referenceCache->remember(
 			$ID,
-			function () use ($ID) {
-				$meta = Meta::forPost($ID);
-				$config = $this->getConfig();
-				$class = new $config['type']();
-				$class->setId(get_the_permalink($ID).'/#'.$class->getTypeName());
-				foreach ($this->referenceProperties as $property => $value){
-					$value = Resolver::resolveForSchema($property, $value, $this->schema, $meta);
-					$method = 'set'.ucfirst($property);
-					$class->$method($value);
+			function () use ($ID, $type) {
+				switch ($type) {
+					case 'post':
+						$meta = Meta::forPost($ID);
+						break;
+					case 'term':
+						$meta = Meta::forTerm($ID);
+						break;
+					case 'user':
+						$meta = Meta::forUser($ID);
+						break;
+					default:
+						error_log('Invalid type used for reference: '.print_r($type, true));
+						$meta = null;
+				}
+				$config = $this->getConfig('archive');
+				$class = $this->classFromConfig($config, $meta);
+				$class->delete('about');
+
+				switch ($type) {
+					case 'post':
+						$class->setId(get_the_permalink($ID).'#'.$class->getTypeName());
+						break;
+					case 'term':
+						$class->setId(get_term_link($ID).'#'.$class->getTypeName());
+						break;
 				}
 
-				$schema = $class->outputSchema();
-				error_log('Generated archive schema: '.print_r($schema, true));
+
 				return $class;
 			}
 		);
@@ -264,7 +351,12 @@
 	}
 	public function defineReference(string $property, string $value):void
 	{
-		$class = $this->getConfig('schema')['type'];
+		$config = $this->getConfig();
+		if (!array_key_exists('type', $config)) {
+			$config['type'] = $this->defaultSchema['type'];
+			update_option(BASE.ucfirst($this->slug).'Schema', $config);
+		}
+		$class = $this->getConfig()['type'];
 		if (!class_exists($class)) {
 			error_log('[SEO]Schema::defineReference Class not found: '.$class);
 			return;
@@ -294,4 +386,47 @@
 			$this->defineReference($property, $value);
 		}
 	}
+
+	public function filterTSFOGTitle(string $title, ?array $args):string{
+		$based = jvbCheckBase($this->slug);
+
+		if (is_singular($based)){
+			$config = $this->getConfig('meta');
+			$meta = Meta::forPost(get_the_ID());
+			$title = Resolver::resolve($config['name'], $meta);
+		} elseif (is_post_type_archive($based) || is_tax($based)) {
+			$config = $this->getConfig('archive');
+			$title = $config['name'];
+		}
+		return $title;
+	}
+
+	protected function classFromConfig(array $config, ?Meta $meta = null):mixed
+	{
+		if (!array_key_exists('type', $config)) {
+			error_log('[Schema]::classFromConfig No class defined in config: '.print_r($config, true));
+			return false;
+		}
+		$className = $config['type'];
+		unset($config['type']);
+		$class = new $className();
+
+		foreach ($config as $property=>$value) {
+			if (is_array ($value)) {
+				$value = $this->classFromConfig($value, $meta);
+			}
+			$method = 'set'.ucfirst($property);
+			if (!method_exists($class, $method)) {
+				error_log('[Schema]::classFromConfig - method: '.$method.' does not exist in class: '.$className);
+				continue;
+			}
+			if (is_string($value) && str_contains($value, '{{')) {
+				$value = Resolver::resolveForSchema($property, $value, $config, $meta);
+			}
+			if (!empty($value)) {
+				$class->$method($value);
+			}
+		}
+		return $class;
+	}
 }

--
Gitblit v1.10.0