From a9b3b28d001941921aa70d37fdc87c758a163a44 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Fri, 05 Jun 2026 16:47:03 +0000
Subject: [PATCH] =Some hefty changes to FeedBlock. Transitioning to loading first page in php to save on extra requests. Got a bit to do yet, but I have to work on Northeh for a bit here.
---
inc/rest/routes/TermRoutes.php | 548 ++++++++++++++++++------------------------------------
1 files changed, 182 insertions(+), 366 deletions(-)
diff --git a/inc/rest/routes/TermRoutes.php b/inc/rest/routes/TermRoutes.php
index 438139e..8954448 100644
--- a/inc/rest/routes/TermRoutes.php
+++ b/inc/rest/routes/TermRoutes.php
@@ -1,11 +1,11 @@
<?php
namespace JVBase\rest\routes;
-use JVBase\JVB;
-use JVBase\rest\RestRouteManager;
-use JVBase\managers\TaxonomyRelationships;
+use JVBase\registrar\Registrar;
+use JVBase\rest\Rest;
use JVBase\managers\UserTermsManager;
-use JVBase\utility\Features;
+use JVBase\rest\Route;
+use JVBase\base\Site;
use WP_REST_Request;
use WP_REST_Response;
use Exception;
@@ -13,18 +13,19 @@
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
-class TermRoutes extends RestRouteManager
+class TermRoutes extends Rest
{
protected object $term_index_manager;
protected int $per_page;
public function __construct()
{
- $this->cache_name = 'terms';
+ $this->cacheName = 'terms';
parent::__construct();
if (JVB_TESTING) {
$this->cache->flush();
}
+ $this->cache->connect('taxonomy', true);
$this->per_page = 20;
add_action('edited_term', [$this, 'deleteTermPath']);
@@ -37,60 +38,31 @@
*/
public function registerRoutes():void
{
- register_rest_route($this->namespace, '/terms', [
- [
- 'methods' => 'GET',
- 'callback' => [$this, 'handleTermSelectionRequest'],
- 'permission_callback' => [$this, 'checkPermission'],
- 'args' => [
- 'page' => [
- 'required' => true,
- 'type' => 'integer',
- 'default' => 1,
- ],
- 'taxonomy' => [
- 'required' => true,
- 'type' => 'string'
- ],
- 'search' => [
- 'required' => false,
- 'type' => 'string'
- ],
- 'parent' => [
- 'required' => false,
- 'type' => 'integer',
- 'default' => 0
- ]
- ]
- ],
- [
- 'methods' => 'POST',
- 'callback' => [$this, 'createTermRequest'],
- 'permission_callback' => [$this, 'checkPermission'],
- 'args' => [
- 'taxonomy' => [
- 'required' => true,
- 'type' => 'string'
- ],
- 'name' => [
- 'required' => true,
- 'type' => 'string'
- ],
- 'parent' => [
- 'required' => false,
- 'type' => 'integer',
- 'default' => 0
- ]
- ]
- ]
- ]);
+ Route::for('terms')
+ ->get([$this, 'handleTermSelectionRequest'])
+ ->auth('public')
+ ->rateLimit()
+ ->args([
+ 'page' => 'int|required',
+ 'taxonomy' => 'string|required',
+ 'search' => 'string',
+ 'parent' => 'int'
+ ])
+ ->post([$this, 'createTermRequest'])
+ ->auth('isVerified')
+ ->rateLimit(30)
+ ->args([
+ 'taxonomy' => 'string|required',
+ 'name' => 'string|required',
+ 'parent' => 'int|default:0',
+ ])
+ ->register();
- //TODO: Just wrap this up to the normal GET request
- register_rest_route($this->namespace, '/terms/check', [
- 'methods' => 'GET',
- 'callback' => [$this, 'getTermDetails'],
- 'permission_callback' => [$this, 'checkPermission'],
- ]);
+ Route::for('terms/check')
+ ->get([$this,'getTermDetails'])
+ ->auth('public')
+ ->rateLimit()
+ ->register();
}
/**
@@ -104,10 +76,7 @@
$term = get_term($term_id);
if (is_wp_error($term)) {
- return new WP_REST_Response([
- 'success' => false,
- 'message' => $term
- ]);
+ return $this->error('No term found');
}
$data = [
@@ -119,7 +88,7 @@
// Add relationship data if requested
if ($request->get_param('include_relationships')) {
- $relationship_manager = new TaxonomyRelationships();
+ $relationship_manager = JVB()->termRelationships();
$related_taxonomies = $request->get_param('related_taxonomies') ?: ['jvb_style', 'jvb_theme', 'jvb_city'];
$data['relationships'] = [];
@@ -142,7 +111,7 @@
}
}
- return new WP_REST_Response($data);
+ return $this->success($data);
}
/**
@@ -150,31 +119,33 @@
*
* @return WP_REST_Response
*/
- public function getTermDetails(WP_REST_Request $request):WP_REST_Response
- {
- $data = $request->get_params();
- // Collect all taxonomies being queried
+ public function getTermDetails(WP_REST_Request $request): WP_REST_Response
+ {
+ $data = $request->get_params();
$taxonomies = array_keys($data);
- // Check HTTP cache headers
- $cache_check = $this->checkHeaders($request, $taxonomies);
+ $cache_check = $this->checkHeaders($request, $this->cache->generateKey(['termDetails' => $data]));
if ($cache_check) {
return $cache_check;
}
- $terms = [];
- foreach ($data as $tax => $IDs) {
- $args = [
- 'taxonomy' => BASE.$tax,
- 'include' => $IDs
- ];
- $terms[$tax] = $this->formatTerms($args, BASE.$tax);
- }
- $response = new WP_REST_Response([
- 'items' => $terms,
- ]);
- return $this->addCacheHeaders($response);
- }
+ $terms = $this->cache->remember(
+ $this->cache->generateKey(['termDetails' => $data]),
+ function() use ($data) {
+ $result = [];
+ foreach ($data as $tax => $IDs) {
+ $args = [
+ 'taxonomy' => BASE . $tax,
+ 'include' => $IDs
+ ];
+ $result[$tax] = $this->formatTerms($args, BASE . $tax);
+ }
+ return $result;
+ }
+ );
+
+ return $this->addCacheHeaders($this->success(['items' => $terms]));
+ }
/**
* @param WP_REST_Request $request
@@ -207,7 +178,7 @@
$key = $this->cache->generateKey($args);
$cached = $this->cache->get($key);
if ($cached) {
- $response = new WP_REST_Response($cached);
+ $response = $this->success($cached);
return $this->addCacheHeaders($response);
}
@@ -216,14 +187,14 @@
'items' => $formatted
];
$this->cache->set($key, $response);
- $response = new WP_REST_Response($response);
+ $response = $this->success($response);
return $this->addCacheHeaders($response);
}
if (array_key_exists('content', $data)) {
// If content_type is provided, use the specialized endpoint
$content_type = $request->get_param('content');
- global $feed_types;
- if (taxIsJVBContentTax($content_type)) {
+ $registrar = Registrar::getInstance($content_type);
+ if ($registrar->hasFeature('is_content')) {
$response = $this->getTermsForContentType($request);
return $this->addCacheHeaders($response);
}
@@ -237,16 +208,7 @@
$per_page = 25;
if (!taxonomy_exists($taxonomy)) {
- return new WP_REST_Response([
- 'items' => [],
- 'pagination' => [
- 'page' => 1,
- 'per_page' => $per_page,
- 'total_pages' => 0,
- 'total_terms' => 0
- ],
- 'has_more' => false
- ]);
+ return $this->emptyResult();
}
$tax_obj = get_taxonomy($taxonomy);
@@ -274,21 +236,12 @@
if ($request->get_param('main_context') && in_array(jvbCheckBase(json_decode($request->get_param('main_context'), true)['context']), jvbUserTypes())) {
$main_context = json_decode($request->get_param('main_context'), true);
- $userID = get_post_meta($main_context['id'], BASE.'link', true);
+ $userID = get_post_meta($main_context['id'], BASE.'profile_link', true);
$manager = new UserTermsManager();
- $related = $manager->getUserTermIDs($userID, $taxonomy);
+ $related = $manager->fetchUserTerms($userID, $taxonomy);
if (empty($related)) {
- $response = new WP_REST_Response([
- 'items' => [],
- 'pagination' => [
- 'page' => 1,
- 'per_page' => $per_page,
- 'total_pages' => 0,
- 'total_terms' => 0,
- ],
- 'has_more' => false
- ]);
+ $response = $this->emptyResult();
return $this->addCacheHeaders($response);
}
@@ -298,20 +251,11 @@
$main_context = json_decode($request->get_param('main_context'), true);
$thisTaxonomy = str_replace('taxonomy:', '', $main_context['context']);
$ID = (int)$main_context['id'];
- $manager = new TaxonomyRelationships();
+ $manager = JVB()->termRelationships();
$related = $manager->getRelatedTerms($ID, BASE.$request->get_param('taxonomy'));
if (empty($related)) {
- $response = new WP_REST_Response([
- 'items' => [],
- 'pagination' => [
- 'page' => 1,
- 'per_page' => $per_page,
- 'total_pages' => 0,
- 'total_terms' => 0
- ],
- 'has_more' => false
- ]);
+ $response = $this->emptyResult();
return $this->addCacheHeaders($response);
}
$args['tax_query'] = [
@@ -325,7 +269,7 @@
$match = $request->get_param('match') ?? 'any';
$context = json_decode($request['context'], true);
- $relationshipManager = new TaxonomyRelationships();
+ $relationshipManager = JVB()->termRelationships();
// Prepare array to collect term IDs that match the context
$related_term_ids = [];
@@ -361,16 +305,7 @@
$args['include'] = $related_term_ids;
} else {
// No related terms found, return empty result
- $response = new WP_REST_Response([
- 'items' => [],
- 'pagination' => [
- 'page' => 1,
- 'per_page' => $per_page,
- 'total_pages' => 0,
- 'total_terms' => 0
- ],
- 'has_more' => false
- ]);
+ $response = $this->emptyResult();
return $this->addCacheHeaders($response);
}
@@ -382,7 +317,7 @@
$cache = $this->cache->get($key);
if ($cache) {
- $response = new WP_REST_Response($cache);
+ $response = $this->success($cache);
return $this->addCacheHeaders($response);
}
@@ -411,7 +346,7 @@
];
$this->cache->set($key, $response);
- $response = new WP_REST_Response($response);
+ $response = $this->success($response);
return $this->addCacheHeaders($response);
}
@@ -449,7 +384,7 @@
'has_more' => true,
];
- $response = new WP_REST_Response($response);
+ $response = $this->success($response);
return $this->addCacheHeaders($response);
}
@@ -525,74 +460,56 @@
*
* @return WP_REST_Response
*/
- public function handleTermSearch(WP_REST_Request $request):WP_REST_Response
- {
- $taxonomy = BASE.$request->get_param('taxonomy');
- $search = $request->get_param('search');
- $page = $request->get_param('page') ?? 1;
- $per_page = $request->get_param('per_page') ?? 20;
+ public function handleTermSearch(WP_REST_Request $request): WP_REST_Response
+ {
+ $taxonomy = BASE . $request->get_param('taxonomy');
+ $search = $request->get_param('search');
+ $page = $request->get_param('page') ?? 1;
+ $per_page = $request->get_param('per_page') ?? 20;
- // When searching, we want to search across all terms regardless of hierarchy
- $args = [
- 'taxonomy' => $taxonomy,
- 'hide_empty' => true,
- 'search' => $search,
- 'search_columns' => ['name', 'slug'],
- 'fields' => 'all',
- 'number' => $per_page,
- 'offset' => ($page - 1) * $per_page,
- ];
+ $args = [
+ 'taxonomy' => $taxonomy,
+ 'hide_empty' => true,
+ 'search' => $search,
+ 'search_columns' => ['name', 'slug'],
+ 'fields' => 'all',
+ 'number' => $per_page,
+ 'offset' => ($page - 1) * $per_page,
+ ];
- $key = $this->cache->generateKey($args);
- $cache = $this->cache->get($key);
- if ($cache) {
- return new WP_REST_Response($cache);
- }
+ $data = $this->cache->remember(
+ $this->cache->generateKey($args),
+ function() use ($args, $taxonomy, $page, $per_page) {
+ $terms = get_terms($args);
- $terms = get_terms($args);
+ if (is_wp_error($terms)) {
+ return $this->emptyResult($page, $per_page);
+ }
- if (is_wp_error($terms)) {
- return new WP_REST_Response([
- 'items' => [],
- 'pagination' => [
- 'page' => 0,
- 'per_page' => 20,
- 'total_pages' => 0,
- 'total_terms' => 0
- ],
- 'has_more' => false
- ]);
- }
+ $formatted_terms = array_map(
+ fn($term) => $this->formatSingleTerm($term, $taxonomy),
+ $terms
+ );
- // Get total count for pagination
- $count_args = array_merge($args, ['fields' => 'count']);
- $total_terms = wp_count_terms($count_args);
+ $count_args = array_merge($args, ['fields' => 'count']);
+ $total_terms = wp_count_terms($count_args);
+ $total_pages = ceil($total_terms / $per_page);
- $formatted_terms = [];
- foreach ($terms as $term) {
- // Search results show path, so includeChildren = false for performance
- $formatted_terms[] = $this->formatSingleTerm($term, $taxonomy, false);
- }
+ return [
+ 'items' => $formatted_terms,
+ 'pagination' => [
+ 'page' => (int)$page,
+ 'per_page' => (int)$per_page,
+ 'total_pages' => $total_pages,
+ 'total_terms' => (int)$total_terms
+ ],
+ 'has_more' => $page < $total_pages
+ ];
+ }
+ );
- // Calculate pagination info
- $total_pages = ceil($total_terms / $per_page);
- $has_more = $page < $total_pages;
-
- $response = [
- 'items' => $formatted_terms,
- 'pagination' => [
- 'page' => (int)$page,
- 'per_page' => (int)$per_page,
- 'total_pages' => $total_pages,
- 'total_terms' => (int)$total_terms
- ],
- 'has_more' => $has_more
- ];
-
- $this->cache->set($key, $response);
-
- return new WP_REST_Response($response);
- }
+ return $this->addCacheHeaders($this->success($data));
+ }
/**
* @param int $termID
@@ -666,7 +583,7 @@
*/
public function getTermsForContentType(WP_REST_Request $request):WP_REST_Response
{
- $manager = new TaxonomyRelationships();
+ $manager = JVB()->termRelationships();
$content_type = BASE . $request->get_param('content');
$taxonomy = BASE . $request->get_param('taxonomy');
$search = $request->get_param('search');
@@ -686,7 +603,8 @@
$cache = $this->cache->get($cache_key);
// Try cache first
if ($cache !== false) {
- return new WP_REST_Response($cache);
+ $response = $this->success($cache);
+ return $this->addCacheHeaders($response);
}
try {
@@ -785,156 +703,54 @@
// Cache results
$this->cache->set($cache_key, $results);
-
- return new WP_REST_Response($results);
+ $response = $this->success($results);
+ return $this->addCacheHeaders($response);
} catch (Exception $e) {
- return new WP_REST_Response([
- 'success' => false,
- 'message' => $e->getMessage()
- ]);
+ return $this->error('Error getting terms for content: '.$e->getMessage(), 'get_terms_for_content');
}
}
+
/**
* @param WP_REST_Request $request
*
* @return WP_REST_Response
*/
- public function handleTermsRequest(WP_REST_Request $request):WP_REST_Response
- {
- $taxonomy = BASE.$request->get_param('taxonomy');
- $search = $request->get_param('search');
- $page = max(1, intval($request->get_param('page')));
- $per_page = $request->get_param('per_page') ?: $this->per_page;
+ public function createTermRequest(WP_REST_Request $request): WP_REST_Response
+ {
+ $user_id = get_current_user_id();
+ $taxonomy = $request->get_param('taxonomy');
+ $name = sanitize_text_field($request->get_param('name'));
+ $parent = (int)$request->get_param('parent') ?: 0;
- // Create cache key
- $cache_key = "terms_{$taxonomy}_" . md5("{$search}_{$page}_{$per_page}");
- $cache = $this->cache->get($cache_key);
- if ($cache) {
- return new WP_REST_Response($cache);
- }
+ try {
+ $existing = term_exists($name, jvbCheckBase($taxonomy), $parent);
- try {
- // Build query args
- $args = [
- 'taxonomy' => $taxonomy,
- 'hide_empty' => true,
- 'orderby' => $search ? 'name' : 'count',
- 'order' => $search ? 'ASC' : 'DESC',
- 'number' => $per_page,
- 'offset' => ($page - 1) * $per_page,
- 'fields' => 'all'
- ];
-
- // Add search if provided
- if ($search) {
- $args['search'] = $search;
- }
-
- // Get terms
- $terms = get_terms($args);
-
- if (is_wp_error($terms)) {
- return new WP_REST_Response([
- 'items' => [],
- 'pagination' => [
- 'page' => 0,
- 'per_page' => 20,
- 'total_pages' => 0,
- 'total_terms' => 0
- ],
- 'has_more' => 0
- ]);
- }
-
- // Check if taxonomy is hierarchical
- $is_hierarchical = is_taxonomy_hierarchical($taxonomy);
-
- // Format terms
- $formatted_terms = [];
- foreach ($terms as $term) {
- $formatted_terms[] = $this->formatSingleTerm($term, $taxonomy, false);
+ if ($existing) {
+ $term = get_term($existing['term_id'], jvbCheckBase($taxonomy));
+ return $this->success(['message' => 'Term already exists', 'term' => [
+ 'id' => $term->term_id,
+ 'name' => html_entity_decode($term->name),
+ 'path' => $this->getTermPath($term->term_id, $term->name, $taxonomy)
+ ]]);
}
- // Get total for pagination
- $total_args = array_merge($args, ['fields' => 'count', 'number' => '']);
- $total = wp_count_terms($taxonomy, $total_args);
- $total_pages = ceil($total / $per_page);
-
- $results = [
- 'items' => $formatted_terms,
- 'pagination' => [
- 'page' => (int)$page,
- 'per_page' => (int)$per_page,
- 'total_pages' => $total_pages,
- 'total_terms' => (int)$total
- ],
- 'has_more' => $page < $total_pages
- ];
-
- // Cache results
- $this->cache->set($cache_key, $results);
-
- return new WP_REST_Response($results);
-
- } catch (Exception $e) {
- return new WP_REST_Response([
- 'success' => false,
- 'message' => $e->getMessage()
- ]);
- }
- }
-
- /**
- * @param WP_REST_Request $request
- *
- * @return WP_REST_Response
- */
- public function createTermRequest(WP_REST_Request $request):WP_REST_Response
- {
- $user_id = get_current_user_id();
- $taxonomy = $request->get_param('taxonomy');
- $name = sanitize_text_field($request->get_param('name'));
- $parent = (int)$request->get_param('parent') ?: 0;
-
-
- try {
- // Check if term already exists
- $existing = term_exists($name, jvbCheckBase($taxonomy), $parent);
-
- if ($existing) {
-
- $term = get_term($existing['term_id'], jvbCheckBase($taxonomy));
- error_log('Existing Term: '.print_r($term, true));
- return new WP_REST_Response([
- 'success' => false,
- 'message' => 'Term already exists',
- 'term' => [
- 'id' => $term->term_id,
- 'name' => html_entity_decode($term->name),
- 'path' => $this->getTermPath($term->term_id, $term->name, $taxonomy)
- ]
- ]);
- }
-
-
- if (Features::forMembership()->has('term_approval')) {
- error_log('Term Approval required');
- // Get approval routes instance
+ $membership = Site::membership();
+ if ($membership && $membership->has('term_approval')) {
$approval_routes = JVB()->routes('approvals');
- // Create approval request
$request_id = $approval_routes->createTermApprovalRequest(
$user_id,
$taxonomy,
sanitize_title($name),
absint($parent)
);
+
if (!$request_id) {
throw new Exception('Failed to create approval request');
}
- $return = [
- 'success' => true,
+
+ return $this->success([
'message' => 'Term suggestion submitted for approval',
'term' => [
'id' => 'pending_' . $request_id,
@@ -942,50 +758,50 @@
'pending' => true,
'request_id' => $request_id
]
- ];
- } else {
- error_log('Creating new Term: ');
- $termID = wp_insert_term(
- $name,
- jvbCheckBase($taxonomy),
- [
- 'parent' => absint($parent)
- ]
- );
- error_log('Result: '.print_r($termID, true));
-
- if (is_wp_error($termID)) {
- throw new Exception('Failed to create new term');
- }
-
- $return = [
- 'success' => true,
- 'message' => $name.' created successfully',
- 'term' => [
- 'id' => $termID['term_id'],
- 'name' => $name,
- 'path' => $this->getTermPath($termID['term_id'], $name, $taxonomy)
- ]
- ];
+ ], 202); // 202 Accepted for pending approval
}
- return new WP_REST_Response($return);
+ $termID = wp_insert_term(
+ $name,
+ jvbCheckBase($taxonomy),
+ ['parent' => absint($parent)]
+ );
- } catch (Exception $e) {
- JVB()->error()->log(
- 'terms',
- 'Term creation failed: ' . $e->getMessage(),
- [
- 'user_id' => $user_id,
- 'taxonomy' => $taxonomy,
- 'name' => $name
- ]
- );
+ if (is_wp_error($termID)) {
+ throw new Exception($termID->get_error_message());
+ }
- return new WP_REST_Response([
- 'success' => false,
- 'message' => $e->getMessage()
- ], 500);
- }
- }
+ return $this->success([
+ 'message' => $name . ' created successfully',
+ 'term' => [
+ 'id' => $termID['term_id'],
+ 'name' => $name,
+ 'path' => $this->getTermPath($termID['term_id'], $name, $taxonomy)
+ ]
+ ], 201); // 201 Created
+
+ } catch (Exception $e) {
+ JVB()->error()->log(
+ 'terms',
+ 'Term creation failed: ' . $e->getMessage(),
+ ['user_id' => $user_id, 'taxonomy' => $taxonomy, 'name' => $name]
+ );
+
+ return $this->error($e->getMessage(), 'term_creation_failed', 500);
+ }
+ }
+
+ protected function emptyResult(int $page = 1, int $per_page = 20):WP_REST_Response
+ {
+ return $this->success([
+ 'items' => [],
+ 'pagination' => [
+ 'page' => $page,
+ 'per_page' => $per_page,
+ 'total_pages' => 0,
+ 'total_terms' => 0
+ ],
+ 'has_more' => false
+ ]);
+ }
}
--
Gitblit v1.10.0