Jake Vanderwerf
2026-01-05 9f86429a1252b45c95b7c62fbaa1b82de3723997
inc/rest/routes/TermRoutes.php
@@ -5,6 +5,7 @@
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;
@@ -23,6 +24,7 @@
        parent::__construct();
//    $this->cache->invalidateGroup('terms');
        $this->per_page = 20;
      $this->cache->clear();
        add_action('edited_term', [$this, 'deleteTermPath']);
        add_action('wp_login', [$this, 'clearUserTaxonomyCache'], 10, 2);
    }
@@ -180,9 +182,8 @@
    public function handleTermSelectionRequest(WP_REST_Request $request):WP_REST_Response
    {
      $data = $request->get_params();
      $taxonomy = jvbCheckBase($data['taxonomy']);
      $taxonomy = jvbCheckBase($data['taxonomy'])??'';
      error_log('Term Request Data for '.$taxonomy.': '.print_r($data, true));
      // Check HTTP cache headers
      $cache_check = $this->checkHeaders($request, $taxonomy);
      if ($cache_check) {
@@ -190,6 +191,11 @@
         return $cache_check;
      }
      // Handle batch request (multiple taxonomies)
      if (str_contains($taxonomy, ',')) {
         return $this->handleBatchTermRequest($taxonomy, $data, $request);
      }
      if (array_key_exists('termIDs', $data)) {
         $args = [
            'taxonomy'  => $taxonomy,
@@ -223,9 +229,10 @@
        $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([
@@ -371,9 +378,9 @@
        $key = $this->cache->generateKey($args);
        $cache = $this->cache->get($key);
      $cache = false;
        if ($cache) {
            $response = new WP_ReST_Response($cache);
            $response = new WP_REST_Response($cache);
         return $this->addCacheHeaders($response);
        }
@@ -406,48 +413,110 @@
      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,
            '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' => $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
@@ -498,16 +567,10 @@
        $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);
@@ -698,15 +761,12 @@
            $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);
@@ -790,16 +850,10 @@
            $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' => '']);
@@ -842,13 +896,15 @@
        $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',
@@ -861,7 +917,8 @@
            }
         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
@@ -885,13 +942,15 @@
               ]
            ];
         } 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');