From 3d25ad7de4fdbb3eba2cde2a62422e6be5d79a0a Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Tue, 25 Aug 2026 22:57:22 +0000
Subject: [PATCH] =It's been a minute. I went through the Routes and associated Managers and ensured they played together well. Reworked the Cache.php, and I think I caught all the references. Moving away from JVBase() root class, to individuall classes that are Instanced. Double checked for the ABSPATH check in every file, and added index.php to every directory that didn't already have it. Also still working on the MenuBlock to work with WooCommerce for now for Northeh

---
 inc/managers/queue/executors/ContentExecutor.php |  369 +++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 259 insertions(+), 110 deletions(-)

diff --git a/inc/managers/queue/executors/ContentExecutor.php b/inc/managers/queue/executors/ContentExecutor.php
index d9a8e11..2755eb9 100644
--- a/inc/managers/queue/executors/ContentExecutor.php
+++ b/inc/managers/queue/executors/ContentExecutor.php
@@ -3,7 +3,7 @@
 
 use JVBase\managers\queue\{Executor, Operation, Progress, Result, Storage};
 use JVBase\meta\Meta;
-use JVBase\utility\Features;
+use JVBase\registrar\Registrar;
 use Exception;
 
 if (!defined('ABSPATH')) {
@@ -32,6 +32,7 @@
 		if (!in_array($operation->type, self::HANDLED_TYPES)) {
 			throw new Exception("ContentExecutor cannot handle type: {$operation->type}");
 		}
+		error_log('Executing ContentExecutor.php');
 
 		try {
 			$data = $operation->requestData;
@@ -66,108 +67,65 @@
 	private function processContentUpdate(Operation $operation, array $data, Progress $progress): Result
 	{
 		$posts = $data['posts'] ?? [];
-
+		error_log('Processing Content Update: '.print_r($posts, true));
 		if (empty($posts)) {
 			return new Result(
-				outcome: 'failed',
+				outcome: 'success',
 				result: ['message' => 'No posts to update']
 			);
 		}
 
-		$results = [];
+		$results = [
+			'errors'	=> [],
+			'success'	=> [],
+			'newPosts'	=> [],
+			'timelineParents'	=> [],
+			'timelineStatus'	=> [],
+			'timelineSharedFields'	=> [],
+		];
 		$errors = [];
-		$success = [];
-		$timelineParents = [];
-		$timelineStatus = [];
-		$timelineSharedFields = [];
-		$newPostsMap = [];
 
 		foreach ($posts as $id => $postData) {
 			try {
-				$content = $postData['content'] ?? '';
-
-				// New post creation
-				if (str_starts_with((string)$id, 'new')) {
-					$newId = wp_insert_post([
-						'post_author' => $this->userId,
-						'post_type'   => jvbCheckBase($content),
-						'post_title'  => $postData['post_title'] ?? '',
-						'post_status' => $postData['status'] ?? 'draft',
-					]);
-
-					if (!$newId || is_wp_error($newId)) {
-						$errors[$id] = 'Could not create post';
-						$progress->failItem($id, 'Could not create post');
-						continue;
-					}
-
-					$newPostsMap[$id] = $newId;
-					$this->savePostFields($newId, $postData);
-					$success[$newId] = array_keys($postData);
-					$progress->advance();
-					continue;
+				$content = $postData['content'] ?? false;
+				if (!$content) continue;
+				$registrar = Registrar::getInstance($content);
+				switch ($registrar->getType()) {
+					case 'post':
+						$results = $this->handlePost($id, $postData, $registrar, $results, $progress);
+						break;
+					case 'term':
+						$results = $this->handleTerm($id, $postData, $registrar, $results, $progress);
+						break;
+					case 'user':
+						$results = $this->handleUser($id, $postData, $registrar, $results, $progress);
+						break;
 				}
-
-				// Existing post update
-				if (!$this->verifyOwnership((int)$id)) {
-					$progress->failItem($id, 'No permission to modify this post');
-					$errors[$id] = 'No permission';
-					continue;
-				}
-
-				$this->savePostFields((int)$id, $postData);
-
-				if (Features::forContent($content)->has('is_timeline')) {
-					$post = get_post((int)$id);
-					$parentId = $post->post_parent > 0 ? $post->post_parent : $post->ID;
-					$sharedFields = array_keys(array_filter(JVB_CONTENT[$content]['fields'], function ($field) {
-						return !array_key_exists('for_all', $field) || !$field['for_all'];
-					}));
-
-					if (array_key_exists('post_date', $postData) && !in_array($parentId, $timelineParents)) {
-						$timelineParents[] = $parentId;
-					}
-					if ($parentId === $id) {
-						if (array_key_exists('post_status', $postData) && !array_key_exists($parentId, $timelineStatus)) {
-							$timelineStatus[$parentId] = $postData['post_status'];
-						}
-
-						if (count(array_intersect($sharedFields, array_keys($postData))) > 0) {
-							if (!array_key_exists($parentId, $timelineSharedFields)) {
-								$timelineSharedFields[$parentId] = [];
-							}
-							$temp = array_intersect($sharedFields, array_keys($postData));
-							$timelineSharedFields[$parentId] = array_unique(array_merge($timelineSharedFields[$parentId], $temp));
-						}
-					}
-				}
-
-				$success[$id] = array_keys($postData);
-				$progress->advance();
 			} catch (Exception $e) {
 				$progress->failItem($id, $e->getMessage());
-				$errors[$id] = $e->getMessage();
+				$results['errors'][$id] = $e->getMessage();
 			}
 		}
+		error_log('Final Results: '.print_r($results, true));
 
 		try {
-			if (!empty($timelineSharedFields)) {
-				$this->checkSharedFields($timelineSharedFields);
+			if (!empty($results['timelineSharedFields'])) {
+				$this->checkSharedFields($results['timelineSharedFields']);
 			}
-			if (!empty($timelineStatus)) {
-				$this->handleTimelineStatusChange($timelineStatus);
+			if (!empty($results['timelineStatus'])) {
+				$this->handleTimelineStatusChange($results['timelineStatus']);
 			}
-			if (!empty($timelineParents)) {
-				$this->maybeReorderTimelines($timelineParents);
+			if (!empty($results['timelineParents'])) {
+				$this->maybeReorderTimelines($results['timelineParents']);
 			}
 		} catch (Exception $e) {
-			$errors[] = $e->getMessage();
+			$results['errors'][] = $e->getMessage();
 		}
 
 
 		// Send notification
 //		if (jvbSiteHasNotifications()) {
-//			JVB()->notification()->addNotification(
+//			NotificationManager::getInstance()->addNotification(
 //				$this->userId,
 //				'content_update_complete',
 //				null,
@@ -182,33 +140,85 @@
 
 		return new Result(
 			outcome: $outcome,
-			result: [
-				'posts'	=> $success,
-				'errors' => $errors,
-				'new_posts' => $newPostsMap,
-				'updated_count' => count($success),
-				'failed_count' => count($errors)
-			]
+			result: $results,
 		);
 	}
 
 	private function savePostFields(int $postId, array $postData): bool
 	{
 		$content = $postData['content'] ?? '';
-		$fields = jvbGetFields($content);
+		$fields = Registrar::getFieldsFor($content);
 
 		$allowedFields = array_filter($postData, function ($key) use ($fields) {
 			return array_key_exists($key, $fields);
 		}, ARRAY_FILTER_USE_KEY);
 
+		//Remove values that are already saved
+		$check = Meta::forPost($postId)->getAll(array_keys($allowedFields));
+		error_log('Stored values: '.print_r($check, true));
+		$allowedFields = array_filter($allowedFields, function ($key) use ($allowedFields, $check) {
+			return $allowedFields[$key] !== $check[$key];
+		}, ARRAY_FILTER_USE_KEY);
+
 		if (empty($allowedFields)) {
 			return true;
 		}
 
 		return Meta::forPost($postId)
-			->setAll($allowedFields)
-			->save();
+			->setAll($allowedFields);
 	}
+	private function saveTermFields(int $termId, array $data): bool
+	{
+		$content = $data['content'] ?? '';
+		error_log('Saving term fields: '.print_r($data, true));
+		$fields = Registrar::getFieldsFor($content);
+
+		$allowedFields = array_filter($data, function ($key) use ($fields) {
+			return array_key_exists($key, $fields);
+		}, ARRAY_FILTER_USE_KEY);
+
+
+		//Remove values that are already saved
+		$check = Meta::forTerm($termId)->getAll(array_keys($allowedFields));
+		error_log('Stored values: '.print_r($check, true));
+		$allowedFields = array_filter($allowedFields, function ($value, $key) use ($check) {
+			error_log('Sent value: '.print_r($value, true));
+			error_log('Stored Value: '.print_r($check[$key], true));
+			return $value !== $check[$key];
+		}, ARRAY_FILTER_USE_BOTH);
+
+		if (empty($allowedFields)) {
+			return true;
+		}
+
+		error_log('Allowed fields: '.print_r($allowedFields, true));
+
+		return Meta::forTerm($termId)
+			->setAll($allowedFields);
+	}
+	private function saveUserFields(int $userId, array $data): bool
+	{
+		$content = $data['content'] ?? '';
+		$fields = Registrar::getFieldsFor($content);
+
+		$allowedFields = array_filter($data, function ($key) use ($fields) {
+			return array_key_exists($key, $fields);
+		}, ARRAY_FILTER_USE_KEY);
+
+		//Remove values that are already saved
+		$check = Meta::forUser($userId)->getAll(array_keys($allowedFields));
+		$allowedFields = array_filter($allowedFields, function ($key) use ($allowedFields, $check) {
+			return $allowedFields[$key] !== $check[$key];
+		}, ARRAY_FILTER_USE_KEY);
+
+		if (empty($allowedFields)) {
+			return true;
+		}
+
+		return Meta::forUser($userId)
+			->setAll($allowedFields);
+	}
+
 
 	// ─────────────────────────────────────────────────────────────
 	// Helpers
@@ -232,23 +242,17 @@
 			}
 		}
 	}
-	protected function maybeReorderTimeline(int $parentID):void
+	protected function getTimelinePosts(int $parentID):array
 	{
-//		clean_post_cache($parentID);
 		$parent = get_post($parentID);
 		if (!$parent) {
-			return;
+			return [];
 		}
 
-		$children = get_children([
-			'post_parent' => $parentID,
-			'posts_per_page' => -1,
-			'post_status' => ['publish', 'draft'],
-		]);
-
+		$children = jvbTimelinePoints($parentID, $parent->post_type, ['publish', 'draft']);
 
 		if (count($children) === 0) {
-			return;
+			return [];
 		}
 
 		$allPosts = array_merge([$parent], $children);
@@ -258,6 +262,22 @@
 			return strtotime($a->post_date) <=> strtotime($b->post_date);
 		});
 
+		return $allPosts;
+	}
+	protected function maybeReorderTimeline(int $parentID):void
+	{
+//		clean_post_cache($parentID);
+		$parent = get_post($parentID);
+		if (!$parent) {
+			return;
+		}
+
+		$allPosts = $this->getTimelinePosts($parentID);
+		if (empty($allPosts)) {
+			return;
+		}
+
+
 
 		// Check if order changed
 		$needsReorder = false;
@@ -323,11 +343,14 @@
 					}
 				}
 			}
+			$isUpdate = $meta->get('is_update');
+			if (!(bool) $isUpdate) {
+				$meta->set('number', $index);
+			}
 
 			if ($lastKey === $index) {
 				$latestTimestamp = strtotime($post->post_date);
 			}
-			$meta->save();
 			$previousPost = $post;
 		}
 
@@ -437,19 +460,14 @@
 			$meta = Meta::forPost($parentID);
 			$values = $meta->getAll($shared);
 
-			$children = get_children([
-				'post_parent' => $parentID,
-				'posts_per_page' => -1,
-				'fields' => 'ids',
-			]);
+			$children = jvbTimelinePoints($parentID, get_post_type($parentID), ['any']);
 
 			if (empty($children)) {
 				continue;
 			}
 
 			foreach ($children as $child) {
-				$childMeta = Meta::forPost($child);
-				$result = $childMeta->setAll($values, false);
+				Meta::forPost($child)->setAll($values);
 			}
 		}
 	}
@@ -461,11 +479,8 @@
 		});
 
 		foreach ($updates as $parentID => $status) {
-			$children = get_children([
-				'post_parent'	=> $parentID,
-				'posts_per_page' => -1,
-				'fields'	=> 'ids'
-			]);
+			$children = jvbTimelinePoints($parentID, get_post_type($parentID), ['any']);
+
 			if (!empty($children)) {
 				foreach($children as $child) {
 					if ($status === 'trash') {
@@ -483,4 +498,138 @@
 			}
 		}
 	}
+
+	protected function handlePost(string|int $ID, array $data, Registrar $registrar, array $results, Progress $progress):array
+	{
+		// New post creation
+		if (str_starts_with((string)$ID, 'new')) {
+
+			$newId = wp_insert_post([
+				'post_author' => $this->userId,
+				'post_type'   => $registrar->getBased(),
+				'post_title'  => $data['post_title'] ?? apply_filters('jvbDefaultTitle', '', $registrar->getSlug()),
+				'post_status' => $data['status'] ?? 'draft',
+			]);
+			error_log('Created new post: '.print_r($newId, true));
+
+			if (!$newId || is_wp_error($newId)) {
+				$results['errors'][$ID] = 'Could not create post';
+				$progress->failItem($ID, 'Could not create post');
+				return $results;
+			}
+
+			$results['newPosts'][$ID] = $newId;
+			$this->savePostFields($newId, $data);
+			unset($data['content']);
+			$results['success'][$newId] = $data;
+			$progress->advance();
+			return $results;
+		}
+
+		//Existing post update
+		if (!$this->verifyOwnership((int)$ID)) {
+			$progress->failItem($ID, 'No permission to modify this post');
+			$results['errors'][$ID] = 'No permission';
+			return $results;
+		}
+
+		$result = $this->savePostFields((int)$ID, $data);
+		unset($data['content']);
+		if ($result) {
+			$results['success'][$ID] = $data;
+		} else {
+			$results['errors'][$ID] = 'Could not update post data';
+		}
+		if ($registrar && $registrar->hasFeature('is_timeline')) {
+			$post = get_post((int)$ID);
+			$parentId = $post->post_parent > 0 ? $post->post_parent : $post->ID;
+			$fields = $registrar->getFields();
+			$sharedFields = array_keys(array_filter($fields, function ($field) {
+				return !array_key_exists('for_all', $field) || !$field['for_all'];
+			}));
+
+
+			if (array_key_exists('timeline_gallery', $data)) {
+				//This should only happen if we delete an image from the gallery
+				$changes = explode(',', $data['timeline_gallery']);
+				$timelinePosts = $this->getTimelinePosts($parentId);
+				if (!empty($timelinePosts)) {
+					$posts = array_map(function($item) { return $item->ID; }, $timelinePosts);
+					$changed = false;
+					foreach ($posts as $tID) {
+						if (!in_array($tID, $changes)) {
+							$changed = true;
+							wp_delete_post($tID, true);
+						}
+					}
+					if ($changed) {
+						$results['timelineParents'][] = $parentId;
+					}
+				}
+
+			}
+
+
+			if (array_key_exists('post_date', $data) && !in_array($parentId, $results['timelineParents'])) {
+				$results['timelineParents'][] = $parentId;
+			}
+			if ($parentId === $ID) {
+				if (array_key_exists('post_status', $data) && !array_key_exists($parentId, $results['timelineStatus'])) {
+					$results['timelineStatus'][$parentId] = $data['post_status'];
+				}
+
+				if (count(array_intersect($sharedFields, array_keys($data))) > 0) {
+					if (!array_key_exists($parentId, $results['timelineSharedFields'])) {
+						$results['timelineSharedFields'][$parentId] = [];
+					}
+					$temp = array_intersect($sharedFields, array_keys($data));
+					$results['timelineSharedFields'][$parentId] = array_unique(array_merge($results['timelineSharedFields'][$parentId], $temp));
+				}
+			}
+		}
+		$progress->advance();
+		return $results;
+	}
+
+
+	protected function handleTerm(int $ID, array $data, Registrar $registrar, array $results, Progress $progress):array
+	{
+		error_log('Handling term '.$ID.' with data: '.print_r($data, true));
+		//Existing term update
+		if ($registrar->hasFeature('is_ownable') && (!Roles::getInstance()()->isOwner($this->userId, $ID) && !Roles::getInstance()()->isManager($this->userId, $ID))) {
+			error_log('Term is ownable. User does not own this term.');
+			$progress->failItem($ID, 'No permission to modify this term');
+			$results['errors'][$ID] = 'No permission';
+			return $results;
+		}
+
+		$result = $this->saveTermFields($ID, $data);
+		unset($data['content']);
+		if ($result) {
+			$results['success'][$ID] = $data;
+		} else {
+			$results['errors'][$ID] = 'Could not update term data';
+		}
+		$progress->advance();
+		return $results;
+	}
+	protected function handleUser(int $ID, array $data, Registrar $registrar, array $results, Progress $progress):array
+	{
+		//Existing term update
+		if ($ID !== $this->userId || !user_can($this->userId, 'manage_options')) {
+			$progress->failItem($ID, 'No permission to modify this term');
+			$results['errors'][$ID] = 'No permission';
+			return $results;
+		}
+
+		$result = $this->saveUserFields($ID, $data);
+		unset($data['content']);
+		if ($result) {
+			$results['success'][$ID] = $data;
+		} else {
+			$results['errors'][$ID] = 'Could not update post data';
+		}
+		$progress->advance();
+		return $results;
+	}
 }

--
Gitblit v1.10.0