From 235ce5716edc2f7cbe80fdccf26eac7269587839 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Mon, 08 Jun 2026 04:38:18 +0000
Subject: [PATCH] =FavouritesManager.php and FavouritesRoutes.php fixes. Moving all logic to FavouritesManager.php. Still some left to do

---
 inc/managers/queue/executors/ContentExecutor.php |  361 ++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 255 insertions(+), 106 deletions(-)

diff --git a/inc/managers/queue/executors/ContentExecutor.php b/inc/managers/queue/executors/ContentExecutor.php
index e8b6e72..6b6aa1a 100644
--- a/inc/managers/queue/executors/ContentExecutor.php
+++ b/inc/managers/queue/executors/ContentExecutor.php
@@ -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,103 +67,59 @@
 	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;
-				}
-
-				// 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);
+				$content = $postData['content'] ?? false;
+				if (!$content) continue;
 				$registrar = Registrar::getInstance($content);
-				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('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));
-						}
-					}
+				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;
 				}
-
-				$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();
 		}
 
 
@@ -183,13 +140,7 @@
 
 		return new Result(
 			outcome: $outcome,
-			result: [
-				'posts'	=> $success,
-				'errors' => $errors,
-				'new_posts' => $newPostsMap,
-				'updated_count' => count($success),
-				'failed_count' => count($errors)
-			]
+			result: $results,
 		);
 	}
 
@@ -202,14 +153,72 @@
 			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
@@ -233,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);
@@ -259,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;
@@ -324,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;
 		}
 
@@ -438,18 +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) {
-				Meta::forPost($child)->setAll($values)->save(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') && (!JVB()->roles()->isOwner($this->userId, $ID) && !JVB()->roles()->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