Jake Vanderwerf
2025-11-10 e9967fa22781d922ba4eb8fb44fe72d200ac4b14
inc/managers/CRUDManager.php
@@ -28,6 +28,13 @@
   protected array $sections;
   protected array $stuck;
   //For Timeline-specific posts
   protected bool $isTimeline = false;
   protected array $nonTimelineFields = [];
   protected array $timelineSharedFields = [];
   protected array $timelineUniqueFields = [];
   protected bool $userCanPublish = false;
   public function __construct(string $content)
@@ -43,6 +50,7 @@
      $this->plural = $this->config['plural'];
      $this->content = $content;
      $this->fields = jvbGetFields($this->content, 'post');
      $this->maybeSetupTimeline();
      $this->sections = jvbGetSections($this->content, 'post');
      $this->stuck = [
         'post_title',
@@ -67,6 +75,34 @@
   }
   protected function maybeSetupTimeline():void {
      $this->isTimeline = Features::forContent($this->content)->has('is_timeline');
      if (!$this->isTimeline) {
         return;
      }
      $this->timelineSharedFields = array_keys(array_filter($this->fields, function ($field) {
         if (!array_key_exists('for_all', $field) || $field['for_all'] === false){
            return true;
         }
         return false;
      }));
      array_unshift($this->timelineSharedFields, 'post_thumbnail');
      array_unshift($this->timelineSharedFields, 'post_title');
      $this->timelineUniqueFields = array_keys(array_filter($this->fields, function ($field) {
         if (array_key_exists('for_all', $field) && $field['for_all'] === true) {
            return true;
         }
         return false;
      }));
      $all = array_merge($this->timelineUniqueFields, $this->timelineSharedFields);
      $this->nonTimelineFields = array_filter($this->fields, function ($field) use ($all) {
         return !in_array($field, $all);
      }, ARRAY_FILTER_USE_KEY);
   }
   protected function initTaxonomies():void
   {
      $this->taxonomies = array_filter(JVB_TAXONOMY, function ($config) {
@@ -84,41 +120,41 @@
            ],
            'future'=> [
               'label'  => 'Upcoming',
               'icon'   => 'future',
               'icon'   => 'clock-clockwise',
            ],
            'past'   => [
               'label'  => 'Past',
               'icon'   => 'past',
               'icon'   => 'clock-counter-clockwise',
            ],
            'repeat'=> [
               'label'  => 'Recurring',
               'icon'   => 'repeat',
            ],
            'draft'  => [
               'icon'   => 'hide',
               'icon'   => 'eye-closed',
               'label'  => 'Hidden',
            ],
            'trash'  => [
               'label'  => 'Scrapped',
               'icon'   => 'delete',
               'icon'   => 'trash',
            ],
         ] :
         [
            'all' => [
               'icon'  => 'all',
               'icon'  => 'infinity',
               'label' => 'Everything',
            ],
            'publish'=> [
               'icon'   => 'publish',
               'icon'   => 'eye',
               'label'  => 'Live',
            ],
            'draft'  => [
               'icon'   => 'hide',
               'icon'   => 'eye-closed',
               'label'  => 'Hidden',
            ],
            'trash'  => [
               'label'  => 'Scrapped',
               'icon'   => 'delete',
               'icon'   => 'trash',
            ],
         ];
   }
@@ -147,7 +183,7 @@
      foreach ($this->taxonomies as $taxonomy=> $config) {
         $this->filters['taxonomy'][$taxonomy] = [
            'label'  => $config['singular'],
            'icon'   => $taxonomy
            'icon'   => $config['icon']??'folder'
         ];
      }
   }
@@ -248,9 +284,9 @@
      ob_start();
      ?>
      <div class="empty-state">
         <h3><?=jvbIcon($this->content)?>Nothing here<?=jvbIcon($this->content)?></h3>
         <h3><?=jvbIcon($this->config['icon'])?>Nothing here<?=jvbIcon($this->config['icon'])?></h3>
         <p>It doesn't look like you have any <?=$this->config['plural'] ?> yet.</p>
         <p><small><i>Add many by uploading images above.</i>, or click the "<?=jvbIcon('add')?>" button to add one at a time.</small></p>
         <p><small><i>Add many by uploading images above.</i>, or click the "<?=jvbIcon('plus-square')?>" button to add one at a time.</small></p>
      </div>
      <?php
      return ob_get_clean();
@@ -278,7 +314,7 @@
               $this->renderDateFilters();
            ?>
            <button type="button" class="clear-filters row" hidden>
               <?= jvbIcon('close', ['title'    => 'Clear']); ?>
               <?= jvbIcon('x', ['title'    => 'Clear']); ?>
               Clear All Filters
            </button>
         </div>
@@ -295,12 +331,12 @@
         <?php
            $order = [
               'orderby' => [
                  'date' => 'Order by date created',
                  'calendar' => 'Order by date created',
                  'alphabetical' => 'Order alphabetically'
               ],
               'order' => [
                  'asc' => 'In ascending order (Z-A, oldest to newest)',
                  'desc' => 'In descending order (A-Z, newest to oldest)'
                  'sort-ascending' => 'In ascending order (Z-A, oldest to newest)',
                  'sort-descending' => 'In descending order (A-Z, newest to oldest)'
               ]
            ];
@@ -360,8 +396,8 @@
         <?php
         $views = [
            'grid' => ['icon' => 'grid', 'label' => 'Grid View'],
            'list' => ['icon' => 'list', 'label' => 'List View'],
            'grid' => ['icon' => 'squares-four', 'label' => 'Grid View'],
            'list' => ['icon' => 'rows', 'label' => 'List View'],
            'table' => ['icon' => 'table', 'label' => 'Table View']
         ];
@@ -605,7 +641,7 @@
   {
      ob_start();
      ?>
      <form class="edit-form" data-save="content" data-form-id="edit-<?=$this->content?>">
      <form class="edit-form" data-save="content" data-form-id="edit-<?=$this->content?>" data-autosave<?= ($this->isTimeline) ? ' data-timeline' : ''?>>
         <?= jvbFormStatus() ?>
         <input type="hidden" name="form-id" value="<?=uniqid('new-')?>" />
         <input type="hidden" name="content" value="<?=$this->content?>" />
@@ -637,11 +673,9 @@
               $tabs = false;
            }
            $isTimeline = Features::forContent($this->content)->has('is_timeline');
            $fields = $this->fields;
            if (!$isTimeline) {
            if (!$this->isTimeline) {
               $first = ['post_thumbnail', 'post_title', 'price'];
               foreach ($first as $f) {
@@ -657,13 +691,11 @@
               }
            }
            if ($isTimeline) {
            if ($this->isTimeline) {
               $temp = array_filter($fields, function ($field) {
                  if (array_key_exists('for_all', $field) && $field['for_all'] === true) {
                     return true;
                  }
                  return false;
               });
                  return in_array($field, $this->timelineUniqueFields);
               }, ARRAY_FILTER_USE_KEY);
               $config = [
                  'type'      => 'gallery',
                  'subtype'   => 'timeline',
@@ -673,21 +705,16 @@
               ];
               $content = '';
               foreach ($fields as $slug=> $field) {
                  if (!array_key_exists('for_all', $field) || $field['for_all'] === false) {
                  if (in_array($slug, $this->timelineSharedFields)) {
                     $content .= $this->form->render($slug, null, $field, false, true);
                  }
               }
               $content .= $this->meta->render('form', 'timeline', $config, false,true);
               $tabs['progression']['content'] = $content;
               $this->fields = array_filter($fields, function ($field) {
                  if (array_key_exists('for_all', $field) && $field['for_all'] === true) {
                     return false;
                  }
                  return true;
               });
               $fields = $this->fields;
               $fields = $this->nonTimelineFields;
            }
            foreach ($fields as $n => $config) {
               if ($tabs) {
@@ -731,7 +758,7 @@
         </div>
         <button type="button" class="add-repeater-row btn secondary">
            <?= jvbIcon('add') ?>
            <?= jvbIcon('plus-square') ?>
            <span>Add Progress Step</span>
         </button>
      </div>
@@ -769,7 +796,7 @@
            if ($status === 'future') {
               $status = 'publish';
               $config = [
                  'icon'   => 'publish',
                  'icon'   => 'eye',
                  'label'  => 'Live',
               ];
            } else {
@@ -870,16 +897,13 @@
      $this->renderGridView();
      $this->renderTableView();
      $this->renderTableRow();
      if (Features::forContent($this->content)->has('is_timeline')) {
      if ($this->isTimeline) {
         $temp = array_filter($this->fields, function ($field) {
            if (array_key_exists('for_all', $field) && $field['for_all'] === true) {
               return true;
            }
            return false;
         });
            return in_array($field, $this->timelineUniqueFields);
         }, ARRAY_FILTER_USE_KEY);
         $form = new MetaForm();
         echo '<template class="uploadTimeline">';
         $form->renderImagePreview(null,$temp);
         echo '<template class="timelineItem">';
         $form->renderImagePreview(null,['fields' => $temp]);
         echo '</template>';
      }
      echo jvbGetEmptyStateTemplate();
@@ -917,11 +941,11 @@
      ?>
      <div class="item-actions">
         <button type="button" class="action" data-action="edit" title="Edit <?= $this->singular ?>">
            <?=jvbIcon('edit')?>
            <?=jvbIcon('pencil-simple')?>
            <span class="screen-reader-text">Edit <?= $this->singular ?></span>
         </button>
         <button type="button" class="action" data-action="trash" title="Scrap <?= $this->singular ?>">
            <?=jvbIcon('delete')?>
            <?=jvbIcon('trash')?>
            <span class="screen-reader-text">Scrap <?= $this->singular ?></span>
         </button>
<!--        <button type="button" class="action" data-action="toggle-status">-->
@@ -1060,7 +1084,7 @@
            if ($status === 'future') {
               $status = 'publish';
               $config = [
                  'icon' => 'publish',
                  'icon' => 'eye',
                  'label' => 'Live'
               ];
            } elseif ($status === 'past') {
@@ -1118,12 +1142,12 @@
            'vertical',
            'TAB NAV:',
            '',
            jvbIcon('down'),
            jvbIcon('right')
            jvbIcon('caret-double-down'),
            jvbIcon('caret-double-right')
         ) ?>
         <button type="button" class="add-row" title="Add new row">
            <?= jvbIcon('add') ?>
            <?= jvbIcon('plus-square') ?>
            <span>Add Row</span>
         </button>
      </div>
@@ -1137,7 +1161,7 @@
      $this->renderCreateModal();
      $content = ob_get_clean();
      $create = [
         'button' => '<button type="button" class="create-item row" title="Create New '.$this->singular.'">'.jvbIcon('add').'<span class="screen-reader-text">Create New '.$this->singular.'</span></button>',
         'button' => '<button type="button" class="create-item row" title="Create New '.$this->singular.'">'.jvbIcon('plus-square').'<span class="screen-reader-text">Create New '.$this->singular.'</span></button>',
         'content'   => $content,
      ];
      $actions[] = $create;