Jake Vanderwerf
2026-03-03 772462eeca3002a1d52508aeba485aab2b4742ad
inc/rest/routes/ContentRoutes.php
@@ -5,18 +5,15 @@
use JVBase\managers\queue\executors\ContentExecutor;
use JVBase\managers\queue\TypeConfig;
use JVBase\meta\Meta;
use JVBase\registrar\Registrar;
use JVBase\rest\PermissionHandler;
use JVBase\rest\Response;
use JVBase\rest\Rest;
use JVBase\managers\Cache;
use JVBase\rest\Route;
use JVBase\utility\Features;
use WP_Post;
use WP_Query;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use Exception;
if (!defined('ABSPATH')) {
   exit; // Exit if accessed directly
@@ -76,20 +73,39 @@
      Route::for('content')
         ->get([$this, 'getContent'])
         ->auth(PermissionHandler::combine(['user', 'nonce', ['actionNonce'=>'dash-']]))
         ->args([
            'content' => 'string|required',
            'status' => 'string|default:all',
            'page' => 'integer|default:1|min:1',
            'per_page' => 'integer|default:30|min:1|max:100',
            'orderby' => 'string|enum:date,alphabetical|default:date',
            'order' => 'string|enum:asc,desc|default:desc',
            'search' => 'string',
            'date-filter' => 'string',
            'dateFrom' => 'string',
            'dateTo' => 'string',
         ])
         ->rateLimit(20)
         ->post([$this, 'postContent'])
         ->auth(PermissionHandler::combine(['user', 'nonce', ['actionNonce'=>'dash-']]))
         ->rateLimit(30);
         ->rateLimit(30)
         ->args([
            'user'   => 'int|required',
            'posts' => 'required',
            'content' => 'string',
         ])
         ->register();
   }
   protected function initTimelineFields(string $content): void
   {
      $content = jvbNoBase($content);
      if (!Features::forContent($content)->has('is_timeline')) {
      $config = Registrar::getInstance($content);
      if (!$config || !$config->hasFeature('is_timeline')) {
         return;
      }
      $config = Features::getConfig($content);
      $this->fields = $config['fields'];
      $this->fields = $config->getFields();
      $this->timelineSharedFields = $this->getTimelineSharedFields($content);
      array_unshift($this->timelineSharedFields, 'post_thumbnail');
@@ -102,11 +118,12 @@
   public function getTimelineUniqueFields(string $content): array
   {
      $content = jvbNoBase($content);
      if (!Features::forContent($content)->has('is_timeline')) {
      $registrar = Registrar::getInstance($content);
      if (!$registrar || !$registrar->hasFeature('is_timeline')) {
         return [];
      }
      $config = Features::getConfig($content);
      $allFields = $config['fields'];
      $allFields = $registrar->getFields();
      return array_keys(array_filter($allFields, function ($field) {
         if (array_key_exists('for_all', $field) && $field['for_all'] === true) {
@@ -119,14 +136,12 @@
   public function getTimelineSharedFields(string $content): array
   {
      $content = jvbNoBase($content);
      if (!Features::forContent($content)->has('is_timeline')) {
      $registrar = Registrar::getInstance($content);
      if (!$registrar || !$registrar->hasFeature('is_timeline')) {
         return [];
      }
      $config = Features::getConfig($content);
      if (!$config || empty($config)) {
         return [];
      }
      $allFields = $config['fields'] ?? [];
      $allFields = $registrar->getFields()??[];
      return array_keys(array_filter($allFields, function ($field) {
         if (!array_key_exists('for_all', $field) || $field['for_all'] === false) {
@@ -151,6 +166,7 @@
         return Response::success(['message'=>'No posts found in request']);
      }
      $count = count($data['posts']);
      $operationId = $data['id'];
      unset($data['user']);
@@ -184,6 +200,7 @@
   public function getContent(WP_REST_Request $request): WP_REST_Response
   {
      $params = $request->get_params();
      error_log('getContent params: '.print_r($params, true));
      $user_id = $params['user'];
      $post_status = $params['status'];
@@ -206,12 +223,14 @@
         'post_status' => $post_status
      ];
      //Only top level posts for timeline types
      if (Features::forContent($post_type)->has('is_timeline')) {
      $registrar = Registrar::getInstance($post_type);
      if ($registrar && $registrar->hasFeature('is_timeline')) {
         $args['post_parent'] = 0;
      }
      //Calendar filters
      if (Features::forContent($post_type)->has('is_calendar')) {
      if ($registrar && $registrar->hasFeature('is_calendar')) {
         $args = $this->applyCalendarFilters($args, $params);
      }
      $taxonomies = array_filter($params, function ($param) {
@@ -262,7 +281,7 @@
      $query = new WP_Query($args);
      $this->fields = jvbGetFields(str_replace('-', '_', $this->post_type));
      $this->fields = Registrar::getFieldsFor(str_replace('-', '_', $this->post_type));
      $this->taxonomies = $this->getTaxonomies($this->post_type);
      $posts = array_map([$this, 'prepareItem'], $query->posts);
@@ -369,16 +388,19 @@
    */
   protected function getTaxonomies(string $content): array
   {
      $taxonomy_for = jvbGlobalTaxonomyFor();
      $out = [];
      foreach ($taxonomy_for as $tax => $postTypes) {
         if (in_array($content, $postTypes)) {
            $out[BASE . $tax] = [
               'label' => JVB_CONTENT[$content]['plural'],
               'icon' => $tax,
            ];
         }
      $registrar = Registrar::getInstance($content);
      if (!$registrar) {
         return [];
      }
      $out = [];
      foreach ($registrar->registrar->taxonomies as $tax) {
         $taxReg = Registrar::getInstance($tax);
         $out[jvbCheckBase($tax)] = [
            'label'  => $taxReg->getPlural(),
            'icon'   => $taxReg->getIcon()??jvbDefaultIcon()
         ];
      }
      return $out;
   }
@@ -405,11 +427,13 @@
    */
   protected function prepareItem(WP_Post $post, bool $skip = false, bool $fields = true): array
   {
      if (!$skip && Features::forContent($post->post_type)->has('is_timeline')) {
      $registrar = Registrar::getInstance($post->post_type);
      if (!$skip && $registrar && $registrar->hasFeature('is_timeline')) {
         $this->initTimelineFields($post->post_type);
         return $this->formatTimeline($post);
      }
      $this->meta = Meta::forPost($post->ID);
      $fields = ($fields) ? $this->meta->getAll() : [];
      $data = [
         'id' => $post->ID,
         'title' => $post->post_title,
@@ -420,7 +444,7 @@
         'alt' => get_post_meta(get_post_thumbnail_id(), '_wp_attachment_image_alt', true),
         'icon' => $this->post_type,
         'taxonomies' => [],
         'fields' => ($fields) ? $this->meta->getAll() : [],
         'fields' => $fields,
         'images' => [],
      ];
@@ -455,25 +479,69 @@
      $images = [];
      $get = [];
      $fields = (empty($fields)) ? $this->fields : $fields;
      foreach ($fields as $field => $config) {
         if ($config['type'] === 'gallery' || $config['type'] === 'image' || $field === 'post_thumbnail') {
            $get[] = $field;
         }
      }
      $get = $this->getUploadFields($fields);
      if (!empty($get)) {
         $allImages = $this->meta->getAll($get);
         $actualGet = array_map(function($fieldName) {
            return (str_contains($fieldName, ':')) ? strtok($fieldName, ':') : $fieldName;
         }, $get);
         $complex = array_map(function($item) {
            return explode(':', $item);
         },array_filter($get, function($fieldName) {
            return str_contains($fieldName, ':');
         }));
         $allImages = $this->meta->getAll($actualGet);
         foreach ($allImages as $k => $imgs) {
            $temp = explode(',', $imgs);
            foreach ($temp as $img) {
               if (is_numeric($img) && !array_key_exists($img, $images)) {
                  $images[$img] = jvbImageData((int)$img);
            //It's a complex field
            if (is_array($imgs)) {
               foreach ($imgs as $row) {
                  foreach ($row as $fName => $fValue) {
                     foreach ($complex as $c) {
                        if (in_array($k, $c)) {
                           foreach ($c as $complexField) {
                              if ($complexField === $fName) {
                                 $images = $this->addImages($fValue, $images);
                              }
                           }
                        }
                     }
                  }
               }
            } else {
               $images = $this->addImages($imgs, $images);
            }
         }
      }
      return $images;
   }
   public function addImages(string $imgs, array $images):array
   {
      $temp = explode(',', $imgs);
      foreach ($temp as $img) {
         if (is_numeric($img) && !array_key_exists($img, $images)) {
            $images[$img] = jvbImageData((int)$img);
         }
      }
      return $images;
   }
   public function getUploadFields($fields):array
   {
      $get = [];
      foreach ($fields as $field => $config) {
         if (in_array($config['type'], ['group', 'repeater'])) {
            $nestedUploads = $this->getUploadFields($config['fields']);
            foreach ($nestedUploads as $nested) {
               $get[] = $field.':'.$nested;
            }
         } elseif ($config['type'] === 'upload' || $config['type'] === 'gallery' || $config['type'] === 'image' ) {
            $get[] = $field;
         }
      }
      return $get;
   }
   public function formatTimeline(WP_Post $post): array
   {