From 9bbeea742424837fb58207d88e10dbca0b2cae04 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 03 May 2026 22:04:17 +0000
Subject: [PATCH] =SEO Field registration and formatting

---
 inc/managers/SEO/render/Traits/_Properties/offersTrait.php |  171 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 150 insertions(+), 21 deletions(-)

diff --git a/inc/managers/SEO/render/Traits/_Properties/offersTrait.php b/inc/managers/SEO/render/Traits/_Properties/offersTrait.php
index c1dda00..a97162e 100644
--- a/inc/managers/SEO/render/Traits/_Properties/offersTrait.php
+++ b/inc/managers/SEO/render/Traits/_Properties/offersTrait.php
@@ -1,9 +1,17 @@
 <?php
 namespace JVBase\managers\SEO\render\Traits\_Properties;
 
+use JVBase\inc\managers\SEO\render\Thing\Intangible\ItemList\OfferCatalog;
 use JVBase\managers\SEO\render\Thing\Intangible\Demand;
 use JVBase\managers\SEO\render\Thing\Intangible\Offer;
+use JVBase\managers\SEO\render\Thing\Intangible\Service;
+use JVBase\managers\SEO\render\Thing\Intangible\StructuredValue\PriceSpecification;
+use JVBase\managers\SEO\render\Thing\Product\Product;
 use JVBase\managers\SEO\render\Traits\_Helpers\arrayHelper;
+use JVBase\meta\Meta;
+use JVBase\registrar\Fields;
+use JVBase\registrar\Registrar;
+use WP_Query;
 
 if (!defined('ABSPATH')) {
 	exit;
@@ -30,34 +38,155 @@
 		}
 		$this->offers = $offers;
 	}
-	public function getOpeningHoursFieldConfig():array
+	public function setOffersField(Fields $fields):void
 	{
-		return [
+		$fields->addField('generate_offers_from_content',
+		[
+			'type'	=> 'true_false',
+			'label'	=> __('Generate Offers from Content', 'jvb'),
+		]);
+		$fields->addField('seo_offers', [
 			'type'	=> 'repeater',
-			'label'	=> 'Opening Hours',
+			'label'	=> __('Offers', 'jvb'),
+			'condition'	=> [
+				'field'	=> 'generate_offers_from_content',
+				'value'	=> true,
+				'operator'	=> '=='
+			],
 			'fields'	=> [
-				'dayOfWeek'	=> [
+				'type'	=> [
 					'type'	=> 'radio',
-					'label'	=> 'Day(s) of Week',
+					'label'	=> __('Select Type', 'jvb'),
 					'options'	=> [
-						'Mo'	=> 'Monday',
-						'Tu'	=> 'Tuesday',
-						'We'	=> 'Wednesday',
-						'Th'	=> 'Thursday',
-						'Fr'	=> 'Friday',
-						'Sa'	=> 'Saturday',
-						'Su'	=> 'Sunday'
-					]
+						'product'	=> 'Product',
+						'service'	=> 'Service'
+					],
+					'required' => true,
 				],
-				'opens'	=> [
-					'type'	=> 'time',
-					'label'	=> 'Opens At',
+				'name'	=> [
+					'type'	=> 'text',
+					'label'	=> __('Name of Product or Service', 'jvb'),
+					'required'	=> true,
 				],
-				'closes'	=> [
-					'type'	=> 'time',
-					'label'	=> 'Closes At',
+				'description'	=> [
+					'type'	=> 'textarea',
+					'label'	=> __('Description (optional)', 'jvb'),
+				],
+				'price'	=> [
+					'type'	=> 'text',
+					'subtype'	=> 'number',
+					'label'		=> __('Price', 'jvb'),
+				],
+				'unitText' 	=> [
+					'type'	=> 'radio',
+					'label'	=> 'Price per unit',
+					'options'	=> [
+						'hour'	=> 'Hour',
+						'unit'	=> 'Unit',
+					],
+					'default'	=> 'unit',
 				]
-			]
-		];
+			],
+		]);
+	}
+
+	public function formatOffersField(Meta $meta):void
+	{
+		$generate = $meta->get('generate_offers_from_content');
+		if (!empty($generate) && $generate === true) {
+			$this->generateOffersFromContent($meta);
+			return;
+		}
+		$catalog = $meta->get('seo_offers');
+		if (!empty($catalog)) {
+			$offerCatalog = [];
+			$name = '';
+			$services = array_filter($catalog, function ($item) {
+				return $item['type'] === 'service';
+			});
+			$products =array_filter($catalog, function ($item) {
+				return $item['type'] === 'product';
+			});
+			if (count($products) > 0) {
+				$name = 'Products';
+				if (count($services) > 0) {
+					$name .= ' & ';
+				}
+			}
+			if (count($services) > 0) {
+				$name .= 'Services';
+			}
+			foreach ($catalog as $row) {
+				$offer = new Offer();
+
+				$item = match($row['type']) {
+					'product'	=> new Product(),
+					'service' 	=> new Service(),
+				};
+
+				$item->setName($row['name']);
+				if (!empty($row['description'])) {
+					$item->setDescription($row['description']);
+				}
+				if (!empty($row['price'])) {
+					$price = new PriceSpecification();
+					$price->setPrice($row['price']);
+					$price->setPriceCurrency('CAD');
+					$price->setUnitText($row['unitText']);
+					$offer->setPriceSpecification($price);
+				}
+				$offer->setItemOffered($item);
+				$offerCatalog[] =  $offer;
+			}
+			if (!empty(!$offerCatalog)) {
+				$this->setOffers($offerCatalog);
+			}
+		}
+	}
+
+	/**
+	 * This presumes that the Meta instance being passed is for a profile content type.
+	 * @param Meta $meta
+	 * @return void
+	 */
+	public function generateOffersFromContent(Meta $meta):void
+	{
+		$userID = (int)get_post_meta($meta->id(), BASE.'profile_link', true);
+		if (empty($userID)) {
+			return;
+		}
+		$user = get_userdata($userID);
+		if (!$user) {
+			return;
+		}
+		$registrar = Registrar::getInstance(jvbUserRole($userID));
+		if (!$registrar) {
+			return;
+		}
+		$types = $registrar->getCreatable();
+		if (empty($types)) {
+			return;
+		}
+		$offers = [];
+		$cities = $meta->get('city');
+		$rate = $meta->get('rate');
+		$reviews = $meta->get('reviews');
+		$rating = $meta->get('average_rating');
+		$theCities = $theRate = $theReviews = $theRating = null;
+
+		foreach($types as $type) {
+			$based = jvbCheckBase($type);
+			$hasAny = new WP_Query([
+				'post_type'		=> $based,
+				'posts_per_page'=> 1,
+				'fields'		=> 'ids',
+				'post_author'	=> $userID
+			]);
+			if ($hasAny->have_posts()) {
+				$offer = new Offer();
+				$typeRegistrar = Registrar::getInstance($type);
+				
+			}
+		}
 	}
 }

--
Gitblit v1.10.0