From 42fa8304ddb811b0f725f245130f70c0f5e86a6c Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Tue, 04 Nov 2025 06:12:02 +0000
Subject: [PATCH] =Refactored LoginManager to be more extensible and configurable, as well as an AjaxRateLimiter

---
 inc/managers/CRUDManager.php |  157 ++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 138 insertions(+), 19 deletions(-)

diff --git a/inc/managers/CRUDManager.php b/inc/managers/CRUDManager.php
index 6deb11e..37b3a59 100644
--- a/inc/managers/CRUDManager.php
+++ b/inc/managers/CRUDManager.php
@@ -2,7 +2,9 @@
 namespace JVBase\managers;
 
 use JVBase\managers\UserTermsManager;
+use JVBase\meta\MetaForm;
 use JVBase\meta\MetaManager;
+use JVBase\utility\Features;
 use WP_User;
 
 if (!defined('ABSPATH')) {
@@ -19,6 +21,7 @@
 	protected array $filters;
 	protected array $bulkActions;
 	protected MetaManager $meta;
+	protected MetaForm $form;
 	protected array $taxonomies;
 	protected array $statuses;
 	protected array $fields;
@@ -47,6 +50,7 @@
 		];
 
 		$this->init();
+		add_filter('jvbAdditionalActions', [$this, 'createItem']);
 	}
 
 	protected function init():void
@@ -56,7 +60,7 @@
 		$this->initTaxonomies();
 		$this->initFilters();
 		$this->meta = new MetaManager(null, 'post', $this->content);
-
+		$this->form = new MetaForm();
 		$plural = strtolower($this->config['plural']??$this->content.'s');
 		$this->userCanPublish = (jvbUserIsVerified()) ?
 					user_can($this->user_id, "publish_{$plural}") : false;
@@ -192,13 +196,13 @@
 			'multiple'		=> true,
 			'destination'	=> 'post'
 		];
-		if (!jvbCheck('single_image', $this->config)) {
+		if (!array_key_exists('single_image', $this->config) || $this->config['single_image'] === false) {
 			$uploadConfig['destination'] = 'post_group';
 		}
 		$uploadConfig['destination'] = 'post_group';
 		if (!jvbCheck('single_image', $this->config)) {
-			$uploadConfig['group_title'] = 'Create '.$this->config['plural'];
-			$uploadConfig['group_description'] = '<p>Drag images into groups. Each group becomes its own '.$this->singular.'.</p>
+			$uploadConfig['label'] = 'Create '.$this->config['plural'];
+			$uploadConfig['upload_text'] = '<p>Drag images into groups. Each group becomes its own '.$this->singular.'.</p>
 						<p>You can also select multiple images and click the "Add to Group" button.</p>
 						<p>If a '.$this->singular.' has multiple images, you can select the '.jvbIcon('star').' to set an image as the main one.</p>
 						<p>Images left ungrouped will become individual '.$this->plural.'</p>
@@ -207,7 +211,6 @@
 			$uploadConfig['description'] = 'Each image will become its own '.$this->singular.'.';
 		}
 		?>
-		<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>
 		<details open class="uploader">
 			<summary class="row btw"><?= $this->config['upload_title'] ?? 'Bulk Upload '.$this->plural?></summary>
 			<?php
@@ -256,7 +259,7 @@
 	protected function renderFilters():void
 	{
 		?>
-		<div class="all-filters col start">
+		<div class="all-filters col start" data-ignore>
 			<div class="search row start nowrap">
 				<span class="label">Search:</span>
 				<?= jvbSearch() ?>
@@ -585,7 +588,7 @@
 
 	protected function renderModals():void
 	{
-		$this->renderCreateModal();
+//		$this->renderCreateModal();
 		$this->renderEditModal();
 		$this->renderBulkEditModal();
 	}
@@ -603,6 +606,7 @@
 		ob_start();
 		?>
 		<form class="edit-form" data-save="content" data-form-id="edit-<?=$this->content?>">
+			<?= jvbFormStatus() ?>
 			<input type="hidden" name="form-id" value="<?=uniqid('new-')?>" />
 			<input type="hidden" name="content" value="<?=$this->content?>" />
 			<div class="fields">
@@ -632,20 +636,59 @@
 				} else {
 					$tabs = false;
 				}
+
+				$isTimeline = Features::forContent($this->content)->has('is_timeline');
+
+
 				$fields = $this->fields;
+				if (!$isTimeline) {
+					$first = ['post_thumbnail', 'post_title', 'price'];
 
-				$first = ['post_thumbnail', 'post_title', 'price'];
-				foreach ($first as $f) {
-					if (array_key_exists($f, $fields)) {
-						if ($tabs) {
-							$tabs['basic']['content'] .= $this->meta->render('form', $f, $fields[$f], false, true);
-						} else {
-							$this->meta->render('form', $f, $fields[$f]);
+					foreach ($first as $f) {
+						if (array_key_exists($f, $fields)) {
+							if ($tabs) {
+								$tabs['basic']['content'] .= $this->meta->render('form', $f, $fields[$f], false, true);
+							} else {
+								$this->meta->render('form', $f, $fields[$f]);
+							}
+
+							unset($fields[$f]);
 						}
-
-						unset($fields[$f]);
 					}
 				}
+
+				if ($isTimeline) {
+					$temp = array_filter($fields, function ($field) {
+						if (array_key_exists('for_all', $field) && $field['for_all'] === true) {
+							return true;
+						}
+						return false;
+					});
+					$config = [
+						'type'		=> 'gallery',
+						'subtype'	=> 'timeline',
+						'data'		=> 'timeline',
+						'label'		=> 'Progression',
+						'fields'	=> $temp
+					];
+					$content = '';
+					foreach ($fields as $slug=> $field) {
+						if (!array_key_exists('for_all', $field) || $field['for_all'] === false) {
+							$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;
+				}
 				foreach ($fields as $n => $config) {
 					if ($tabs) {
 						$section = (array_key_exists('section', $config)) ? $config['section'] : 'basic';
@@ -653,10 +696,8 @@
 					} else {
 						$this->meta->render('form', $n, $config);
 					}
-
 				}
 
-
 				if ($tabs) {
 					jvbRenderTabs($tabs);
 				}
@@ -667,6 +708,58 @@
 		return ob_get_clean();
 	}
 
+
+	protected function renderTimelineFields():string
+	{
+		ob_start();
+
+
+		?>
+		<div class="repeater-field timeline-repeater" data-timeline data-field="fields">
+			<div class="repeater-rows" data-repeater-container>
+				<!-- Parent row (non-draggable) -->
+				<div class="repeater-row parent-row" data-row-index="0" data-id="">
+					<div class="row-header">
+						<h4>Before (Starting Point)</h4>
+					</div>
+					<div class="row-fields">
+						<?php $this->renderRowFields(); ?>
+					</div>
+				</div>
+
+				<!-- Child rows will be added dynamically -->
+			</div>
+
+			<button type="button" class="add-repeater-row btn secondary">
+				<?= jvbIcon('add') ?>
+				<span>Add Progress Step</span>
+			</button>
+		</div>
+		<?php
+		return ob_get_clean();
+	}
+
+	protected function renderRowFields():void
+	{
+		$fields = $this->fields;
+
+		// Render priority fields first
+		$first = ['post_thumbnail', 'post_title', 'price'];
+		foreach ($first as $f) {
+			if (array_key_exists($f, $fields)) {
+				$this->meta->render('form', $f, $fields[$f]);
+				unset($fields[$f]);
+			}
+		}
+
+		// Render remaining fields
+		foreach ($fields as $name => $config) {
+			if (!array_key_exists('hidden', $config) || !$config['hidden']) {
+				$this->meta->render('form', $name, $config);
+			}
+		}
+	}
+
 	protected function getApplicableStatuses(string $prefix) {
 		foreach ($this->statuses as $status => $config) {
 			if ($status === 'all') {
@@ -713,6 +806,7 @@
 		ob_start();
 		?>
 		<form class="bulk-edit-form" data-save="content" data-form-id="bulk-edit-<?=$this->content?>">
+			<?= jvbFormStatus() ?>
 			<div class="selected"></div>
 			<p class="description">You can unselect items by clicking the image here.</p>
 			<p class="hint"><strong>IMPORTANT: </strong> Whatever changes you make here will be applied to all selected <?=$this->plural?>.</p>
@@ -776,6 +870,18 @@
 		$this->renderGridView();
 		$this->renderTableView();
 		$this->renderTableRow();
+		if (Features::forContent($this->content)->has('is_timeline')) {
+			$temp = array_filter($this->fields, function ($field) {
+				if (array_key_exists('for_all', $field) && $field['for_all'] === true) {
+					return true;
+				}
+				return false;
+			});
+			$form = new MetaForm();
+			echo '<template class="uploadTimeline">';
+			$form->renderImagePreview(null,$temp);
+			echo '</template>';
+		}
 		echo jvbGetEmptyStateTemplate();
 		echo jvbGetGalleryPreviewTemplate();
 
@@ -886,7 +992,7 @@
 				  data-save="content"
 				  data-content="<?= esc_attr($this->content) ?>"
 				  data-form-id="content-table-<?= esc_attr($this->content) ?>">
-
+				<?= jvbFormStatus() ?>
 				<?= $this->renderTableActions() ?>
 
 				<table>
@@ -1024,4 +1130,17 @@
 		<?php
 		return ob_get_clean();
 	}
+
+	public function createItem(array $actions):array
+	{
+		ob_start();
+		$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>',
+			'content'	=> $content,
+		];
+		$actions[] = $create;
+		return $actions;
+	}
 }

--
Gitblit v1.10.0