Jake Vanderwerf
2026-09-18 a6413da67a4579866f0fd0323ddb23a7b6b9654a
inc/rest/Rest.php
@@ -1,10 +1,14 @@
<?php
namespace JVBase\rest;
use JVBase\inc\managers\ErrorHelper;
use JVBase\integrations\services\Cloudflare;
use JVBase\managers\Cache;
use JVBase\managers\Errors;
use JVBase\meta\Meta;
use JVBase\registrar\Registrar;
use JVBase\base\Site;
use JVBase\rest\routes\TermRoutes;
use WP_REST_Request;
use WP_REST_Response;
use Exception;
@@ -27,10 +31,11 @@
 */
abstract class Rest
{
   use ErrorHelper;
   protected string $namespace = 'jvb/v1';
   protected ?Cache $cache = null;
   protected string $cacheName = '';
   protected int $cacheTtl = 3600;
   protected int $cacheTtl = HOUR_IN_SECONDS;
   protected static ?string $action;
   public function __construct()
@@ -39,9 +44,15 @@
         $this->cache = Cache::for($this->cacheName, $this->cacheTtl);
      }
      add_action('rest_api_init', [$this, 'registerRoutes']);
      add_action('rest_api_init', [$this, 'registerRoutes'], 10);
      add_action('rest_api_init', [$this, 'ensureDefinitions'], 9);
   }
   public function ensureDefinitions():void
   {
      Site::getInstance();
      Registrar::ensureInstanced();
   }
   /**
    * Register routes - implement using Route builder
    */
@@ -174,7 +185,7 @@
   /**
    * Convert MySQL datetime to ISO 8601 timestamp
    */
   protected function formatTimestamp(?string $mysqlDatetime): ?string
   public function formatTimestamp(?string $mysqlDatetime): ?string
   {
      return Response::formatTimestamp($mysqlDatetime);
   }
@@ -224,7 +235,7 @@
      // Keep existing author filtering logic
      $authorQuery = [];
      foreach (Registrar::getFeatured('can_create', 'user') as $type) {
      foreach (Registrar::withFeature('can_create', 'user') as $type) {
         if (array_key_exists($type, $data)) {
            $artist_ids = array_map(
               'absint',
@@ -477,10 +488,20 @@
    */
   protected function checkUser(int $userId): bool
   {
      $cache = Cache::for('checkUser', DAY_IN_SECONDS)->connect('user');
      $cache = Cache::for('checkUser', 'user',DAY_IN_SECONDS);
      return $cache->remember($userId, fn() => (bool) get_userdata($userId));
   }
   protected function checkArray(string $value, array $search, bool $lowercase = true):string|false
   {
      if ($lowercase) {
         $value = strtolower($value);
      }
      return in_array($value, $search) ? $value : false;
   }
   /**
    * Check if term exists (cached)
    */
@@ -493,7 +514,7 @@
         return false;
      }
      $cache = Cache::for('checkTerm', DAY_IN_SECONDS)->connect('taxonomy');
      $cache = Cache::for('checkTerm', 'term', DAY_IN_SECONDS);
      return $cache->remember($termId, fn() => (bool) term_exists($termId, jvbCheckBase($taxonomy)));
   }
@@ -502,7 +523,7 @@
    */
   protected function isVerifiedUser(int $userId): bool
   {
      $cache = Cache::for('verifiedUsers', DAY_IN_SECONDS)->connect('user');
      $cache = Cache::for('verifiedUsers', 'user',DAY_IN_SECONDS);
      return $cache->remember($userId, fn() => user_can($userId, 'skip_moderation'));
   }
@@ -537,7 +558,7 @@
         return false;
      }
      $post_types = is_array($args['post_type']) ? $args['post_type'] : [$args['post_type']];
      $hasTimeline = array_map(function($item) { return jvbCheckBase($item); },Registrar::getFeatured('is_timeline', 'post'));
      $hasTimeline = array_map(function($item) { return jvbCheckBase($item); },Registrar::withFeature('is_timeline', 'post'));
      return !empty(array_intersect($post_types, $hasTimeline));
   }
   // =========================================================================
@@ -549,11 +570,11 @@
    */
   protected function verifyTurnstile(string $token): bool
   {
      if (!Site::hasIntegration('cloudflare') || !JVB()->connect('cloudflare')->isSetUp()) {
      if (!Site::hasIntegration('cloudflare') || !Cloudflare::getInstance()->isSetUp()) {
         return true;
      }
      return !empty($token) && JVB()->connect('cloudflare')->verifyTurnstile($token);
      return !empty($token) && Cloudflare::getInstance()->verifyTurnstile($token);
   }
   /**
@@ -626,24 +647,12 @@
      ]);
      try {
         JVB()->error()->log('security_audit', $event, $context, 'info');
         $this->logError($event,'auditLog', $context);
      } catch (Exception $e) {
         error_log("Security Audit: {$event} - " . json_encode($context));
      }
   }
   /**
    * Log errors with proper context
    */
   protected function logError(string $message, array $context = [], string $severity = 'error'): void
   {
      try {
         JVB()->error()->log(static::class, $message, $context, $severity);
      } catch (Exception $e) {
         error_log(static::class . " Error: {$message} - " . json_encode($context));
      }
   }
   /************************************************************
   SESSION FINGERPRINT
    ************************************************************/
@@ -872,12 +881,12 @@
         return $terms;
      }
      $ids = array_map('absint', explode(',',$value));
      $cache = Cache::for('term_data')->connect('taxonomy');
      $cache = Cache::for('term_data','term');
      $cache->flush();
      if (!array_key_exists($taxonomy, $terms)) {
         $terms[$taxonomy] = [];
         $registrar = Registrar::getInstance($taxonomy);
         $terms[$taxonomy]['icon'] = $registrar ? $registrar->getIcon() : jvbDefaultIcon();;
         $terms[$taxonomy]['icon'] = $registrar ? $registrar->getIcon() : jvbDefaultIcon();
      }
      foreach ($ids as $id) {
         $data = $cache->remember(
@@ -890,7 +899,7 @@
                     'name'   => $term->name,
                     'slug'   => $term->slug,
                     'parent' => $term->parent,
                     'path'   => JVB()->routes('term')->getTermPath($term->term_id, $term->name, $taxonomy),
                     'path'   => TermRoutes::getInstance()->getTermPath($term->term_id, $term->name, $taxonomy),
                     'taxonomy'  => jvbNoBase($term->taxonomy),
                     'count'  => $term->count,
                  ];