From d38d825e3484d822ea3c1f0fb1df37ecf386b18a Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 04 Jan 2026 19:54:16 +0000
Subject: [PATCH] =TaxonomyCreator.js debugging
---
inc/rest/routes/ContentRoutes.php | 322 +++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 248 insertions(+), 74 deletions(-)
diff --git a/inc/rest/routes/ContentRoutes.php b/inc/rest/routes/ContentRoutes.php
index dfa9cb6..3d455d5 100644
--- a/inc/rest/routes/ContentRoutes.php
+++ b/inc/rest/routes/ContentRoutes.php
@@ -36,7 +36,7 @@
{
$this->cache_name = 'user_content_'.get_current_user_id();
parent::__construct();
-
+ $this->cache->clear();
$this->action = 'dash-';
$this->operation_type = 'content_update';
add_filter(BASE.'handle_bulk_operation', [$this, 'processOperation'], 10, 3);
@@ -88,17 +88,44 @@
$config = Features::getConfig($content);
$this->fields = $config['fields'];
- $this->timelineSharedFields = array_keys(array_filter($this->fields, function ($field) {
- if (!array_key_exists('for_all', $field) || $field['for_all'] === false){
+ $this->timelineSharedFields = $this->getTimelineSharedFields($content);
+ array_unshift($this->timelineSharedFields, 'post_thumbnail');
+ array_unshift($this->timelineSharedFields, 'post_title');
+ array_unshift($this->timelineSharedFields, 'post_status');
+
+ $this->timelineUniqueFields = $this->getTimelineUniqueFields($content);
+ }
+ public function getTimelineUniqueFields(string $content):array
+ {
+ $content = jvbNoBase($content);
+ if (!Features::forContent($content)->has('is_timeline')){
+ return [];
+ }
+ $config = Features::getConfig($content);
+ $allFields = $config['fields'];
+
+ return array_keys(array_filter($allFields, function ($field) {
+ if (array_key_exists('for_all', $field) && $field['for_all'] === true) {
return true;
}
return false;
}));
- array_unshift($this->timelineSharedFields, 'post_thumbnail');
- array_unshift($this->timelineSharedFields, 'post_title');
+ }
- $this->timelineUniqueFields = array_keys(array_filter($this->fields, function ($field) {
- if (array_key_exists('for_all', $field) && $field['for_all'] === true) {
+ public function getTimelineSharedFields(string $content):array
+ {
+ $content = jvbNoBase($content);
+ if (!Features::forContent($content)->has('is_timeline')){
+ return [];
+ }
+ $config = Features::getConfig($content);
+ if (!$config || empty($config)) {
+ return [];
+ }
+ $allFields = $config['fields']??[];
+
+ return array_keys(array_filter($allFields, function ($field) {
+ if (!array_key_exists('for_all', $field) || $field['for_all'] === false){
return true;
}
return false;
@@ -198,9 +225,6 @@
public function handleContentRequest(WP_REST_Request $request):WP_REST_Response
{
$params = $request->get_params();
- error_log('handleContentRequest params: '.print_r($params, true));
-
- error_log('Fetching content. Params: '.print_r($params, true));
$user_id = $params['user'];
if (!$this->userCheck($user_id)) {
return new WP_REST_Response([
@@ -237,6 +261,16 @@
if (Features::forContent($post_type)->has('is_calendar')) {
$args = $this->applyCalendarFilters($args, $params);
}
+ $taxonomies = array_filter($params, function($param) {
+ return str_starts_with($param, 'tax_');
+ }, ARRAY_FILTER_USE_KEY);
+ if (!empty($taxonomies)) {
+ $params['taxonomies'] = [];
+ foreach ($taxonomies as $taxonomy => $terms) {
+ $taxonomy = str_replace('tax_', '', $taxonomy);
+ $params['taxonomies'][$taxonomy] = $terms;
+ }
+ }
if (array_key_exists('taxonomies', $params)) {
$args = $this->applyTaxonomyFilters($args, $params);
}
@@ -251,10 +285,6 @@
$args['s'] = sanitize_text_field($params['search']);
}
-
-
- error_log('Content Routes final args: '.print_r($args, true));
-
$key = $this->cache->generateKey($args);
// Check HTTP cache headers with the specific content type
$content_type = $params['content'] ?? $params['type'];
@@ -267,7 +297,6 @@
$cache = $this->cache->get($key);
- $cache = false;
if ($cache) {
$response = new WP_REST_Response($cache);
return $this->addCacheHeaders($response);
@@ -339,8 +368,21 @@
$results = [];
foreach ($posts as $ID => $post_data) {
- if (Features::forContent($post_data['content'])->has('is_timeline')) {
- $results[$ID] =$this->processTimelinePost($ID, $post_data);
+ if (Features::forContent($post_data['content'])->has('is_timeline') && array_key_exists('timeline', $post_data)) {
+ // Handle timeline posts - ensure we have a valid integer ID
+ $parent_id = (int)$ID;
+
+ // Skip if ID is invalid (0, 'null', etc would become 0)
+ if ($parent_id === 0) {
+ error_log('Invalid timeline parent ID: ' . $ID);
+ $results[$ID] = [
+ 'success' => false,
+ 'message' => 'Invalid parent post ID for timeline'
+ ];
+ continue;
+ }
+
+ $results[$ID] = $this->processTimelinePost($parent_id, $post_data);
continue;
}
if (str_starts_with($ID, 'new')) {
@@ -416,7 +458,6 @@
error_log('Allowed Fields: '.print_r($allowedFields, true));
$meta = new MetaManager($ID, 'post');
$success = $meta->setAll($allowedFields);
- error_log('Should be set?');
$results[$ID] = [
'success' => $success
];
@@ -458,62 +499,138 @@
return ['success' => false, 'message' => 'No permission'];
}
+ $ignore = ['content', 'user'];
$this->fields = jvbGetFields($post_data['content']);
$this->initTimelineFields($post_data['content']);
- error_log('Received Data: '.print_r($post_data, true));
- // First, process the main fields that will apply to all posts
- $sharedData = array_filter($post_data, function ($key) {
- return in_array($key, $this->timelineSharedFields);
+ // Get parent post details
+ $parent_post = get_post($parent_id);
+ $parent_title = $parent_post->post_title;
+ $parent_is_published = ($parent_post->post_status === 'publish');
+
+ // Extract shared data from top level (excluding post_thumbnail which is unique per post)
+ $sharedData = array_filter($post_data, function ($key) use ($ignore) {
+ return in_array($key, $this->timelineSharedFields)
+ && !in_array($key, $ignore)
+ && $key !== 'post_thumbnail';
}, ARRAY_FILTER_USE_KEY);
- //Next, process any individual posts, including any menu order changes
+ // If no shared post_title at top level, extract from first timeline entry
+ if (!isset($sharedData['post_title']) && isset($post_data['timeline'][0]['post_title'])) {
+ $sharedData['post_title'] = $post_data['timeline'][0]['post_title'];
+ }
+ $clearParent = false;
if (array_key_exists('timeline', $post_data) && is_array($post_data['timeline'])) {
- $sharedTaxonomies = $sharedData;
- unset($sharedTaxonomies['post_title']);
+ // Remove post_title and post_thumbnail from shared taxonomies
+ $sharedTaxonomies = array_filter($sharedData, function($key) {
+ return $key !== 'post_title' && $key !== 'post_thumbnail';
+ }, ARRAY_FILTER_USE_KEY);
- //Ensure the parent post exists and is still first in the array
+ // Ensure the parent post exists and is still first in the array
$index = array_search((string)$parent_id, array_column($post_data['timeline'], 'id'));
- error_log('Found index: '.print_r($index, true));
+
if ($index === false) {
return [
'success' => false,
- 'message' => 'Missing parent id. This should not have happened'
+ 'message' => 'Missing parent id. This should not have happened'
];
- } elseif ($index !== 0) {
- // Move that element to the start of the array
- $item = $post_data['timeline'][$index];
- unset($post_data['timeline'][$index]);
- array_unshift($post_data['timeline'], $item);
}
+
+ if ($index !== 0) {
+ $new_parent_id = $post_data['timeline'][0]['id'];
+
+ if (is_numeric($new_parent_id) && (int)$new_parent_id > 0) {
+ $new_parent_id = (int)$new_parent_id;
+ wp_update_post([
+ 'ID' => $new_parent_id,
+ 'post_parent' => 0
+ ]);
+
+ wp_update_post([
+ 'ID' => $parent_id,
+ 'post_parent' => $new_parent_id
+ ]);
+
+ $existing_children = get_children([
+ 'post_parent' => $parent_id,
+ 'fields' => 'ids'
+ ]);
+
+ foreach ($existing_children as $child_id) {
+ if ($child_id !== $new_parent_id) {
+ wp_update_post([
+ 'ID' => $child_id,
+ 'post_parent' => $new_parent_id
+ ]);
+ }
+ }
+
+ // Update parent references
+ $parent_id = $new_parent_id;
+ $parent_post = get_post($parent_id);
+ $parent_title = $parent_post->post_title;
+ $parent_is_published = ($parent_post->post_status === 'publish');
+ } else {
+ $item = $post_data['timeline'][$index];
+ unset($post_data['timeline'][$index]);
+ array_unshift($post_data['timeline'], $item);
+ }
+ }
+
$errors = [];
$success = [];
- // Get existing children to track deletions
$existing_children = get_children([
'post_parent' => $parent_id,
- 'post_type' => jvbCheckBase($post_data['content']),
- 'fields' => 'ids'
+ 'orderby' => 'menu_order',
+ 'post_status' => ['publish', 'draft'],
+ 'fields'=> 'ids'
]);
- //Iterate through the timeline posts
+
+ $prevDate = null;
+
foreach($post_data['timeline'] as $order => $timeline) {
- $allowedFields = array_filter($timeline, function($key) {
- return in_array($key, $this->timelineUniqueFields);
+ // Get unique fields for this specific timeline entry
+ $allowedFields = array_filter($timeline, function($key) use ($ignore) {
+ return in_array($key, $this->timelineUniqueFields) && !in_array($key, $ignore);
}, ARRAY_FILTER_USE_KEY);
- $allowedFields['post_title'] = $allowedFields['post_title'] ?? $sharedData['post_title'].' - Treatment #'.$order;
- $allowedFields = array_merge($allowedFields, $sharedTaxonomies);
+ // Determine the post title
+ $is_parent = ((int)$timeline['id'] === $parent_id);
+ $provided_title = $timeline['post_title'] ?? '';
+ $auto_generated_pattern = '/^.+Treatment #?\d+$/'; // Matches "Title - Treatment #1" or "Title - Treatment 1"
+
+ if ($is_parent) {
+ // Parent keeps its own title or uses shared title
+ $allowedFields['post_title'] = $provided_title ?: ($sharedData['post_title'] ?? $parent_title);
+ } else {
+ // For child posts, auto-generate if:
+ // 1. No title provided, OR
+ // 2. Title matches auto-generated pattern (meaning it wasn't customized)
+ if (empty($provided_title) || preg_match($auto_generated_pattern, $provided_title)) {
+ $allowedFields['post_title'] = 'Treatment ' . $order;
+ } else {
+ // Keep custom title
+ $allowedFields['post_title'] = $provided_title;
+ }
+ }
+
+ // Merge with shared taxonomies AFTER setting unique fields
+ $allowedFields = array_merge($sharedTaxonomies, $allowedFields);
+
+ // Handle post creation if needed
if (!array_key_exists('id', $timeline) || !is_numeric($timeline['id'])) {
$newChild = wp_insert_post([
- 'post_author' => $this->user_id,
- 'post_type' => jvbCheckBase($post_data['content']),
- 'post_title' => $allowedFields['post_title'],
- 'post_parent' => $parent_id,
- 'menu_order' => $order
+ 'post_author' => $this->user_id,
+ 'post_type' => jvbCheckBase($post_data['content']),
+ 'post_title' => $allowedFields['post_title'],
+ 'post_parent' => $parent_id,
+ 'menu_order' => $order,
+ 'post_status' => $parent_is_published ? 'publish' : 'draft'
]);
if (!$newChild || is_wp_error($newChild)) {
$errors[] = [
- 'message' => 'Could not create child post',
- 'data' => $timeline
+ 'message' => 'Could not create child post',
+ 'data' => $timeline
];
continue;
}
@@ -524,42 +641,98 @@
unset($existing_children[array_search((int)$timeline['id'], $existing_children)]);
}
- //Determine which fields to update
- $meta = new MetaManager($timeline['id'], 'post');
- $oldValues = $meta->getAll(array_keys($allowedFields));
- $updateValues = array_filter($allowedFields, function($value, $key) use ($oldValues) {
- return (!array_key_exists($key, $oldValues) || $value !== $oldValues[$key]);
- }, ARRAY_FILTER_USE_BOTH);
- $meta->setAll($updateValues);
- //Update Menu Order, if applicable
- if ((int) $timeline['id'] !== $parent_id) {
- $post = get_post((int) $timeline['id']);
- if ($post && $post->menu_order !== $order) {
- $updated = wp_update_post([
- 'ID' => $post->ID,
- 'menu_order' => $order,
- ]);
- if (!$updated || is_wp_error($updated)) {
- $errors[] = [
- 'message' => 'Could not update timeline order for post',
- 'data' => $timeline
- ];
+ // Update post status and menu order
+ $post_updates = ['ID' => $timeline['id']];
+
+ if (!$is_parent) {
+ $post_updates['menu_order'] = $order;
+
+ // Auto-publish child if parent is published
+ if ($parent_is_published) {
+ $current_post = get_post($timeline['id']);
+ if ($current_post && $current_post->post_status !== 'publish') {
+ $post_updates['post_status'] = 'publish';
}
}
}
+
+ if (count($post_updates) > 1) {
+ $result = wp_update_post($post_updates);
+ error_log('Updated post '.$timeline['id'].' with: '.print_r($post_updates, true).' Result: '.$result);
+ $clearParent = true;
+ }
+
+ // Update metadata
+ $meta = new MetaManager($timeline['id'], 'post');
+ $oldValues = $meta->getAll(array_keys($allowedFields));
+
+ // Set number taxonomy to menu_order (always update for reordering)
+ if (!$is_parent) {
+ $number_value = $order;
+ $term = get_term_by('name', (string)$number_value, BASE.'number');
+ if (!$term) {
+ $result = wp_insert_term((string)$number_value, BASE.'number');
+ if ($result && !is_wp_error($result)) {
+ $term = $result['term_id'];
+ }
+ } else {
+ $term = $term->term_id;
+ }
+ $allowedFields['number'] = $term;
+ }
+
+ // Auto-timeline logic
+ if ($prevDate) {
+ $newDate = array_key_exists('date', $oldValues) ? $oldValues['date'] : ((array_key_exists('date', $allowedFields)) ? $allowedFields['date'] : null);
+ if ($newDate) {
+ $date1 = new \DateTime($prevDate);
+ $date2 = new \DateTime($newDate);
+ $weeks = floor($date1->diff($date2)->days / 7);
+ if ($weeks > 0) {
+ $termToCheck = $weeks.' Weeks';
+ $term = get_term_by('name', $termToCheck, BASE.'timeline');
+ if (!$term) {
+ $result = wp_insert_term($termToCheck, BASE.'timeline');
+ if ($result && !is_wp_error($result)) {
+ $term = $result['term_id'];
+ }
+ } else {
+ $term = $term->term_id;
+ }
+ $allowedFields['timeline'] = $term;
+ }
+ }
+ }
+ $prevDate = array_key_exists('date', $oldValues) ? $oldValues['date'] : ((array_key_exists('date', $allowedFields)) ? $allowedFields['date'] : $prevDate);
+
+ $updateValues = array_filter($allowedFields, function($value, $key) use ($oldValues) {
+ return (!array_key_exists($key, $oldValues) || $value !== $oldValues[$key]);
+ }, ARRAY_FILTER_USE_BOTH);
+ error_log('Setting values for '.$timeline['id'].': '.print_r($updateValues, true));
+
+ $meta->setAll($updateValues);
+ $timeline['id'] = (int) $timeline['id'];
+
$success[] = $timeline['id'];
}
}
- //Delete any remaining children that no longer exist
+
+ // Delete any remaining children that no longer exist
if (!empty($existing_children)) {
foreach ($existing_children as $ID) {
wp_delete_post($ID);
}
}
+ if ($clearParent) {
+ $this->cache->clear();
+ CacheManager::onPostSave($parent_id, $parent_post);
+ }
+
+
return ['success' => true, 'data' => [
- 'success' => $success,
- 'errors' => $errors
+ 'success' => $success,
+ 'errors' => $errors
]];
}
@@ -650,6 +823,7 @@
$this->meta = new MetaManager($post->ID, 'post');
$data = [
'id' => $post->ID,
+ 'title' => $post->post_title,
'status' => $post->post_status,
'date' => $post->post_date,
'modified' => $post->post_modified,
@@ -711,7 +885,7 @@
return $images;
}
- protected function formatTimeline(WP_Post $post):array
+ public function formatTimeline(WP_Post $post):array
{
$item = $this->prepareItem($post, true, false);
//Step 1: Get the fields that apply to all posts
@@ -719,7 +893,7 @@
$item['fields'] = $mainMeta->getAll($this->timelineSharedFields);
//Step 2: Get the fields for each individual posts
- $children = get_children(['post_parent' => $post->ID, 'orderby' => 'menu_order', 'post_status' => ['publish', 'draft'], 'fields'=> 'ids']);
+ $children = get_children(['post_parent' => $post->ID, 'orderby' => 'date', 'order' => 'ASC', 'post_status' => ['publish', 'draft'], 'fields'=> 'ids']);
array_unshift($children, $post->ID);
$subFields = [];
@@ -728,7 +902,7 @@
$meta = new MetaManager($child, 'post');
$f = $meta->getAll($this->timelineUniqueFields);
$f = ['id' => $child] + $f;
- $subFields[$f['post_thumbnail']] = $f;
+ $subFields[] = $f;
$images[$f['post_thumbnail']] = jvbImageData((int) $f['post_thumbnail']);
}
--
Gitblit v1.10.0