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/rest/routes/ContentRoutes.php | 1178 +++++++++++++++++++++++++++-------------------------------
1 files changed, 540 insertions(+), 638 deletions(-)
diff --git a/inc/rest/routes/ContentRoutes.php b/inc/rest/routes/ContentRoutes.php
index 6916093..7d5ef42 100644
--- a/inc/rest/routes/ContentRoutes.php
+++ b/inc/rest/routes/ContentRoutes.php
@@ -1,722 +1,624 @@
<?php
+
namespace JVBase\rest\routes;
-use JVBase\JVB;
-use JVBase\rest\RestRouteManager;
-use JVBase\managers\CacheManager;
-use JVBase\meta\MetaManager;
+use JVBase\Instance;
+use JVBase\managers\Cache;
+use JVBase\managers\queue\executors\ContentExecutor;
+use JVBase\managers\queue\Queue;
+use JVBase\managers\queue\TypeConfig;
+use JVBase\meta\Meta;
+use JVBase\registrar\Registrar;
+use JVBase\rest\PermissionHandler;
+use JVBase\rest\Response;
+use JVBase\rest\Rest;
+use JVBase\rest\Route;
+use WP_Post;
use WP_Query;
-use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
-use Exception;
+use WP_Term;
+use WP_Term_Query;
if (!defined('ABSPATH')) {
- exit; // Exit if accessed directly
+ exit; // Exit if accessed directly
}
-class ContentRoutes extends RestRouteManager
+class ContentRoutes extends Rest
{
- protected array $fields = [];
- protected array $taxonomies = [];
- protected MetaManager $meta;
- protected string $post_type = '';
- protected string $user_id = '';
+ use Instance;
+ protected array $fields = [];
+ protected array $taxonomies = [];
+ protected string $post_type = '';
+ protected string $user_id = '';
- //TODO: Ensure we are handling the bulk operations for all processes
- //TODO: be sure to clear cache ($this->>cache->invalidateGroup($this->>cache_name)) on content update/create
- //TODO: Also invalidate feed caches on updates!!
+ //For Timeline-specific posts
+ protected array $timelineSharedFields = [];
+ protected array $timelineUniqueFields = [];
+ protected static ?string $action = 'dash-';
+ protected Meta $meta;
+ protected Cache $termCache;
- public function __construct()
- {
- $this->cache_name = 'user_content_'.get_current_user_id();
- parent::__construct();
- $this->action = 'dash-';
- $this->operation_type = 'content_update';
- add_filter(BASE.'handle_bulk_operation', [$this, 'processOperation'], 10, 3);
- }
-
- /**
- * Registers content routes
- * @return void
- */
- public function registerRoutes():void
- {
- // Base content endpoint
- register_rest_route($this->namespace, "/content", [
- [
- 'methods' => 'GET',
- 'callback' => [$this, 'handleContentRequest'],
- 'permission_callback' => [$this, 'checkPermission'],
- ],
- [
- 'methods' => 'POST',
- 'callback' => [$this, 'handleContentUpdate'],
- 'permission_callback' => [$this, 'checkPermission']
- ]
- ]);
-
- //TODO: consolidate create/batch in with create? I don't think we are ever creating a single item
- register_rest_route($this->namespace, "/create", [
- [
- 'methods' => 'POST',
- 'callback' => [$this, 'handleContentCreate'],
- 'permission_callback' => [$this, 'checkPermission']
- ]
- ]);
- register_rest_route($this->namespace, "/create/batch", [
- [
- 'methods' => 'POST',
- 'callback' => [$this, 'handleBatchCreation'],
- 'permission_callback' => [$this, 'checkPermission']
- ]
- ]);
- }
-
- /**
- * Handle content update/creation
- * @param WP_REST_Request $request
- *
- * @return WP_REST_Response
- */
- public function handleContentUpdate(WP_REST_Request$request):WP_REST_Response
- {
- $data = $request->get_params();
- error_log('Received data: '.print_r($data, true));
- $user_id = $data['user'];
+ public function __construct()
+ {
+ $this->cacheName = 'user_content';
+ parent::__construct();
+ $this->cache = Cache::for($this->cacheName, 'post', DAY_IN_SECONDS);
+ $this->cache->user();
+ $this->termCache = Cache::for($this->cacheName.'_terms', 'term', DAY_IN_SECONDS);
+ $this->termCache->user();
- if (!isset($data['posts']) || !is_array($data['posts'])) {
- return new WP_REST_Response([
- 'success' => false,
- 'message' =>'Invalid request format'
- ]);
- }
+ if (JVB_TESTING) {
+ $this->cache->flush();
+ }
+ add_action('init', [$this, 'registerContentExecutors'], 5);
+ }
- $count = count($data['posts']);
- $operationId = $data['id'];
- unset($data['user']);
- unset($data['id']);
+ /**
+ * Register content operation types with the queue's TypeRegistry
+ */
+ public function registerContentExecutors(): void
+ {
+ $registry = Queue::getInstance()->registry();
+ $executor = new ContentExecutor();
- $queue = JVB()->queue();
- $queue->queueOperation(
- 'content_update',
- $user_id,
- $data,
- [
- 'count' => $count,
- 'chunk_key' => 'posts',
- 'chunk_size' => 10,
- 'operation_id' => $operationId
- ]
- );
- return new WP_REST_Response([
- 'success' => true,
- 'message' => 'Queued for processing',
- 'operation' => $operationId
- ]);
- }
+ // Content updates - chunked at 10 posts
+ $registry->register('content_update', new TypeConfig(
+ executor: $executor,
+ chunkKey: 'posts',
+ chunkSize: 10
+ ));
- /**
- * Handle content creation
- * @param WP_REST_Request $request
- *
- * @return WP_REST_Response
- */
- public function handleContentCreate(WP_REST_Request$request):WP_REST_Response
- {
- $data = $request->get_json_params();
- $user_id = $data['user'];
+ // Batch creation (from uploads) TODO: I believe this is all handled by UploadExecutor
+// $registry->register('batch_creation', new TypeConfig(
+// executor: $executor
+// ));
+ }
- if (!isset($data['posts']) || !is_array($data['posts'])) {
- return new WP_REST_Response([
- 'success' => false,
- 'message' => 'Invalid request format'
- ]);
- }
+ /**
+ * Registers content routes
+ * @return void
+ */
+ public function registerRoutes(): void
+ {
+ Route::for('content')
+ ->get([$this, 'getContent'])
+ ->auth(PermissionHandler::combine(['user', 'nonce', ['actionNonce'=>'dash-']]))
+ ->args([
+ 'content' => 'string|required',
+ 'status' => 'string|default:all',
+ 'page' => 'integer|default:1|min:1',
+ 'per_page' => 'integer|default:30|min:1|max:100',
+ 'orderby' => 'string|enum:date,alphabetical|default:date',
+ 'order' => 'string|enum:asc,desc|default:desc',
+ 'search' => 'string',
+ 'date-filter' => 'string',
+ 'dateFrom' => 'string',
+ 'dateTo' => 'string',
+ ])
+ ->rateLimit(30)
+ ->post([$this, 'postContent'])
+ ->auth(PermissionHandler::combine(['user', 'nonce', ['actionNonce'=>'dash-']]))
+ ->rateLimit()
+ ->args([
+ 'posts' => 'required',
+ 'content' => 'string',
+ ])
+ ->register();
+ }
- $count = count($data['posts']);
- $operationId = $data['id'];
- unset($data['user']);
- unset($data['id']);
- JVB()->queue()->queueOperation(
- 'batch_creation',
- $user_id,
- $data,
- [
- 'count' => $count,
- 'operation_id' => $operationId,
- ]
- );
+ protected function initTimelineFields(string $content): void
+ {
+ $content = jvbNoBase($content);
- return new WP_REST_Response([
- 'success' => true,
- 'message' => 'Queued for processing',
- 'operation' => $operationId
- ]);
- }
+ $config = Registrar::getInstance($content);
+ if (!$config || !$config->hasFeature('is_timeline')) {
+ return;
+ }
+ $this->fields = $config->getFields();
+
+ $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);
+ $registrar = Registrar::getInstance($content);
+ if (!$registrar || !$registrar->hasFeature('is_timeline')) {
+ return [];
+ }
+
+ $allFields = $registrar->getFields();
+
+ return array_keys(array_filter($allFields, function ($field) {
+ if (array_key_exists('for_all', $field) && $field['for_all'] === true) {
+ return true;
+ }
+ return false;
+ }));
+ }
+
+ public function getTimelineSharedFields(string $content): array
+ {
+ $content = jvbNoBase($content);
+ $registrar = Registrar::getInstance($content);
+ if (!$registrar || !$registrar->hasFeature('is_timeline')) {
+ return [];
+ }
+
+ $allFields = $registrar->getFields()??[];
+
+ return array_keys(array_filter($allFields, function ($field) {
+ if (!array_key_exists('for_all', $field) || is_null($field['for_all']) || $field['for_all'] === false) {
+ return true;
+ }
+ return false;
+ }));
+ }
+
+ /**
+ * Handle content update/creation
+ * @param WP_REST_Request $request
+ *
+ * @return WP_REST_Response
+ */
+ public function postContent(WP_REST_Request $request): WP_REST_Response
+ {
+ $data = $request->get_params();
+ $user_id = get_current_user_id();
+
+ if (!array_key_exists('posts', $data) || !is_array($data['posts'])) {
+ return Response::success(['message'=>'No posts found in request']);
+ }
- /**
- * Handle request
- * @param WP_REST_Request $request
- *
- * @return WP_REST_Response
- */
- public function handleContentRequest(WP_REST_Request $request):WP_REST_Response
- {
- $params = $request->get_params();
- error_log('handleContentRequest params: '.print_r($params, true));
+ $count = count($data['posts']);
+ $operationId = $data['id'];
+ unset($data['id']);
- error_log('Fetching content. Params: '.print_r($params, true));
- $user_id = $params['user'];
- if (!$this->userCheck($user_id)) {
- return new WP_REST_Response([
- 'success' => false,
- 'message' => 'User does not match up. Are you a bot?',
- ]);
- }
+ error_log('[CONTENT]:'.print_r($data, true));
+ $queue = Queue::getInstance();
+ $queue->queueOperation(
+ 'content_update',
+ $user_id,
+ $data,
+ [
+ 'operation_id' => $operationId
+ ]
+ );
- $post_status = $params['status'];
- if ($post_status === 'all') {
- $post_status = ['publish', 'draft'];
- } else {
- $post_status = explode(',', $post_status);
- }
- $post_type = str_replace('-', '_',jvbCheckBase($params['content']));
-
- $config = (array_key_exists($params['content'], JVB_CONTENT) && !empty(JVB_CONTENT[$params['content']])) ? JVB_CONTENT[$params['content']] : [];
+ return Response::queued($operationId);
+ }
+ /**
+ * Handle request
+ * @param WP_REST_Request $request
+ *
+ * @return WP_REST_Response
+ */
+ public function getContent(WP_REST_Request $request): WP_REST_Response
+ {
+ $params = $request->get_params();
+ error_log('getContent::params '.print_r($params, true));
- // Build query args
- $args = [
- 'post_type' => $post_type,
- 'posts_per_page' => $params['per_page']??30,
- 'paged' => $params['page'],
- 'orderby' => 'date',
- 'order' => 'DESC',
- 'author' => $user_id,
- 'post_status' => $post_status
- ];
+ $registrar = Registrar::getInstance($params['content']);
+ switch ($registrar->getType()) {
+ case 'term':
+ return $this->getTerms($request, $params, $registrar);
+ case 'user':
+ //TODO maybe do something?
+ break;
+ case 'post':
+ return $this->getPosts($request, $params, $registrar);
+ }
+
+ return $this->error('Something went wrong, this does not appear to have a proper content type');
+ }
+
+ public function getPosts(WP_REST_Request $request, array $params, Registrar $registrar):WP_REST_Response
+ {
+ $user_id = $params['user'];
+
+ $post_status = $params['status'];
+ if ($post_status === 'all') {
+ $post_status = ['publish', 'draft'];
+ } else {
+ $post_status = explode(',', $post_status);
+ }
+ $post_type = str_replace('-', '_', jvbCheckBase($params['content']));
+
+ // Build query args
+ $args = [
+ 'post_type' => $post_type,
+ 'posts_per_page' => $params['per_page'] ?? 30,
+ 'paged' => $params['page'],
+ 'orderby' => 'date',
+ 'order' => 'DESC',
+ 'author' => $user_id,
+ 'post_status' => $post_status
+ ];
+
+
+ //Only top level posts for timeline types
+ if ($registrar?->hasFeature('is_timeline')) {
+ $args['post_parent'] = 0;
+ }
//Calendar filters
- if (jvbCheck('is_calendar', $config)) {
+ if ($registrar?->hasFeature('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);
}
- if (array_key_exists('date', $params) && !empty($params['date'])) {
+ if (array_key_exists('date-filter', $params) || array_key_exists('dateFrom', $params)) {
$args = $this->applyDateFilters($args, $params);
}
if (array_key_exists('orderby', $params) || array_key_exists('order', $params)) {
$args = $this->applyOrderFilters($args, $params);
}
- if (!empty($params['search'])) {
+ if (array_key_exists('search', $params)) {
$args['s'] = sanitize_text_field($params['search']);
}
- error_log('Content Routes final args: '.print_r($args, true));
-
- $key = $this->cache->generateKey($args);
- $lastModified = $this->cache->getTimestamp($key);
- if ($lastModified !== false) {
- $headerCheck = $this->ifModifiedSince($lastModified, $args, $request);
- if (!is_null($headerCheck)) {
- return $headerCheck;
- }
- } else {
- // No timestamp yet, but we can still set ETag
- $etag = '"' . md5(serialize($args)) . '"';
- header('ETag: ' . $etag);
- header('Cache-Control: private, max-age=30');
+ $key = $this->cache->generateKey($args);
+ $cached = $this->cache->get($key);
+ if ($cached) {
+ return $cached;
}
+ $this->post_type = jvbCheckBase($params['content'] ?? $params['type']);
- $cache = $this->cache->get($key);
- $cache = false;
- if ($cache) {
- return new WP_REST_Response($cache);
- }
+ if (array_key_exists('s', $args)) {
+ $args = $this->applySearchFilters($args, $params);
+ }
- // Run query
- $query = new WP_Query($args);
+ // Run query
+ $query = new WP_Query($args);
- $this->post_type = $params['content']??$params['type'];
+ $registrar = Registrar::getInstance($this->post_type);
+ $this->fields = $registrar->getFields()??[];
+ $this->taxonomies = $this->getTaxonomies($this->post_type);
- $this->fields = jvbGetFields(str_replace('-','_',$this->post_type));
- $this->taxonomies = $this->getTaxonomies($this->post_type);
- $posts = array_map([$this, 'prepareItem'], $query->posts);
+ $posts = array_map([$this, 'preparePost'], $query->posts);
+
+ $data = [
+ 'items' => $posts,
+ 'total' => $query->found_posts,
+ 'total_pages' => $query->max_num_pages,
+ 'has_more' => $args['paged']??1 < $query->max_num_pages,
+ ];
- $data = [
- 'items' => $posts,
- 'total' => $query->found_posts,
- 'total_pages' => $query->max_num_pages
- ];
+ $this->cache->set($key, $data);
+ return Response::success($data);
+ }
+ public function getTerms(WP_REST_Request $request, array $params, Registrar $registrar):WP_REST_Response
+ {
+ // Build query args
+ $args = [
+ 'taxonomy' => jvbCheckBase($params['content']),
+ 'number' => $params['per_page'] ?? 30,
+ 'orderby' => 'name',
+ 'order' => 'DESC',
+ 'hide_empty' => false,
+ ];
+ $paged = $params['page']??1;
+ $args['page'] = $paged;
+ if ($paged > 1) {
+ $args['offset'] = ($paged-1) * $args['number'];
+ }
- $this->cache->set($key, $data);
+ //TODO
+// if (array_key_exists('taxonomies', $params)) {
+// $args = $this->applyTaxonomyFilters($args, $params);
+// }
+// if (array_key_exists('date-filter', $params) || array_key_exists('dateFrom', $params)) {
+// $args = $this->applyDateFilters($args, $params);
+// }
+ if (array_key_exists('orderby', $params) || array_key_exists('order', $params)) {
+ $args = $this->applyOrderFilters($args, $params);
+ }
- return new WP_REST_Response($data);
- }
+ if (array_key_exists('search', $params)) {
+ $args['s'] = sanitize_text_field($params['search']);
+ }
- /**
- * Gets allowed taxonomies for a particular content
- * @param string $content
- *
- * @return array
- */
- protected function getTaxonomies(string $content):array
- {
- $taxonomy_for = jvbGlobalTaxonomyFor();
- $out = [];
- foreach ($taxonomy_for as $tax => $postTypes) {
- if (in_array($content, $postTypes)) {
- $out[BASE.$tax] = [
- 'label' => JVB_CONTENT[$content]['plural'],
- 'icon' => $tax,
- ];
- }
- }
- return $out;
- }
+ $key = $this->cache->generateKey($args);
+ // Check HTTP cache headers with the specific content type
+// $cache_check = $this->checkHeaders($request, $key);
+// if ($cache_check) {
+// return $cache_check;
+// }
- /**
- * Processes operation from queue
- * @param object $operation
- * @param array $data
- *
- * @return array
- */
- protected function processBatches(object $operation, array $data):array
- {
- $this->user_id = $operation->user_id;
- $posts = $data['posts'];
+ $cache = $this->cache->get($key);
+ if ($cache) {
+ return Response::success($cache);
+ }
+ $this->post_type = jvbCheckBase($params['content'] ?? $params['type']);
+ // Only expand search to taxonomies if we're actually going to query
+ if (array_key_exists('s', $args)) {
+ $args = $this->applySearchFilters($args, $params);
+ }
- if (empty($posts)) {
- return [
- 'success' => false,
- 'message' => 'No posts to update'
- ];
- }
+ // Run query
+ $query = new WP_Term_Query($args);
- $results = [];
+ $terms = $query->get_terms();
+ $data = [
+ 'total' => 0,
+ 'total_pages' => 0,
+ 'has_more' => false
+ ];
- foreach ($posts as $ID => $post_data) {
- if (str_starts_with($ID, 'new')) {
+ if (!is_wp_error($terms) && !empty($terms))
+ {
+ $total = get_terms([
+ 'taxonomy' => $args['taxonomy'],
+ 'hide_empty' => false,
+ 'fields' => 'count'
+ ]);
+ $data['total'] = $total;
+ $data['total_pages'] = max($total/$args['number'], 1);
+ $data['has_more'] = ($args['page'] * $args['number']) < $total;
+ } else {
+ $terms = [];
+ }
- error_log('New post detected. Creating... with: '.print_r([
- 'post_author' => $this->user_id,
- 'post_type' => jvbCheckBase($post_data['content']),
- 'post_title' => $post_data['post_title']??'',
- 'post_status' => $post_data['status']??'draft',
- ], true));
- error_log('Recieved Data: '.print_r($post_data, true));
- $ID = wp_insert_post([
- 'post_author' => $this->user_id,
- 'post_type' => jvbCheckBase($post_data['content']),
- 'post_title' => $post_data['post_title']??'',
- 'post_status' => $post_data['status']??'draft',
+ $this->fields = $registrar->getFields()??[];
+
+ $this->taxonomies = [];
+ $data['items'] =array_map([$this, 'prepareTerm'], $terms);
+
+ $this->cache->set($key, $data);
+
+ return Response::success($data);
+ }
+
+ protected function applySearchFilters(array $args, array $params): array
+ {
+ $search_term = sanitize_text_field($params['search']);
+
+ // Search term is already in $args['s'] from earlier
+
+ // Get all taxonomies registered to this post type
+ $taxonomies = get_object_taxonomies($this->post_type, 'names');
+
+ if (empty($taxonomies)) {
+ return $args;
+ }
+
+ // Cache the taxonomy term lookup per search term + post type
+ $term_cache_key = 'search_terms_' . md5($search_term . $this->post_type);
+ $matching_term_ids = $this->cache->get($term_cache_key);
+
+ if ($matching_term_ids === false) {
+ $matching_term_ids = [];
+
+ foreach ($taxonomies as $taxonomy) {
+ $terms = get_terms([
+ 'taxonomy' => $taxonomy,
+ 'search' => $search_term,
+ 'hide_empty' => false,
+ 'fields' => 'ids'
]);
- if (!$ID || is_wp_error($ID)) {
- $results[$ID] = [
- 'success' => false,
- 'message' => 'Couldn\'t Create Post'
- ];
- continue;
- }
- $fields = jvbGetFields($post_data['content']);
- $allowedFields = array_filter($post_data, function($key) use ($fields) {
- return array_key_exists($key, $fields);
- }, ARRAY_FILTER_USE_KEY);
- $meta = new MetaManager($ID, 'post');
- $success = $meta->setAll($allowedFields);
- $results[$ID] = [
- 'success' => $success
+ if (!is_wp_error($terms) && !empty($terms)) {
+ $matching_term_ids = array_merge($matching_term_ids, $terms);
+ }
+ }
+
+ // Cache term IDs for 1 hour
+ $this->cache->set($term_cache_key, $matching_term_ids, 3600);
+ }
+
+ if (empty($matching_term_ids)) {
+ return $args;
+ }
+
+ // Build tax_query for matching terms
+ $term_queries = [];
+
+ foreach ($taxonomies as $taxonomy) {
+ $taxonomy_term_ids = array_filter($matching_term_ids, function ($term_id) use ($taxonomy) {
+ $term = get_term($term_id);
+ return !is_wp_error($term) && $term->taxonomy === $taxonomy;
+ });
+
+ if (!empty($taxonomy_term_ids)) {
+ $term_queries[] = [
+ 'taxonomy' => $taxonomy,
+ 'field' => 'term_id',
+ 'terms' => array_values($taxonomy_term_ids),
+ 'operator' => 'IN'
+ ];
+ }
+ }
+
+ if (!empty($term_queries)) {
+ if (isset($args['tax_query'])) {
+ $args['tax_query'] = [
+ 'relation' => 'OR',
+ $args['tax_query'],
+ [
+ 'relation' => 'OR',
+ ...$term_queries
+ ]
];
} else {
- if (!$this->verifyOwnership($ID)) {
- $results[$ID] = [
- 'success' => false,
- 'message' => 'No permission to modify this post'
- ];
- continue;
- }
- error_log('Saving post data: '.print_r($post_data, true));
-
- if (array_key_exists('post_status', $post_data)) {
- switch ($post_data['post_status']) {
- case 'publish':
- unset($post_data['post_status']);
- if (user_can($this->user_id, 'manage_options') || user_can($this->user_id, 'skip_moderation')) {
- $result = wp_update_post(['ID' => $ID, 'post_status' => 'publish']);
- }
- break;
- case 'draft':
- $result = wp_update_post([
- 'ID' => $ID,
- 'post_status' => 'draft'
- ]);
- break;
- case 'trash':
- $result = wp_trash_post($ID);
- break;
- case 'delete':
- $result = wp_delete_post($ID, true);
- return ['success' => (bool)$result];
- }
- }
- error_log('Updating data: '.print_r($post_data, true));
- $fields = jvbGetFields($post_data['content']);
- $allowedFields = array_filter($post_data, function($key) use ($fields) {
- return array_key_exists($key, $fields);
- }, ARRAY_FILTER_USE_KEY);
-
- 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
+ $args['tax_query'] = [
+ 'relation' => 'OR',
+ ...$term_queries
];
-
}
+ }
- CacheManager::invalidateGroup($post_data['content']);
- if (jvbSiteUsesFeedBlock()) {
- CacheManager::invalidateGroup($post_data['feed']);
- }
- }
+ return $args;
+ }
+
+ /**
+ * Gets allowed taxonomies for a particular content
+ * @param string $content
+ *
+ * @return array
+ */
+ protected function getTaxonomies(string $content): array
+ {
+ $registrar = Registrar::getInstance($content);
+ if (!$registrar || $registrar->getType()!== 'post') {
+ return [];
+ }
+ $out = [];
+ foreach ($registrar->registrar->taxonomies as $tax) {
+ $taxReg = Registrar::getInstance($tax);
+ $out[jvbCheckBase($tax)] = [
+ 'label' => $taxReg->getPlural(),
+ 'icon' => $taxReg->getIcon()??jvbDefaultIcon()
+ ];
+ }
+
+ return $out;
+ }
- CacheManager::invalidateGroup('user_content');
- if (jvbSiteHasNotifications()) {
- $this->notifications = JVB()->notification();
- $this->notifications->addNotification(
- $this->user_id,
- 'content_update_complete',
- null,
- 'Content updates completed!'
- );
+
+ /**
+ * Generates a post title, based on content type
+ * @param string $content the post type
+ *
+ * @return string
+ */
+ protected function generatePostTitle(string $content): string
+ {
+ $username = get_user_meta($this->user_id, 'first_name', true);
+ $link = get_user_meta($this->user_id, BASE . 'link', true);
+ $city = jvbArtistCity($link);
+ return ucfirst($content) . ' by ' . $city . ' artist ' . $username;
+ }
+
+ /**
+ * @param WP_Post $post the post object
+ *
+ * @return array
+ */
+ protected function preparePost(WP_Post $post, bool $skip = false, bool $fields = true): array
+ {
+ $registrar = Registrar::getInstance($post->post_type);
+ if (!$skip && $registrar && $registrar->hasFeature('is_timeline')) {
+ $this->initTimelineFields($post->post_type);
+ return $this->formatTimeline($post);
+ }
+ $this->meta = Meta::forPost($post->ID);
+ $fields = ($fields) ? $this->meta->getAll() : [];
+ $data = [
+ 'id' => $post->ID,
+ 'title' => $post->post_title,
+ 'status' => $post->post_status,
+ 'date' => $post->post_date,
+ 'modified' => $post->post_modified,
+ 'thumbnail' => get_the_post_thumbnail_url($post->ID),
+ 'alt' => get_post_meta(get_post_thumbnail_id(), '_wp_attachment_image_alt', true),
+ 'icon' => $registrar->getIcon(),
+ 'taxonomies' => [],
+ 'fields' => $fields,
+ 'images' => [],
+ ];
+
+ $images = $this->extractImages($fields, $this->meta);
+ if (!empty($images)) {
+ $data['images'] = $images;
}
- return [
- 'success' => true,
- 'result' => $results
- ];
- }
+ $taxonomies = $this->extractTerms($fields, $this->meta);
+ if (!empty($taxonomies)) {
+ $data['taxonomies'] = $taxonomies;
+ }
+ return $data;
+ }
- /**
- * Handle batch content creation from uploads
- * @param WP_REST_Request $request
- *
- * @return WP_REST_Response
- */
- public function handleBatchCreation(WP_REST_Request $request):WP_REST_Response
- {
- //Operation has two parts
- //First, queue image processing
- //Then queue post creation from the stored IDs, depending on mode
- //if direct, each image becomes a new post
- //if selection, each group becomes its own post,
- // and ungrouped items each become their own post
- if (!isset($_FILES['files'])) {
- return new WP_REST_Response([
- 'success' => false,
- 'message' => 'No files uploaded...',
- ]);
- }
+ /**
+ * @param WP_Term $post the post object
+ *
+ * @return array
+ */
+ protected function prepareTerm(WP_Term $post, bool $fields = true): array
+ {
+ $registrar = Registrar::getInstance($post->taxonomy);
- $data = $request->get_params();
+ $this->meta = Meta::forTerm($post->term_id);
+ $fields = ($fields) ? $this->meta->getAll() : [];
+ $data = [
+ 'id' => $post->term_id,
+ 'title' => $post->name,
+ 'date' => $fields['created_date']??'',
+ 'modified' => $fields['modified_date']??'',
+ 'thumbnail' => '',
+ 'icon' => $registrar->getIcon(),
+ 'taxonomies' => [],
+ 'fields' => $fields,
+ 'images' => [],
+ ];
+
+ $images = $this->extractImages($fields, $this->meta);
+ if (!empty($images)) {
+ $data['images'] = $images;
+ }
+
+ $taxonomies = $this->extractTerms($fields, $this->meta);
+ if (!empty($taxonomies)) {
+ $data['taxonomies'] = $taxonomies;
+ }
+
+ error_log('Term data: '.print_r($data, true));
+ return $data;
+ }
- $user_id = $data['user'];
- if (!$this->userCheck($user_id)) {
- return new WP_REST_Response([
- 'success' => 'false',
- 'message' => 'Invalid user match... are you a bot?'
- ]);
- }
- $operation_id = $data['id'];
- $response = new WP_REST_Response([
- 'success' => true,
- 'message' => 'Successfully sent to server. Added to queue.',
- 'operation_id' => $operation_id,
- 'status' => 'pending'
- ]);
- $this->queue = JVB()->queue();
- JVB()->routes('uploads')->handleUploadRequest($request, false);
- $this->queue->queueOperation(
- 'batch_creation',
- $user_id,
- [
- 'content' => $request->get_param('content'),
- 'mode' => $request->get_param('mode') ?: 'direct',
- 'files_data'=> $request->get_param('files_data')
- ],
- [
- 'operation_id' => $operation_id,
- 'priority' => 'high',
- 'notification' => true,
- 'depends_on' => $operation_id.'_upload'
- ]
- );
+ public function formatTimeline(WP_Post $post): array
+ {
+ $item = $this->preparePost($post, true, false);
+ //Step 1: Get the fields that apply to all posts
+ $mainMeta = Meta::forPost($post->ID);
+ $item['fields'] = $mainMeta->getAll($this->timelineSharedFields);
- return $response;
- }
+ //Step 2: Get the fields for each individual posts
+ $children = jvbTimelinePoints($post->ID, $post->post_type,['publish', 'draft']);
+ array_unshift($children, $post->ID);
- /**
- * Generates a post title, based on content type
- * @param string $content the post type
- *
- * @return string
- */
- protected function generatePostTitle(string $content):string
- {
- $username = get_user_meta($this->user_id, 'first_name', true);
- $link = get_user_meta($this->user_id, BASE.'link', true);
- $city = jvbArtistCity($link);
- return ucfirst($content).' by '.$city.' artist '.$username;
- }
-
- /**
- * @param object $post the wordpress post object
- *
- * @return array
- */
- protected function prepareItem(object $post):array
- {
- $this->meta = new MetaManager($post->ID, 'post');
- $data = [
- 'id' => $post->ID,
- 'status' => $post->post_status,
- 'date' => $post->post_date,
- 'modified' => $post->post_modified,
- 'thumbnail' => get_the_post_thumbnail_url($post->ID),
- 'alt' => get_post_meta(get_post_thumbnail_id(), '_wp_attachment_image_alt', true),
- 'icon' => $this->post_type,
- 'taxonomies'=> [],
- 'fields' => $this->meta->getAll(),
- 'images' => [],
- ];
-
- // Add taxonomy terms
- foreach ($this->taxonomies as $taxonomy => $options) {
- $tax = str_replace(BASE, '', $taxonomy);
- $terms = wp_get_object_terms(
- $post->ID,
- $taxonomy,
- ['fields' => 'id=>name']
- );
- $data['taxonomies'][$tax] = [
- 'terms' => (is_wp_error($terms))? [] : $terms,
- 'name' => $options['label'],
- 'icon' => $tax
- ];
- }
-
-
- //Extract images
+ $subFields = [];
$images = [];
- $get = [];
- foreach ($this->fields as $field => $config) {
- if ($config['type'] === 'gallery' || $config['type'] === 'image' || $field === 'post_thumbnail') {
- $get[] = $field;
- }
- }
+ foreach ($children as $child) {
+ $meta = Meta::forPost($child);
+ $f = $meta->getAll($this->timelineUniqueFields);
+ $f = ['id' => $child] + $f;
+ $subFields[] = $f;
- if (!empty($get)) {
- $allImages = $this->meta->getAll($get);
- foreach($allImages as $k => $imgs){
- $temp = explode(',', $imgs);
- foreach($temp as $img) {
- if (is_numeric($img) && !array_key_exists($img, $images)) {
- $images[$img] = jvbImageData((int) $img);
- }
- }
- }
+ $images[$f['post_thumbnail']] = jvbImageData((int)$f['post_thumbnail']);
}
+ $item['fields']['timeline_gallery'] = $subFields;
+ $item['images'] = $item['images'] + $images;
+ $item['number'] = $mainMeta->get('number');
- if (!empty($images)) {
- $data['images'] = $images;
- }
-
- return $data;
- }
-
- /**
- * Builds the taxonomy query
- * @param array $taxonomies
- *
- * @return array|string[]
- */
- protected function buildTaxQuery(array $taxonomies):array
- {
- $tax_query = [];
- error_log('Taxonomies in query: '.print_r($taxonomies, true));
-
- foreach ($taxonomies as $taxonomy => $terms) {
- if (!empty($terms)) {
- $tax_query[] = [
- 'taxonomy' => jvbCheckBase($taxonomy),
- 'field' => 'term_id',
- 'terms' => array_map('absint', (array)$terms)
- ];
- }
- }
-
-
- return count($tax_query) > 1
- ? array_merge(['relation' => 'AND'], $tax_query)
- : $tax_query;
- }
-
- /**
- * Builds the date query
- * @param array $date_params
- *
- * @return array
- */
- protected function buildDateQuery(array $date_params):array
- {
- $query = [];
-
- if (!empty($date_params['after'])) {
- $query['after'] = sanitize_text_field($date_params['after']);
- }
-
- if (!empty($date_params['before'])) {
- $query['before'] = sanitize_text_field($date_params['before']);
- }
-
- if (isset($date_params['inclusive'])) {
- $query['inclusive'] = (bool)$date_params['inclusive'];
- }
-
- return empty($query) ? [] : [$query];
- }
-
- /**
- * @param int $post_id
- *
- * @return bool
- */
- protected function verifyOwnership(int $post_id):bool
- {
- $post = get_post($post_id);
- return $post && $post->post_author == $this->user_id;
- }
-
- /**
- * Processes operation from Operation Queue
- * @param WP_Error|array $result
- * @param object $operation
- * @param array $data
- *
- * @return array|WP_Error
- */
- public function processOperation(WP_Error|array $result, object $operation, array $data):array|WP_Error
- {
- if ($operation->type === 'batch_creation') {
- $JVB = JVB();
- $queue = $JVB->queue();
-
- $images = $queue->getOperationValue($operation->id.'_upload', 'result')??false;
-
- $this->user_id = $operation->user_id;
- $this->post_type = BASE.$data['content'];
- try {
- $results = [];
- if ($images) {
- if ($data['mode'] == 'selection') {
- $total = count($images);
- foreach ($images as $group => $files) {
- $settings = json_decode($data['files_data'][$group]);
-
- switch ($settings->type) {
- case 'group':
- $featuredIndex = $settings->metadata->featuredFile??0;
- $title = $settings->metadata->title??$this->generatePostTitle($data['content']);
- $new = wp_insert_post([
- 'post_type' => BASE.$data['content'],
- 'post_title' => $title,
- 'post_status' => 'draft',
- 'post_author' => $operation->user_id
- ]);
- if ($new && !is_wp_error($new)) {
- set_post_thumbnail($new, $files[$featuredIndex]['attachment_id']);
- unset($files[$featuredIndex]);
- if (!empty($files)) {
- $meta = new MetaManager($new, 'post');
- $IDs = array_column($files, 'attachment_id');
- $meta->updateValue('gallery', implode(',', $IDs));
- }
- $results[] = $new;
-// $queue->updateOperationProgress($operation->id, $group + 1, $total);
- }
- break;
- default:
- foreach ($files as $img) {
- $new = wp_insert_post([
- 'post_type' => BASE. $data['content'],
- 'post_title' => $this->generatePostTitle($data['content']),
- 'post_status' => 'draft',
- 'post_author' => $operation->user_id
- ]);
-
- if ($new && !is_wp_error($new)) {
- set_post_thumbnail($new, $img['attachment_id']);
- $results[] = $new;
-// $queue->updateOperationProgress($operation->id, $group + 1, $total);
- }
- }
- break;
- }
- }
- } else {
- $total = count($images);
- foreach ($images as $key => $img) {
- $new = wp_insert_post([
- 'post_type' => BASE.$data['content'],
- 'post_title' => $this->generatePostTitle($data['content']),
- 'post_status' => 'draft',
- 'post_author' => $operation->user_id
- ]);
- if ($new && !is_wp_error($new)) {
- set_post_thumbnail($new, $img['attachment_id']);
- }
- $results[] = $new;
-// $queue->updateOperationProgress($operation->id, $key + 1, $total);
- }
- }
-
- //Clear cache
- CacheManager::invalidateGroup($data['content']);
- CacheManager::invalidateGroup('feed');
- CacheManager::invalidateGroup('user_content');
- }
-
- return [
- 'success' => true,
- 'result' => $results
- ];
- } catch (Exception $e) {
- $JVB->error()->log(
- '[ContentRoutes]:processOperation',
- $e->getMessage()
- );
- }
-
- return $results;
- } elseif ($operation->type == 'content_update') {
- $result = $this->processBatches($operation, $data);
- }
-
- return $result;
- }
+ return $item;
+ }
}
--
Gitblit v1.10.0