From 3b3bd067d0ff2671fca2890c14428c97e1011a2b Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Wed, 11 Feb 2026 03:20:21 +0000
Subject: [PATCH] =Hey guess what? Meta->set() and Meta->setAll() doesn't actually save the meta to the database. Went through the files and added a ->save() call after every set

---
 inc/rest/routes/UploadRoutes.php |  688 ---------------------------------------------------------
 1 files changed, 1 insertions(+), 687 deletions(-)

diff --git a/inc/rest/routes/UploadRoutes.php b/inc/rest/routes/UploadRoutes.php
index 4b2a4a6..f1db7a0 100644
--- a/inc/rest/routes/UploadRoutes.php
+++ b/inc/rest/routes/UploadRoutes.php
@@ -627,6 +627,7 @@
 
 		// Update with comma-separated string
 		$meta->set($data['field_name'], implode(',', $all_ids));
+		$meta->save();
 	}
 
 	/**
@@ -1124,10 +1125,6 @@
 		return $this->success($response);
 	}
 
-
-
-
-
 	public function handleGroupingRequest(WP_REST_Request $request): WP_REST_Response
 	{
 		try {
@@ -1199,687 +1196,4 @@
 			return $this->error('Grouping operation failed: '.$e->getMessage());
 		}
 	}
-
-	protected function processUploadGroups(WP_Error|array $result, object $operation, array $data): WP_Error|array
-	{
-		try {
-			$queue = JVB()->queue();
-			$all_uploaded_images = [];
-
-			// Get the upload operation ID from dependencies
-			$dependencies = json_decode($operation->dependencies, true);
-
-			if (empty($dependencies)) {
-				return [
-					'success'   => false,
-					'result'    => 'No dependencies found'
-				];
-			}
-
-			// Collect uploads from all dependency operations
-			$uploads = [];
-			foreach ($dependencies as $dependency) {
-				// Use getOperationValue like ContentRoutes does
-				$res = $queue->getOperationValue($dependency, 'result');
-
-				if (empty($res)) {
-					continue;
-				}
-
-				// Results are stored at root level, keyed by upload_id
-				// Filter to only include actual upload results (arrays with attachment_id)
-				foreach ($res as $key => $value) {
-					if (is_array($value) && isset($value['attachment_id'])) {
-						$uploads[$key] = $value;
-					}
-				}
-			}
-
-			if (empty($uploads)) {
-				return [
-					'success'   => false,
-					'result'    => 'No uploads to process'
-				];
-			}
-
-			// Build map of upload_id => attachment_id
-			foreach ($uploads as $upload_id => $img) {
-				$all_uploaded_images[$upload_id] = [
-					'upload_id' => $upload_id,
-					'attachment_id' => (int)$img['attachment_id']
-				];
-			}
-
-			$content = jvbCheckBase($data['content']);
-			if (Features::forContent($data['content'])->has('is_timeline')) {
-				return $this->processTimelineUploads($data, $uploads, $all_uploaded_images, $operation);
-			}
-
-			$user = (int)$data['user'];
-			$created_posts = [];
-			$used_upload_ids = [];
-
-			// Create posts from groups
-			foreach ($data['posts'] as $index => $post) {
-				$post_title = !empty($post['fields']['post_title'])
-					? sanitize_text_field($post['fields']['post_title'])
-					: 'New ' . JVB_CONTENT[$data['content']]['singular'] . ' ' . ($index + 1);
-
-				$post_excerpt = !empty($post['fields']['post_excerpt'])
-					? sanitize_textarea_field($post['fields']['post_excerpt'])
-					: '';
-
-				$args = [
-					'post_type' => $content,
-					'post_author' => $user,
-					'post_status' => 'draft',
-					'post_title' => $post_title,
-					'post_excerpt' => $post_excerpt,
-				];
-
-				$new_post_id = wp_insert_post($args);
-
-				if ($new_post_id && !is_wp_error($new_post_id)) {
-					$created_posts[] = $new_post_id;
-
-					// Get featured image upload_id - string, not int!
-					$featured_upload_id = $post['fields']['featured'] ?? null;
-					$featured_attachment_id = null;
-					$gallery_attachment_ids = [];
-
-					// Process all images for this post
-					foreach ($post['images'] as $img) {
-						$upload_id = $img['upload_id'];
-						$used_upload_ids[] = $upload_id;
-
-						if (isset($all_uploaded_images[$upload_id])) {
-							$attachment_id = $all_uploaded_images[$upload_id]['attachment_id'];
-
-							if ($upload_id === $featured_upload_id) {
-								$featured_attachment_id = $attachment_id;
-							} else {
-								$gallery_attachment_ids[] = $attachment_id;
-							}
-						}
-					}
-
-					// Set featured image
-					if ($featured_attachment_id) {
-						set_post_thumbnail($new_post_id, $featured_attachment_id);
-					} elseif (!empty($gallery_attachment_ids)) {
-						set_post_thumbnail($new_post_id, $gallery_attachment_ids[0]);
-						array_shift($gallery_attachment_ids);
-					}
-
-					// Set gallery images
-					if (!empty($gallery_attachment_ids)) {
-						$meta = Meta::forPost($new_post_id);
-						$fields = jvbGetFields($content, 'post');
-
-						foreach ($fields as $name => $config) {
-							if ($config['type'] === 'gallery') {
-								$meta->set($name, implode(',', $gallery_attachment_ids));
-								break;
-							}
-						}
-					}
-				}
-			}
-
-			return [
-				'success' => true,
-				'result' => [
-					'created_posts' => $created_posts,
-					'total_posts' => count($created_posts),
-					'used_images' => count($used_upload_ids),
-					'message' => "Created " . count($created_posts) . " post(s) from uploads"
-				]
-			];
-
-		} catch (Exception $e) {
-			JVB()->error()->log(
-				'[UploadRoutes]:processUploadGroups',
-				$e->getMessage(),
-				[
-					'operation_id' => $operation->id,
-					'user_id' => $operation->user_id
-				]
-			);
-
-			return [
-				'success' => false,
-				'result' => $e->getMessage()
-			];
-		}
-	}
-
-	protected function processTimelineUploads(array $data, array $uploads, array $uploadMap, object $operation):array
-	{
-		try {
-			$user = (int)$data['user'];
-			$created_posts = [];
-			$used_upload_ids = [];
-
-			$content = jvbCheckBase($data['content']);
-
-			$config = Features::getConfig($content);
-
-			$defaultTitle = 'New '.$config['singular']. ' ';
-			foreach ($data['posts'] as $index=> $post) {
-				$title = !empty($post['fields']['post_title'])
-					? sanitize_text_field($post['fields']['post_title'])
-					: $defaultTitle.($index + 1);
-				$excerpt = !empty($post['fields']['post_excerpt'])
-					? sanitize_textarea_field($post['fields']['post_excerpt'])
-					: '';
-
-				$args =[
-					'post_type'		=> $content,
-					'post_author'	=> $user,
-					'post_status'	=> 'draft',
-					'post_title'	=> $title,
-					'post_excerpt'	=> $excerpt
-				];
-				$parent = wp_insert_post($args);
-
-				if ($parent && !is_wp_error($parent)) {
-					//Get the attachment IDs first
-					$childPosts = [];
-					$featured = $post['fields']['featured']??null;
-					$featuredID = null;
-					foreach ($post['images'] as $key => $img) {
-						$upload_id = $img['upload_id'];
-						$used_upload_ids[] = $upload_id;
-
-						if (isset($uploadMap[$upload_id])) {
-							$attachment_id = (int)$uploadMap[$upload_id]['attachment_id'];
-							if ($upload_id === $featured) {
-								$featuredID = $attachment_id;
-							} else {
-								$childPosts[] = $attachment_id;
-							}
-						}
-					}
-					// Set the featured image for the parent
-					if ($featuredID) {
-						set_post_thumbnail($parent, $featuredID);
-					} elseif (!empty($childPosts)) {
-						//use first image if no set featured
-						set_post_thumbnail($parent, (int)$childPosts[0]);
-						array_shift($childPosts);
-					}
-
-					//Create Child Posts
-					if (!empty($childPosts)) {
-						$args['post_parent'] = $parent;
-						$created_posts[$parent] = [];
-						foreach ($childPosts as $i => $imgID) {
-							$treatment = $i + 1;
-							$childTitle = $title.' - Treatment '.$treatment;
-							$childDesc = '';
-							$args['post_title'] = $childTitle;
-							$args['post_excerpt'] = $childDesc;
-							$child = wp_insert_post($args);
-							if ($child && !is_wp_error($child)) {
-								$created_posts[$parent][] = $child;
-								set_post_thumbnail($child, $imgID);
-							}
-						}
-					}
-				}
-			}
-			return [
-				'success'	=> true,
-				'result'	=> [
-					'created_posts'	=> $created_posts,
-					'used_images'	=> $used_upload_ids
-				]
-			];
-		} catch (Exception $e) {
-			JVB()->error()->log(
-				'[UploadRoutes]:processTimelineUploads',
-				$e->getMessage(),
-				[
-					'operation_id' => $operation->id,
-					'user_id' => $operation->user_id
-				]
-			);
-
-			return [
-				'success' => false,
-				'result' => $e->getMessage()
-			];
-		}
-	}
-
-	protected function cleanupUnusedImages(array $unused_images): array
-	{
-		$cleaned_count = 0;
-		$errors = [];
-
-		foreach ($unused_images as $upload_id => $image_data) {
-			try {
-				$attachment_id = $image_data['attachment_id'];
-
-				// Verify this attachment exists and wasn't already deleted
-				if (get_post($attachment_id)) {
-					// Delete the attachment and its files
-					$deleted = wp_delete_attachment($attachment_id, true);
-
-					if ($deleted) {
-						$cleaned_count++;
-					} else {
-						$errors[] = "Failed to delete attachment {$attachment_id} for upload {$upload_id}";
-					}
-				} else {
-					// Attachment already doesn't exist, count as cleaned
-					$cleaned_count++;
-				}
-
-			} catch (Exception $e) {
-				$errors[] = "Error cleaning up upload {$upload_id}: " . $e->getMessage();
-			}
-		}
-
-		return [
-			'cleaned_count' => $cleaned_count,
-			'errors' => $errors
-		];
-	}
-
-	function getAttachmentID(array $image, array $storedResults): int|false
-	{
-		foreach ($storedResults as $operationID => $uploads) {
-			foreach ($uploads as $upload) {
-				// FIX: Handle both case variations
-				$stored_upload_id = $upload['upload_id'];
-				$search_upload_id = $image['upload_id'];
-
-				if ($stored_upload_id === $search_upload_id) {
-					return (int)$upload['attachment_id'];
-				}
-			}
-		}
-		return false;
-	}
-
-	function extractFeaturedItem(array &$items, string $meta_key = 'featured'): array
-	{
-		// Handle empty array
-		if (empty($items)) {
-			return [
-				'featured' => null,
-				'remaining' => []
-			];
-		}
-
-		$featured_index = null;
-
-		// First pass: look for featured item
-		foreach ($items as $index => $item) {
-			if (isset($item['meta'][$meta_key])) {
-				$featured_index = $index;
-				break;
-			}
-		}
-
-		// If no featured item found, use first item (index 0)
-		if ($featured_index === null) {
-			$featured_index = 0;
-		}
-
-		// Extract the featured/first item
-		$featured = $items[$featured_index];
-
-		// Remove the item from the original array
-		unset($items[$featured_index]);
-
-		// Re-index the array to maintain sequential indices
-		$remaining = array_values($items);
-
-		return [
-			'featured' => $featured,
-			'remaining' => $remaining
-		];
-	}
-
-	protected function mapUploadIdsToAttachments(array $uploadIds, array $uploadedImages): array
-	{
-		$mappedImages = [];
-
-		foreach ($uploadIds as $uploadId) {
-			$imageData = $this->findImageByUploadId($uploadId, $uploadedImages);
-			if ($imageData) {
-				$mappedImages[] = $imageData;
-			}
-		}
-
-		return $mappedImages;
-	}
-
-	protected function findImageByUploadId(string $uploadId, array $uploadedImages): ?array
-	{
-		// Handle both flat array and grouped results
-		foreach ($uploadedImages as $image) {
-			if (is_array($image)) {
-				// If it's a grouped result, check each image in the group
-				if (isset($image[0]) && is_array($image[0])) {
-					foreach ($image as $groupImage) {
-						if (isset($groupImage['upload_id']) && $groupImage['upload_id'] === $uploadId) {
-							return $groupImage;
-						}
-					}
-				} else {
-					// Single image result
-					if (isset($image['upload_id']) && $image['upload_id'] === $uploadId) {
-						return $image;
-					}
-				}
-			}
-		}
-
-		return null;
-	}
-
-	protected function determineFeaturedImage(array $group, array $groupImages): ?int
-	{
-		// Check if user has starred a specific image
-		if (!empty($group['featured_upload_id'])) {
-			foreach ($groupImages as $image) {
-				if (isset($image['upload_id']) && $image['upload_id'] === $group['featured_upload_id']) {
-					return $image['attachment_id'];
-				}
-			}
-		}
-
-		// Default to first image
-		return !empty($groupImages) ? $groupImages[0]['attachment_id'] : null;
-	}
-
-	protected function sanitizeGroupMetadata(array $metadata): array
-	{
-		$sanitized = [];
-
-		foreach ($metadata as $key => $value) {
-			$sanitizedKey = sanitize_key($key);
-
-			if (is_string($value)) {
-				$sanitized[$sanitizedKey] = sanitize_text_field($value);
-			} elseif (is_array($value)) {
-				$sanitized[$sanitizedKey] = array_map('sanitize_text_field', $value);
-			} else {
-				$sanitized[$sanitizedKey] = $value;
-			}
-		}
-
-		return $sanitized;
-	}
-
-	protected function generatePostTitle(string $content, int $userId): string
-	{
-		$username = get_user_meta($userId, 'first_name', true) ?: get_user_meta($userId, 'display_name', true);
-		$link = get_user_meta($userId, BASE.'link', true);
-		$city = function_exists('jvbArtistCity') ? jvbArtistCity($link) : '';
-
-		$title = ucfirst($content);
-		if ($username) {
-			$title .= ' by ' . $username;
-		}
-		if ($city) {
-			$title .= ' from ' . $city;
-		}
-
-		return $title;
-	}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-	/**
-	 * Determine how to save uploaded files based on configuration
-	 */
-	protected function handleUploadDestination(array $data, array $results): void
-	{
-		// Determine destination from config
-		$destination = $data['destination'] ?? 'meta';
-
-		switch ($destination) {
-			case 'meta':
-				// Save to post/term/user meta
-				$this->saveToMeta($data, $results);
-				break;
-
-			case 'post':
-				// Create individual posts for each file
-				$this->createIndividualPosts($data, $results);
-				break;
-
-			case 'post_group':
-				// Create posts with grouped files
-				$this->createGroupedPosts($data, $results);
-				break;
-
-			default:
-				// No destination specified - files processed but not attached
-				break;
-		}
-	}
-
-	/**
-	 * Infer destination from existing data (backward compatibility)
-	 */
-	protected function inferDestination(array $data): string
-	{
-		// If field_name exists → saving to meta
-		if (!empty($data['field_name'])) {
-			return 'meta';
-		}
-
-		// If post_type exists without field_name → creating posts
-		if (!empty($data['content'])) {
-			return 'post';
-		}
-
-		// No destination
-		return 'none';
-	}
-
-	private function getMetaManager(array $data): ?Meta
-	{
-		if (!empty($data['post_id'])) {
-			return Meta::forPost($data['post_id']);
-		}
-		if (!empty($data['term_id'])) {
-			return Meta::forTerm($data['term_id']);
-		}
-		if (!empty($data['user'])) {
-			$link = (int)get_user_meta($data['user'], BASE . 'link', true);
-			if ($link) {
-				return Meta::forPost($link);
-			}
-		}
-		return null;
-	}
-	/**
-	 * Save attachment IDs to meta field
-	 */
-	private function saveToMeta(array $data, array $results): void
-	{
-		if (empty($data['field_name'])) {
-			return;
-		}
-
-		$attachmentIds = array_column($results, 'attachment_id');
-		$meta = $this->getMetaManager($data);
-		if (!$meta) {
-			return;
-		}
-
-		$fieldType = $data['field_type'] ?? 'single';
-
-		if ($fieldType === 'single') {
-			// Single field: replace with latest upload
-			$meta->set($data['field_name'], end($attachmentIds));
-		} else {
-			// Multi field: merge with existing
-			$existing = $meta->get($data['field_name']);
-			$existingIds = !empty($existing) ? explode(',', $existing) : [];
-			$allIds = array_unique(array_merge($existingIds, $attachmentIds));
-			$meta->set($data['field_name'], implode(',', $allIds));
-		}
-	}
-
-	/**
-	 * Create individual posts from uploads
-	 */
-	protected function createIndividualPosts(array $data, array $results): array
-	{
-		if (empty($data['content'])) {
-			return [];
-		}
-
-		$created_posts = [];
-
-		foreach ($results as $result) {
-			$attachment_id = $result['attachment_id'];
-			$attachment = get_post($attachment_id);
-
-			// Create post
-			$post_data = [
-				'post_type' => jvbCheckBase($data['content']),
-				'post_title' => $attachment->post_title,
-				'post_status' => 'draft',
-				'post_author' => $data['user'] ?? get_current_user_id(),
-			];
-
-			$post_id = wp_insert_post($post_data);
-
-			if (!is_wp_error($post_id)) {
-				// Set as featured image or attach to gallery
-				$this->attachFileToPost($post_id, $attachment_id, $data);
-
-				$created_posts[] = [
-					'post_id' => $post_id,
-					'attachment_id' => $attachment_id,
-				];
-			}
-		}
-
-		return $created_posts;
-	}
-
-	/**
-	 * Create posts with grouped uploads
-	 */
-	protected function createGroupedPosts(array $data, array $results): array
-	{
-		if (empty($data['content'])) {
-			return [];
-		}
-
-		$id_map = [];
-		foreach ($results as $result) {
-			if (isset($result['upload_id'], $result['attachment_id'])) {
-				$id_map[$result['upload_id']] = $result['attachment_id'];
-			}
-		}
-
-		// Groups come from frontend as metadata
-		$groups = $data['groups'] ?? [array_column($results, 'attachment_id')];
-		$created_posts = [];
-
-		foreach ($groups as $group_index => $group_upload_ids) {
-			$group_attachment_ids = array_filter(
-				array_map(fn($uid) => $id_map[$uid] ?? null, $group_upload_ids)
-			);
-
-			if (empty($group_attachment_ids)) continue;
-			// Create post for this group
-			$first_attachment = get_post($group_attachment_ids[0]);
-
-			$post_data = [
-				'post_type' => jvbCheckBase($data['content']),
-				'post_title' => $data['group_titles'][$group_index] ?? $first_attachment->post_title,
-				'post_status' => $data['post_status'] ?? 'draft',
-				'post_author' => $data['user'] ?? get_current_user_id(),
-			];
-
-			$post_id = wp_insert_post($post_data);
-
-			if (!is_wp_error($post_id)) {
-				// Attach all files in group
-				foreach ($group_attachment_ids as $index => $attachment_id) {
-					if ($index === 0) {
-						// First is featured
-						set_post_thumbnail($post_id, $attachment_id);
-					} else {
-						// Others go to gallery
-						$meta = Meta::forPost($post_id);
-						$existing = $meta->get('gallery');
-						$existing_ids = !empty($existing) ? explode(',', $existing) : [];
-						$existing_ids[] = $attachment_id;
-						$meta->set('gallery', implode(',', $existing_ids));
-					}
-				}
-
-				$created_posts[] = [
-					'post_id' => $post_id,
-					'attachment_ids' => $group_attachment_ids,
-				];
-			}
-		}
-
-		return $created_posts;
-	}
-
-	/**
-	 * Attach file to post based on file type
-	 */
-	protected function attachFileToPost(int $post_id, int $attachment_id, array $data): void
-	{
-		$attachment = get_post($attachment_id);
-		$mime_type = $attachment->post_mime_type;
-
-		// Determine file type
-		if (str_starts_with($mime_type, 'image/')) {
-			// Set as featured image
-			set_post_thumbnail($post_id, $attachment_id);
-		} elseif (str_starts_with($mime_type, 'video/')) {
-			// Save to video field
-			$meta = Meta::forPost($post_id);
-			$meta->set('video', $attachment_id);
-		} else {
-			// Documents - save to documents field
-			$meta = Meta::forPost($post_id);
-			$existing = $meta->get('documents');
-			$existing_ids = !empty($existing) ? explode(',', $existing) : [];
-			$existing_ids[] = $attachment_id;
-			$meta->set('documents', implode(',', $existing_ids));
-		}
-	}
 }

--
Gitblit v1.10.0