From b38f03c0e7218762d90fa5092696b127f24f36db Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 25 Jan 2026 07:07:26 +0000
Subject: [PATCH] =Some logical flaws in Queue.php, Queue.js, ContentExecutor.php, UploadExecutor.php - particularly with timeline ordering, frontend queue updates, etc
---
inc/rest/routes/FeedRoutes.php | 293 +++++++++++++++++++++++++++++++---------------------------
1 files changed, 156 insertions(+), 137 deletions(-)
diff --git a/inc/rest/routes/FeedRoutes.php b/inc/rest/routes/FeedRoutes.php
index 92375c2..2c83a63 100644
--- a/inc/rest/routes/FeedRoutes.php
+++ b/inc/rest/routes/FeedRoutes.php
@@ -1,7 +1,7 @@
<?php
namespace JVBase\rest\routes;
-use JVBase\managers\CacheManager;
+use JVBase\managers\Cache;
use JVBase\rest\RestRouteManager;
use JVBase\integrations\Umami;
use JVBase\meta\MetaManager;
@@ -32,39 +32,24 @@
$this->cache_name = 'feed';
$this->cache_ttl = 86400;
parent::__construct();
- $this->cache->clear();
+ $this->cache
+ ->connect('post')
+ ->connect('taxonomy')
+ ->connect('user');
+
+ if (JVB_TESTING) {
+ $this->cache->flush();
+ }
+
}
public function init():void
{
- $this->cache->clear();
$this->checker = Checker::getInstance();
- if (jvbSiteUsesUmami()) {
+ if (Features::hasIntegration('umami')) {
$this->tracker = JVB()->connect('umami');
}
- $this->setupCacheConnections();
- }
-
- /**
- * Set up cache connections for automatic invalidation
- */
- protected function setupCacheConnections(): void
- {
- // Connect to all content types with show_feed
- $contentTypes = Features::getTypesWithFeature('show_feed', 'content');
- foreach ($contentTypes as $type) {
- CacheManager::for('feed_item_'.$type)->connectTo('post');
- $this->cache->connectTo('post', $type);
- }
-
- // Connect to all taxonomies with show_feed
- $taxonomies = Features::getTypesWithFeature('show_feed', 'taxonomy');
- foreach ($taxonomies as $tax) {
- CacheManager::for('feed_item_'.$tax)->connectTo('taxonomy');
- $this->cache->connectTo('taxonomy', $tax);
- }
-
}
/**
@@ -99,21 +84,20 @@
$post = get_post($postID);
$type = jvbNoBase($post->post_type);
$metaType = 'post';
- $cache = CacheManager::for('feed_item_'.$type);
break;
default:
$post = get_term($postID, jvbCheckBase($type));
$type = jvbNoBase($type);
$metaType = 'term';
- $cache = CacheManager::for('feed_item_'.$type);
break;
}
if (!$post || is_wp_error($post)) {
return [];
}
-//
-// return $cache->remember($postID,
-// function() use ($postID, $type, $metaType, $post, $skip) {
+
+ return $this->cache->remember(
+ $postID,
+ function() use ($postID, $type, $metaType, $post, $skip) {
$config = null;
switch ($metaType) {
case 'post':
@@ -146,33 +130,7 @@
];
//Format Taxonomies
- $temp = array_filter($fields, function($field) {
- return $field['type'] === 'taxonomy';
- });
- foreach ($temp as $key => $config) {
- if (array_key_exists($key, $out['fields']) && $out['fields'][$key] !== '') {
- $IDs = array_map('absint', explode(',', $out['fields'][$key]));
- $data = [];
- $icon = JVB_TAXONOMY[$config['taxonomy']]['icon']??jvbDefaultIcon();
- foreach ($IDs as $ID) {
- $term = get_term($ID, jvbCheckBase($config['taxonomy']));
- if ($term && !is_wp_error($term)) {
- $data[$ID] = [
- 'id' => $ID,
- 'icon' => $icon,
- 'name' => $term->name,
- 'url' => get_term_link($ID, jvbCheckBase($config['taxonomy'])),
- ];
- if ($this->tracker) {
- $data[$ID]['umami_click'] = $this->tracker->trackClick($ID, $config['taxonomy'], ['from' => $type.'_'.$postID]);
- }
- }
- }
- if (!empty($data)) {
- $out['fields'][$key] = $data;
- }
- }
- }
+ $out['taxonomies'] = $this->extractTaxonomies($values, $postID, $type);
//Add images
$imgIDs = [];
@@ -208,17 +166,19 @@
$out['user_id'] = $owner;
}
$out['url'] = get_term_link($postID, $type);
+ $out['title'] = html_entity_decode($post->name);
break;
case 'post':
$out['date'] = $post->post_date;
+ $out['modified'] = $post->post_modified;
$out['user_id'] = (int)$post->post_author;
$out['url'] = get_the_permalink($postID);
+ $out['title']= get_the_title($postID);
break;
}
-// return $out;
-// }
-// );
- return $out;
+ return $out;
+ }
+ );
}
@@ -263,6 +223,8 @@
$children = get_children(['post_parent' => $post->ID, 'orderby' => 'date', 'order' => 'ASC', 'post_status' => ['publish'], 'fields'=> 'ids']);
array_unshift($children, $post->ID);
+ $item['taxonomies'] = $this->extractTaxonomies($item['fields'], $postID, jvbNoBase($post->post_type));
+
$subFields = [];
$images = [];
foreach ($children as $child) {
@@ -270,41 +232,91 @@
$f = $meta->getAll($this->timelineUniqueFields);
$f = ['id' => $child] + $f;
$subFields[] = $f;
-
+ $item['taxonomies'] = array_merge($item['taxonomies'], $this->extractTaxonomies($f, $postID, jvbNoBase($post->post_type)));
$images[$f['post_thumbnail']] = jvbImageData((int) $f['post_thumbnail']);
}
- $item['fields']['order'] = $subFields;
+ $item['number'] = (int)get_post_meta($post->ID,BASE.'number', true);
+ $item['fields']['before'] = get_post_thumbnail_id($children[0]);
+ $item['fields']['after'] = get_post_thumbnail_id($children[array_key_last($children)]);
+
+ $item['fields']['timeline'] = $subFields;
$item['images'] = $item['images'] + $images;
+
return $item;
}
+ protected function extractTaxonomies(array $fields, int $postID, string $content):array {
+ $taxonomies = [];
+ foreach ($fields as $key => $value) {
+ if (empty($value)) {
+ continue;
+ }
+ if (!array_key_exists($key, JVB_TAXONOMY)) {
+ continue;
+ }
- protected function formatTaxonomy(WP_Term $term, int $postID, string $type)
+ $taxConfig = JVB_TAXONOMY[$key];
+ if (isset($taxConfig['public']) && $taxConfig['public'] === false) {
+ continue;
+ }
+ $terms = array_map('absint', explode(',', $value));
+ $terms = array_filter($terms); // Remove 0 values
+
+ if (empty($terms)) {
+ continue;
+ }
+ foreach($terms as $termID) {
+ $term = get_term($termID, jvbCheckBase($key));
+ if ($term && !is_wp_error($term)) {
+ $taxonomies[$key][$termID] = $this->formatTaxonomy($term, $postID, $content);
+ }
+ }
+ }
+ return $taxonomies;
+ }
+
+ protected function formatTaxonomy(WP_Term|int $term, int $postID, string $type)
{
- return [
- 'ID' => $term->term_id,
- 'title' => htmlspecialchars_decode($term->name),
- 'url' => get_term_link($term->term_id, $term->taxonomy),
- 'umami_click' => $this->tracker->trackTaxonomyClick($term->term_id, $term->taxonomy, [
- 'from' => $type . '_' . $postID
- ])
- ];
+ return $this->cache->remember(
+ $term->term_id,
+ function () use ($term, $postID, $type) {
+ $base = [
+ 'ID' => $term->term_id,
+ 'title' => html_entity_decode($term->name),
+ 'url' => get_term_link($term->term_id, $term->taxonomy),
+ ];
+ if ($this->tracker) {
+ $base['umami_click'] =$this->tracker->trackTaxonomyClick($term->term_id, $term->taxonomy, [
+ 'from' => $type . '_' . $postID
+ ]);
+ }
+ return $base;
+ }
+ );
}
protected function getAuthorData(WP_Post $post)
{
- $author = $this->cache->get($post->post_author, 'author_data');
- if (!$author) {
- $author = [
- 'id' => $post->post_author,
- 'label' => 'Artist',
- 'value' => get_the_author_meta('display_name', $post->post_author),
- 'icon' => 'artist',
- 'url' => get_the_permalink(get_user_meta($post->post_author, BASE . 'link', true)),
- ];
- $this->cache->set($post->post_author, $author, 'author_data');
- }
- return $author;
+ $author = $post->post_author;
+ $userLink = get_user_meta($author, BASE.'link', true);
+ return $this->cache->remember(
+ $userLink,
+ function () use ($userLink, $author) {
+ $label = jvbUserRole($author);
+ if (array_key_exists($label, JVB_USER)) {
+ $label = JVB_USER[$label]['label'];
+ } else {
+ $label = 'Artist';
+ }
+ return [
+ 'id' => $userLink,
+ 'label' => $label,
+ 'value' => get_the_title($userLink),
+ 'icon' => 'user',
+ 'url' => get_the_permalink($userLink),
+ ];
+ }
+ );
}
protected function getTaxonomies(int $postID, string $content): array
@@ -320,16 +332,23 @@
'icon' => $config,
'title' => JVB_TAXONOMY[$config]['plural'],
'terms' => array_map(function ($term) use ($tax, $postID, $content) {
- return [
- 'ID' => $term->term_id,
- 'title' => htmlspecialchars_decode($term->name),
- 'url' => get_term_link($term->term_id, $tax),
- 'umami_click' => $this->tracker->trackTaxonomyClick($term->term_id, $tax, [
- 'from' => $content . '_' . $postID
- ])
- ];
+ $item = $this->cache->remember(
+ $term->term_id,
+ function() use ($term, $tax, $content, $postID) {
+ return [
+ 'ID' => $term->term_id,
+ 'title' => html_entity_decode($term->name),
+ 'url' => get_term_link($term->term_id, $tax),
+ ];
+ }
+ );
+ $item['umami_click'] = $this->tracker->trackTaxonomyClick($term->term_id, $tax, [
+ 'from' => $content.'_'.$postID
+ ]);
+ return $item;
}, $terms),
];
+
}
}
return $out;
@@ -363,47 +382,46 @@
$args = $this->applyOrderFilters($args, $data);
$args = $this->applyDateFilters($args, $data);
- $args = $this->applyFavouritesFilter($args, $data);
- return $args;
+ return $this->applyFavouritesFilter($args, $data);
}
- protected function applyTaxonomyFilters(array $args, array $data): array
- {
- if (!isset($data['taxonomy']) || empty($data['taxonomy'])) {
- return $args;
- }
-
- $taxonomyFilters = $data['taxonomy'];
-
- // Validate taxonomies exist and sanitize
- $validFilters = [];
- foreach ($taxonomyFilters as $taxonomy => $terms) {
- if (!taxonomy_exists(jvbCheckBase($taxonomy))) {
- continue;
- }
-
- $validFilters[] = [
- 'taxonomy' => jvbCheckBase($taxonomy),
- 'field' => 'term_id',
- 'terms' => array_map('absint', (array)$terms),
- 'operator' => 'IN'
- ];
- }
-
- if (empty($validFilters)) {
- return $args;
- }
-
- // Determine relation based on match filter
- $relation = ($data['match'] ?? 'all') === 'all' ? 'AND' : 'OR';
-
- $args['tax_query'] = array_merge(
- ['relation' => $relation],
- $validFilters
- );
-
- return $args;
- }
+// protected function applyTaxonomyFilters(array $args, array $data): array
+// {
+// if (!array_key_exists('taxonomy', $data) || empty($data['taxonomy'])) {
+// return $args;
+// }
+//
+// $taxonomyFilters = $data['taxonomy'];
+//
+// // Validate taxonomies exist and sanitize
+// $validFilters = [];
+// foreach ($taxonomyFilters as $taxonomy => $terms) {
+// if (!taxonomy_exists(jvbCheckBase($taxonomy))) {
+// continue;
+// }
+//
+// $validFilters[] = [
+// 'taxonomy' => jvbCheckBase($taxonomy),
+// 'field' => 'term_id',
+// 'terms' => array_map('absint', (array)$terms),
+// 'operator' => 'IN'
+// ];
+// }
+//
+// if (empty($validFilters)) {
+// return $args;
+// }
+//
+// // Determine relation based on match filter
+// $relation = ($data['match'] ?? 'all') === 'all' ? 'AND' : 'OR';
+//
+// $args['tax_query'] = array_merge(
+// ['relation' => $relation],
+// $validFilters
+// );
+//
+// return $args;
+// }
/**
* @param WP_REST_Request $request
@@ -413,19 +431,17 @@
public function handleFeedRequest(WP_REST_Request $request): WP_REST_Response
{
$args = $this->buildRequestArgs($request);
- $cacheContext = $this->buildCacheContext($args, $request);
+ $key = $this->cache->generateKey($args);
// Check HTTP cache headers first
$cache_check = $this->checkHeaders(
$request,
- $cacheContext['content_types'],
- $cacheContext['additional_params']
+ $key
);
if ($cache_check) {
return $cache_check; // Returns 304 Not Modified
}
- $key = $this->cache->generateKey($args);
$cached = $this->cache->get($key);
if ($cached) {
if ($request->get_param('highlight')) {
@@ -439,7 +455,7 @@
// Fetch and format items
$items = $this->fetchFeedItems($args);
- $ttl = (str_contains($args['orderby'], 'RAND')) ? 1800 : $this->cache_ttl;
+ $ttl = (str_contains($args['orderby'], 'RAND')) ? 300 : $this->cache_ttl;
$this->cache->set($key, $items, $ttl);
if ($request->get_param('highlight')) {
@@ -1243,6 +1259,7 @@
// Get content types with show_feed
$contentTypes = Features::getTypesWithFeature('show_feed', 'content');
foreach ($contentTypes as $slug) {
+ $this->cache->tag('content:'.$slug);
$contentConfig = JVB_CONTENT[$slug] ?? null;
if (!$contentConfig) continue;
@@ -1263,6 +1280,8 @@
continue;
}
+ $this->cache->tag('taxonomy:'.$slug);
+
$config[$slug] = [
'type' => 'taxonomy',
'singular' => $taxConfig['singular'] ?? ucfirst($slug),
--
Gitblit v1.10.0