| | |
| | | use JVBase\rest\RestRouteManager; |
| | | use JVBase\managers\TaxonomyRelationships; |
| | | use JVBase\managers\UserTermsManager; |
| | | use JVBase\utility\Features; |
| | | use WP_REST_Request; |
| | | use WP_REST_Response; |
| | | use Exception; |
| | |
| | | parent::__construct(); |
| | | // $this->cache->invalidateGroup('terms'); |
| | | $this->per_page = 20; |
| | | |
| | | add_action('edited_term', [$this, 'deleteTermPath']); |
| | | add_action('wp_login', [$this, 'clearUserTaxonomyCache'], 10, 2); |
| | | } |
| | |
| | | public function getTermDetails(WP_REST_Request $request):WP_REST_Response |
| | | { |
| | | $data = $request->get_params(); |
| | | // Collect all taxonomies being queried |
| | | $taxonomies = array_keys($data); |
| | | |
| | | // Check HTTP cache headers |
| | | $cache_check = $this->checkHeaders($request, $taxonomies); |
| | | if ($cache_check) { |
| | | return $cache_check; |
| | | } |
| | | $terms = []; |
| | | foreach ($data as $tax => $IDs) { |
| | | $args = [ |
| | |
| | | |
| | | $terms[$tax] = $this->formatTerms($args, BASE.$tax); |
| | | } |
| | | return new WP_REST_Response([ |
| | | $response = new WP_REST_Response([ |
| | | 'items' => $terms, |
| | | ]); |
| | | return $this->addCacheHeaders($response); |
| | | } |
| | | |
| | | /** |
| | |
| | | public function handleTermSelectionRequest(WP_REST_Request $request):WP_REST_Response |
| | | { |
| | | $data = $request->get_params(); |
| | | $taxonomy = jvbCheckBase($data['taxonomy']); |
| | | $taxonomy = sanitize_text_field($data['taxonomy'])??''; |
| | | // Check HTTP cache headers |
| | | $cache_check = $this->checkHeaders($request, $taxonomy); |
| | | if ($cache_check) { |
| | | error_log('Header Check failed'); |
| | | return $cache_check; |
| | | } |
| | | |
| | | // 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 = [ |
| | |
| | | $key = $this->cache->generateKey($args); |
| | | $cached = $this->cache->get($key); |
| | | if ($cached) { |
| | | return new WP_REST_Response($cached); |
| | | $response = new WP_REST_Response($cached); |
| | | return $this->addCacheHeaders($response); |
| | | } |
| | | |
| | | $formatted = $this->formatTerms($args, $taxonomy); |
| | |
| | | 'items' => $formatted |
| | | ]; |
| | | $this->cache->set($key, $response); |
| | | return new WP_REST_Response($response); |
| | | $response = new WP_REST_Response($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)) { |
| | | return $this->getTermsForContentType($request); |
| | | $response = $this->getTermsForContentType($request); |
| | | return $this->addCacheHeaders($response); |
| | | } |
| | | } |
| | | |
| | | $taxonomy = BASE.$request->get_param('taxonomy'); |
| | | $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')); |
| | | |
| | | $parent = (int)$data['parent']??0; |
| | | $page = max(1, (int)($data['page']??1)); |
| | | $per_page = 25; |
| | | |
| | | if (!taxonomy_exists($taxonomy)) { |
| | | return new WP_REST_Response([ |
| | |
| | | |
| | | // If searching, handle differently |
| | | if (!empty($search)) { |
| | | return $this->handleTermSearch($request); |
| | | error_log('Handling search...'); |
| | | $response = $this->handleTermSearch($request); |
| | | return $this->addCacheHeaders($response); |
| | | } |
| | | |
| | | // Get terms for current level with child count |
| | |
| | | $related = $manager->getUserTermIDs($userID, $taxonomy); |
| | | |
| | | if (empty($related)) { |
| | | return new WP_REST_Response([ |
| | | $response = new WP_REST_Response([ |
| | | 'items' => [], |
| | | 'pagination' => [ |
| | | 'page' => 1, |
| | |
| | | 'has_more' => false |
| | | ] |
| | | ]); |
| | | return $this->addCacheHeaders($response); |
| | | } |
| | | |
| | | $args['include'] = $related; |
| | |
| | | $related = $manager->getRelatedTerms($ID, BASE.$request->get_param('taxonomy')); |
| | | |
| | | if (empty($related)) { |
| | | return new WP_REST_Response([ |
| | | $response = new WP_REST_Response([ |
| | | 'items' => [], |
| | | 'pagination' => [ |
| | | 'page' => 1, |
| | |
| | | 'has_more' => false |
| | | ] |
| | | ]); |
| | | return $this->addCacheHeaders($response); |
| | | } |
| | | $args['tax_query'] = [ |
| | | 'taxonomy' => $taxonomy, |
| | |
| | | $args['include'] = $related_term_ids; |
| | | } else { |
| | | // No related terms found, return empty result |
| | | return new WP_REST_Response([ |
| | | $response = new WP_REST_Response([ |
| | | 'items' => [], |
| | | 'pagination' => [ |
| | | 'page' => 1, |
| | |
| | | 'has_more' => false |
| | | ] |
| | | ]); |
| | | |
| | | return $this->addCacheHeaders($response); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | $key = $this->cache->generateKey($args); |
| | | $cache = $this->cache->get($key); |
| | | $cache = false; |
| | | |
| | | if ($cache) { |
| | | return $cache; |
| | | $response = new WP_REST_Response($cache); |
| | | return $this->addCacheHeaders($response); |
| | | } |
| | | |
| | | $formatted_terms = $this->formatTerms($args, $taxonomy); |
| | |
| | | ]; |
| | | |
| | | $this->cache->set($key, $response); |
| | | return new WP_REST_Response($response); |
| | | $response = new WP_REST_Response($response); |
| | | return $this->addCacheHeaders($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, |
| | | ] |
| | | ]; |
| | | |
| | | $response = new WP_REST_Response($response); |
| | | return $this->addCacheHeaders($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( |
| | | $this->cache->generateKey($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, true); |
| | | } |
| | | |
| | | 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, |
| | | 'parent' => $term->parent, |
| | | 'path' => $this->getTermPath($term->term_id, $term->name, $taxonomy), |
| | | 'hasChildren' => $has_children, |
| | | ]; |
| | | } |
| | | return $this->cache->remember($cache_key, function() use ($term, $taxonomy) { |
| | | $data = [ |
| | | 'id' => $term->term_id, |
| | | 'name' => $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 |
| | |
| | | $total_terms = wp_count_terms($count_args); |
| | | |
| | | $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 |
| | | ]; |
| | | } |
| | | foreach ($terms as $term) { |
| | | // Search results show path, so includeChildren = false for performance |
| | | $formatted_terms[] = $this->formatSingleTerm($term, $taxonomy, false); |
| | | } |
| | | |
| | | // Calculate pagination info |
| | | $total_pages = ceil($total_terms / $per_page); |
| | |
| | | $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 |
| | | ]; |
| | | } |
| | | foreach ($terms as $term) { |
| | | $formatted = $this->formatSingleTerm($term, $taxonomy, false); |
| | | // Add relationship strength which is unique to this method |
| | | $formatted['relationship_strength'] = $term->relationship_count ?? 0; |
| | | $formatted_terms[] = $formatted; |
| | | } |
| | | |
| | | // Build response |
| | | $total_pages = ceil($total / $per_page); |
| | |
| | | $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) |
| | | ]; |
| | | } |
| | | $formatted_terms = []; |
| | | foreach ($terms as $term) { |
| | | $formatted_terms[] = $this->formatSingleTerm($term, $taxonomy, false); |
| | | } |
| | | |
| | | // Get total for pagination |
| | | $total_args = array_merge($args, ['fields' => 'count', 'number' => '']); |
| | |
| | | $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)); |
| | | |
| | | $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', |
| | |
| | | } |
| | | |
| | | |
| | | if (jvbSiteHasTermApproval()) { |
| | | if (Features::forMembership()->has('term_approval')) { |
| | | error_log('Term Approval required'); |
| | | // Get approval routes instance |
| | | $approval_routes = JVB()->routes('approvals'); |
| | | // Create approval request |
| | |
| | | ] |
| | | ]; |
| | | } else { |
| | | error_log('Creating new Term: '); |
| | | $termID = wp_insert_term( |
| | | $name, |
| | | jvbCheckBase($taxonomy), |
| | | [ |
| | | 'parent' => absint($parent??0) |
| | | 'parent' => absint($parent) |
| | | ] |
| | | ); |
| | | error_log('Result: '.print_r($termID, true)); |
| | | |
| | | if (is_wp_error($termID)) { |
| | | throw new Exception('Failed to create new term'); |