From 18e7e415339ccc9adf8ade562f93abef606da16d Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Wed, 26 Aug 2026 22:24:18 +0000
Subject: [PATCH] =Cache::connects throughout codebase refactored
---
inc/rest/routes/TermRoutes.php | 941 ++++++++++++++++++++--------------------------------------
1 files changed, 333 insertions(+), 608 deletions(-)
diff --git a/inc/rest/routes/TermRoutes.php b/inc/rest/routes/TermRoutes.php
index da8f52c..38772cb 100644
--- a/inc/rest/routes/TermRoutes.php
+++ b/inc/rest/routes/TermRoutes.php
@@ -1,10 +1,15 @@
<?php
namespace JVBase\rest\routes;
-use JVBase\JVB;
-use JVBase\rest\RestRouteManager;
+use JVBase\Instance;
+use JVBase\managers\Cache;
+use JVBase\managers\Errors;
use JVBase\managers\TaxonomyRelationships;
+use JVBase\registrar\Registrar;
+use JVBase\rest\Rest;
use JVBase\managers\UserTermsManager;
+use JVBase\rest\Route;
+use JVBase\base\Site;
use WP_REST_Request;
use WP_REST_Response;
use Exception;
@@ -12,19 +17,22 @@
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
-class TermRoutes extends RestRouteManager
+class TermRoutes extends Rest
{
+ use Instance;
protected object $term_index_manager;
protected int $per_page;
public function __construct()
{
- $this->cache_name = 'terms';
+ $this->cacheName = 'terms';
parent::__construct();
-// $this->cache->invalidateGroup('terms');
+ $this->cache = Cache::for('terms', 'term');
+
+
$this->per_page = 20;
+
add_action('edited_term', [$this, 'deleteTermPath']);
- add_action('wp_login', [$this, 'clearUserTaxonomyCache'], 10, 2);
}
/**
@@ -33,60 +41,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();
}
/**
@@ -100,22 +79,19 @@
$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 = [
'id' => $term->term_id,
- 'name' => $term->name,
+ 'name' => html_entity_decode($term->name),
'slug' => $term->slug,
'taxonomy' => $term->taxonomy,
];
// Add relationship data if requested
if ($request->get_param('include_relationships')) {
- $relationship_manager = new TaxonomyRelationships();
+ $relationship_manager = TaxonomyRelationships::getInstance();
$related_taxonomies = $request->get_param('related_taxonomies') ?: ['jvb_style', 'jvb_theme', 'jvb_city'];
$data['relationships'] = [];
@@ -130,7 +106,7 @@
$term = get_term($rel->related_term_id, $rel->related_taxonomy);
return [
'id' => $rel->related_term_id,
- 'name' => $term ? $term->name : 'Unknown',
+ 'name' => $term ? html_entity_decode($term->name) : 'Unknown',
'count' => $rel->relationship_count
];
}, $relationships);
@@ -138,7 +114,7 @@
}
}
- return new WP_REST_Response($data);
+ return $this->success($data);
}
/**
@@ -146,22 +122,27 @@
*
* @return WP_REST_Response
*/
- public function getTermDetails(WP_REST_Request $request):WP_REST_Response
- {
- $data = $request->get_params();
- $terms = [];
- foreach ($data as $tax => $IDs) {
- $args = [
- 'taxonomy' => BASE.$tax,
- 'include' => $IDs
- ];
+ public function getTermDetails(WP_REST_Request $request): WP_REST_Response
+ {
+ $data = $request->get_params();
- $terms[$tax] = $this->formatTerms($args, BASE.$tax);
- }
- return new WP_REST_Response([
- 'items' => $terms,
- ]);
- }
+ $terms = $this->cache->remember(
+ ['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->success(['items' => $terms]);
+ }
/**
* @param WP_REST_Request $request
@@ -171,67 +152,72 @@
public function handleTermSelectionRequest(WP_REST_Request $request):WP_REST_Response
{
$data = $request->get_params();
- $taxonomy = jvbCheckBase($data['taxonomy']);
+ $taxonomy = sanitize_text_field($data['taxonomy'])??'';
+ if (empty($taxonomy)) {
+ return $this->success(['message' => 'No taxonomy selected']);
+ }
+
+ // Handle batch request (multiple taxonomies)
+ if (str_contains($taxonomy, ',')) {
+ return $this->handleBatchTermRequest($taxonomy, $data, $request);
+ }
+ $taxonomy = jvbCheckBase($taxonomy);
if (array_key_exists('termIDs', $data)) {
$args = [
'taxonomy' => $taxonomy,
'include' => $data['termIDs'],
- 'hide_empty' => false,
+ 'hide_empty' => true,
];
- $key = $this->cache->generateKey($args);
- $cached = $this->cache->get($key);
- if ($cached) {
- return new WP_REST_Response($cached);
- }
+ $data = $this->cache->remember(
+ $args,
+ function() use ($args, $taxonomy) {
+ return $this->formatTerms($args, $taxonomy);
+ }
+ );
- $formatted = $this->formatTerms($args, $taxonomy);
$response = [
- 'items' => $formatted
+ 'items' => $data
];
- $this->cache->set($key, $response);
- return new WP_REST_Response($response);
+
+ return $this->success($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)) {
- return $this->getTermsForContentType($request);
+ $registrar = Registrar::getInstance($content_type);
+ if ($registrar->hasFeature('is_content')) {
+ //TODO: Not sure what we're trying for here. Doesn't seem to be used.
+ //TODO: Likely for taxonomy content types, like tattoo shops
+ return $this->emptyResult();
}
}
- $taxonomy = BASE.$request->get_param('taxonomy');
+ $taxonomy = jvbCheckBase($request->get_param('taxonomy'));
+ if (!taxonomy_exists($taxonomy)) {
+ return $this->emptyResult();
+ }
$search = $request->get_param('search');
- $parent = (int)$request->get_param('parent');
- $page = max(1, (int)$request->get_param('page'));
- $per_page = max(20, (int)$request->get_param('per_page'));
- 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
- ]
- ]);
- }
+ $parent = (int)$data['parent']??0;
+ $page = max(1, (int)($data['page']??1));
+ $per_page = 25;
+
$tax_obj = get_taxonomy($taxonomy);
$is_hierarchical = $tax_obj->hierarchical;
// If searching, handle differently
if (!empty($search)) {
- return $this->handleTermSearch($request);
+ error_log('Handling search...');
+
+ return $this->handleTermSearch($request);
}
// Get terms for current level with child count
$args = [
'taxonomy' => $taxonomy,
- 'hide_empty' => false,
+ 'hide_empty' => true,
'parent' => $parent,
'number' => $per_page,
'orderby'=> 'name',
@@ -243,21 +229,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);
- $manager = new UserTermsManager();
- $related = $manager->getUserTermIDs($userID, $taxonomy);
+ $userID = get_post_meta($main_context['id'], BASE.'profile_link', true);
+ $manager = UserTermsManager::getInstance();
+ $related = $manager->fetchUserTerms($userID, $taxonomy);
if (empty($related)) {
- 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();
}
$args['include'] = $related;
@@ -266,20 +243,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 = TaxonomyRelationships::getInstance();
$related = $manager->getRelatedTerms($ID, BASE.$request->get_param('taxonomy'));
if (empty($related)) {
- 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();
}
$args['tax_query'] = [
'taxonomy' => $taxonomy,
@@ -292,7 +260,7 @@
$match = $request->get_param('match') ?? 'any';
$context = json_decode($request['context'], true);
- $relationshipManager = new TaxonomyRelationships();
+ $relationshipManager = TaxonomyRelationships::getInstance();
// Prepare array to collect term IDs that match the context
$related_term_ids = [];
@@ -328,178 +296,201 @@
$args['include'] = $related_term_ids;
} else {
// No related terms found, return empty result
- 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();
}
}
+ $response = $this->cache->remember(
+ $args,
+ function() use ($args, $taxonomy, $parent, $per_page, $page, $is_hierarchical) {
+ $formatted_terms = $this->formatTerms($args, $taxonomy);
+ // Get total count for pagination
+ $total_terms = wp_count_terms([
+ 'taxonomy' => $taxonomy,
+ 'hide_empty' => false,
+ 'parent' => $parent
+ ]);
+ // Calculate pagination
+ $total_pages = ceil($total_terms / $per_page);
+ $has_more = $page < $total_pages;
- $key = $this->cache->generateKey($args);
- $cache = $this->cache->get($key);
- $cache = false;
- if ($cache) {
- return $cache;
- }
+ return [
+ 'items' => $formatted_terms,
+ 'is_hierarchical' => $is_hierarchical,
+ 'pagination' => [
+ 'page' => $page,
+ 'per_page' => $per_page,
+ 'total_pages' => $total_pages,
+ 'total_terms' => (int)$total_terms
+ ],
+ 'has_more' => $has_more
+ ];
+ }
+ );
- $formatted_terms = $this->formatTerms($args, $taxonomy);
- // Get total count for pagination
- $total_terms = wp_count_terms([
- 'taxonomy' => $taxonomy,
- 'hide_empty' => false,
- 'parent' => $parent
- ]);
-
- // Calculate pagination
- $total_pages = ceil($total_terms / $per_page);
- $has_more = $page < $total_pages;
-
- $response = [
- 'items' => $formatted_terms,
- 'is_hierarchical' => $is_hierarchical,
- 'pagination' => [
- 'page' => $page,
- 'per_page' => $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->success($response);
}
+ protected function handleBatchTermRequest(string $taxonomy, array $data, WP_REST_Request $request):WP_REST_Response
+ {
+ $taxonomies = array_map('trim', explode(',', $taxonomy));
+ $all_terms = [];
+ $parent = (int)$data['parent']??0;
+ $page = max(1, (int)($data['page']??1));
+ $per_page = 25;
+ $mainArgs = [
+ 'hide_empty'=> false,
+ 'parent' => $parent,
+ 'number' => $per_page,
+ 'orderby' => 'name',
+ 'offset' => ($page -1) * $per_page,
+ ];
+
+ foreach ($taxonomies as $taxonomy) {
+ if (!taxonomy_exists(BASE.$taxonomy)) {
+ continue;
+ }
+ $args = $mainArgs;
+ $args['taxonomy'] = BASE.$taxonomy;
+
+ $all_terms = array_merge($all_terms, $this->formatTerms($args, $taxonomy));
+ }
+
+ $response = [
+ 'items' => $all_terms,
+ 'pagination'=> [
+ 'page' => $page,
+ 'per_page'=> $per_page
+ ],
+ 'has_more' => true,
+ ];
+
+ return $this->success($response);
+ }
+
+
/**
* @param array $args
* @param string $taxonomy
*
* @return array
*/
- protected function formatTerms(array $args, string $taxonomy):array
- {
- $terms = get_terms($args);
+ protected function formatTerms(array $args, string $taxonomy): array
+ {
+ return $this->cache->remember(
+ $args,
+ function() use ($args, $taxonomy) {
+ $terms = get_terms($args);
- if (is_wp_error($terms)) {
- return [];
- }
+ if (is_wp_error($terms)) {
+ return [];
+ }
+
+ $formatted_terms = [];
+ foreach ($terms as $term) {
+ $formatted_terms[] = $this->formatSingleTerm($term, $taxonomy);
+ }
+
+ return $formatted_terms;
+ }
+ );
+ }
- $formatted_terms = [];
- foreach ($terms as $term) {
- // Check for children explicitly
- $children_args = [
- 'taxonomy' => $taxonomy,
- 'parent' => $term->term_id,
- 'fields' => 'count',
- 'hide_empty' => false
- ];
- $count = wp_count_terms($children_args);
- $has_children = !is_wp_error($count) && $count > 0;
+ /**
+ * Format a single term with caching
+ *
+ * @param object $term WP_Term object
+ * @param string $taxonomy Full taxonomy name
+ *
+ * @return array Formatted term data
+ */
+ protected function formatSingleTerm(object $term, string $taxonomy): array
+ {
+ $cache_key = "{$term->term_id}_{$taxonomy}";
- $formatted_terms[] = [
- 'id' => $term->term_id,
- 'name' => $term->name,
- 'slug' => $term->slug,
- 'parent' => $term->parent,
- 'path' => $this->getTermPath($term->term_id, $term->name, $taxonomy),
- 'hasChildren' => $has_children,
- 'taxonomy' => $term->taxonomy,
- 'count' => $term->count,
- ];
- }
+ return $this->cache->remember($cache_key, function() use ($term, $taxonomy) {
+ $data = [
+ 'id' => $term->term_id,
+ 'name' => html_entity_decode($term->name),
+ 'slug' => $term->slug,
+ 'parent' => $term->parent,
+ 'path' => $this->getTermPath($term->term_id, $term->name, $taxonomy),
+ 'taxonomy' => jvbNoBase($term->taxonomy),
+ 'count' => $term->count,
+ ];
- return $formatted_terms;
- }
+ $children_args = [
+ 'taxonomy' => $taxonomy,
+ 'parent' => $term->term_id,
+ 'fields' => 'count',
+ 'hide_empty' => false
+ ];
+ $count = wp_count_terms($children_args);
+ $data['hasChildren'] = !is_wp_error($count) && $count > 0;
+
+
+ return $data;
+ });
+ }
/**
* @param WP_REST_Request $request
*
* @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' => false,
- '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(
+ $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) {
- $formatted_terms[$term->term_id] = [
- 'id' => $term->term_id,
- 'name' => $term->name,
- 'parent' => $term->parent,
- 'path' => $this->getTermPath($term->term_id, $term->name, $taxonomy),
- 'hasChildren' => (bool)$term->has_children,
- 'count' => (int)$term->count
- ];
- }
+ 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->success($data);
+ }
/**
* @param int $termID
@@ -540,314 +531,46 @@
delete_term_meta($termID, BASE.'term_path');
}
- /**
- * @param string $username
- * @param object $user
- *
- * @return void
- */
- public function clearUserTaxonomyCache(string $username, object $user):void
- {
- global $wpdb;
-
- // Get all transients for this user
- $like_pattern = $wpdb->esc_like(BASE.'user_' . $user->ID) . '_%';
-
- $transients = $wpdb->get_col($wpdb->prepare("
- SELECT option_name
- FROM {$wpdb->options}
- WHERE option_name LIKE %s
- AND option_name LIKE %s
- ", '_transient_' . $like_pattern, '%'));
-
- // Delete all found transients
- foreach ($transients as $transient) {
- delete_transient(str_replace('_transient_', '', $transient));
- }
- }
/**
* @param WP_REST_Request $request
*
* @return WP_REST_Response
*/
- public function getTermsForContentType(WP_REST_Request $request):WP_REST_Response
- {
- $manager = new TaxonomyRelationships();
- $content_type = BASE . $request->get_param('content');
- $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') ?: 20;
+ 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_for_{$content_type}_{$taxonomy}_" . md5("{$search}_{$page}_{$per_page}");
+ try {
+ $existing = term_exists($name, jvbCheckBase($taxonomy), $parent);
- $cache_key = $this->cache->generateKey([
- 'terms_for' => $content_type,
- 'taxonomy' => $taxonomy,
- 'search' => $search,
- 'page' => $page,
- 'per_page' => $per_page
- ]);
- $cache = $this->cache->get($cache_key);
- // Try cache first
- if ($cache !== false) {
- return new WP_REST_Response($cache);
- }
+ 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)
+ ]]);
+ }
- try {
- global $wpdb;
-
- // Starting the query building
- $query_args = [];
- $terms_query = "
- SELECT DISTINCT t.term_id, t.name, t.slug, tt.count, tt.taxonomy,
- (SELECT COUNT(DISTINCT tm.meta_key) FROM {$wpdb->termmeta} tm WHERE tm.term_id = t.term_id) AS meta_count
- FROM {$wpdb->terms} t
- JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
- JOIN {$manager->getTableName()} tr ON (
- (tr.primary_taxonomy = %s AND tr.primary_term_id = t.term_id)
- OR (tr.related_taxonomy = %s AND tr.related_term_id = t.term_id)
- )
- ";
-
- $query_args[] = $taxonomy;
- $query_args[] = $taxonomy;
-
- // Add content type filter through posts
- $query_where = " WHERE tt.taxonomy = %s";
- $query_args[] = $taxonomy;
-
- // Add search condition if provided
- if ($search) {
- $query_where .= " AND (t.name LIKE %s OR t.slug LIKE %s)";
- $search_like = '%' . $wpdb->esc_like($search) . '%';
- $query_args[] = $search_like;
- $query_args[] = $search_like;
- }
-
- // Add relationship strength ordering
- $query_order = " GROUP BY t.term_id";
- $query_order .= " ORDER BY COUNT(tr.id) DESC, tt.count DESC";
-
- // Add pagination
- $query_limit = " LIMIT %d OFFSET %d";
- $query_args[] = $per_page;
- $query_args[] = ($page - 1) * $per_page;
-
- // Combine the query
- $final_query = $query_where . $query_order . $query_limit;
-
- // Get terms
- $terms = $wpdb->get_results(
- $wpdb->prepare(
- $terms_query . $final_query,
- $query_args
- )
- );
- // Get total count for pagination
- $count_query = str_replace($query_limit, '', $query_where);
- $count_query = "SELECT COUNT(DISTINCT t.term_id) FROM {$wpdb->terms} t
- JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
- JOIN {$manager->getTableName()} tr ON (
- (tr.primary_taxonomy = %s AND tr.primary_term_id = t.term_id)
- OR (tr.related_taxonomy = %s AND tr.related_term_id = t.term_id)
- ) " . $count_query;
-
- // Remove pagination args
- array_pop($query_args);
- array_pop($query_args);
-
- $total = $wpdb->get_var(
- $wpdb->prepare(
- $count_query,
- $query_args
- )
- );
-
- // Format terms
- $formatted_terms = [];
- $is_hierarchical = is_taxonomy_hierarchical($taxonomy);
-
- foreach ($terms as $term) {
- $formatted_terms[$term->term_id] = [
- 'id' => $term->term_id,
- 'name' => $term->name,
- 'count' => $term->count,
- 'path' => $this->getTermPath($term->term_id, $term->name, $taxonomy),
- 'relationship_strength' => $term->relationship_count ?? 0
- ];
- }
-
- // Build response
- $total_pages = ceil($total / $per_page);
- $results = [
- 'items' => $formatted_terms,
- 'pagination' => [
- 'page' => (int)$page,
- 'per_page' => (int)$per_page,
- 'total_terms'=> $total,
- 'total_pages'=> $total_pages,
- '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 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;
-
- // 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 {
- // Build query args
- $args = [
- 'taxonomy' => $taxonomy,
- 'hide_empty' => false,
- '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[$term->term_id] = [
- 'id' => $term->term_id,
- 'name' => $term->name,
- 'count' => $term->count,
- 'parent' => $term->parent,
- '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));
-
- return new WP_REST_Response([
- 'success' => false,
- 'message' => 'Term already exists',
- 'term' => [
- 'id' => $term->term_id,
- 'name' => $term->name,
- 'path' => $this->getTermPath($term->term_id, $term->name, $taxonomy)
- ]
- ]);
- }
-
-
- if (jvbSiteHasTermApproval()) {
- // Get approval routes instance
- $approval_routes = JVB()->routes('approvals');
- // Create approval request
+ $membership = Site::membership();
+ if ($membership && $membership->has('term_approval')) {
+ $approval_routes = ApprovalRoutes::getInstance();
$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,
@@ -855,48 +578,50 @@
'pending' => true,
'request_id' => $request_id
]
- ];
- } else {
- $termID = wp_insert_term(
- $name,
- jvbCheckBase($taxonomy),
- [
- 'parent' => absint($parent??0)
- ]
- );
-
- 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) {
+ Errors::getInstance()->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