From 3d25ad7de4fdbb3eba2cde2a62422e6be5d79a0a Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Tue, 25 Aug 2026 22:57:22 +0000
Subject: [PATCH] =It's been a minute. I went through the Routes and associated Managers and ensured they played together well. Reworked the Cache.php, and I think I caught all the references. Moving away from JVBase() root class, to individuall classes that are Instanced. Double checked for the ABSPATH check in every file, and added index.php to every directory that didn't already have it. Also still working on the MenuBlock to work with WooCommerce for now for Northeh

---
 inc/meta/Form.php |  432 +++++++++++++++++++++++++++++++++--------------------
 1 files changed, 268 insertions(+), 164 deletions(-)

diff --git a/inc/meta/Form.php b/inc/meta/Form.php
index 3b54486..a553b32 100644
--- a/inc/meta/Form.php
+++ b/inc/meta/Form.php
@@ -2,6 +2,9 @@
 namespace JVBase\meta;
 
 use DateTime;
+use JVBase\base\Site;
+use JVBase\integrations\services\GoogleMaps;
+use JVBase\registrar\Registrar;
 
 if (!defined('ABSPATH')) {
 	exit;
@@ -25,7 +28,10 @@
 			$value = '';
 		}
 		if (!empty($config['hidden'])) {
-			return '';
+            if ($config['type'] !== 'upload') {
+                return static::renderHidden($name, $value, $config);
+            }
+            return '';
 		}
 
 		$type = $config['type'] ?? 'text';
@@ -52,12 +58,19 @@
 	/**
 	 * Render complete form from Meta instance
 	 */
-	public static function renderFormFrom(Meta $meta, string $endpoint, array $options = []): string
+	public static function renderFormFrom(Meta $meta, string $endpoint, array $options = [], array $fields = []): string
 	{
 		$id = $options['form-id'] ?? $endpoint;
 		$classes = isset($options['classes']) ? ' class="' . implode(' ', $options['classes']) . '"' : '';
+		$formID = isset($options['showFormID']) && $options['showFormID']!== false;
 
-		$output = '<form id="' . esc_attr($endpoint) . '"' . $classes . ' data-save="' . esc_attr($endpoint) . '" data-form-id="' . esc_attr($id) . '">';
+		$output = sprintf(
+			'<form id="%s"%s data-save="%s"%s>',
+			esc_attr($endpoint),
+			$classes,
+			esc_attr($endpoint),
+			$formID ? ' data-form-id="'.esc_attr($id).'"' : '',
+		);
 
 		if (!empty($options['heading'])) {
 			$output .= '<h2>' . esc_html($options['heading']) . '</h2>';
@@ -70,8 +83,11 @@
 			}
 		}
 
-		foreach ($meta->configs() as $name => $config) {
-			$output .= static::render($name, $meta->get($name), $config);
+		$allFields = $meta->getAll($fields);
+
+		foreach ($allFields as $name => $value) {
+			$config = $meta->config($name);
+			$output .= static::render($name, $value, $config);
 		}
 
 		if (!empty($options['submit'])) {
@@ -87,8 +103,11 @@
 	// Helper Methods
 	// ─────────────────────────────────────────────────────────────
 
-	protected static function fieldWrap(string $name, string $content, array $config): string
+	public static function fieldWrap(string $name, string $content, array $config, bool $col = false): string
 	{
+		if (!array_key_exists('type', $config)) {
+			jvbDump('No type set for '.$name.' with config: '.print_r($config, true));
+		}
 		$classes = static::buildClasses($config);
 		$datasets = static::buildDatasets($config);
 
@@ -106,7 +125,9 @@
 		$output .= static::buildCharacterLimit($config);
 		$output .= static::buildLabel($name, $config);
 		if (!array_key_exists('skipInput', $config)) {
-			$output .= static::buildInput($content);
+			$output .= static::buildInput($content, $col);
+		} else {
+			$output .= $content;
 		}
 
 		$output .= static::buildHint($config);
@@ -208,14 +229,15 @@
 			return '';
 		}
 
-		public static function buildInput(string $content):string
+		public static function buildInput(string $content, bool $col = false):string
 		{
 			return sprintf(
-				'<div class="field-input-wrapper">
+				'<div class="wrapper row%s">
 			%s
-			<span class="validation-icon success" hidden aria-hidden="true">%s</span>
-			<span class="validation-icon error" hidden aria-hidden="true">%s</span>
+			<span class="validation success" hidden aria-hidden="true">%s</span>
+			<span class="validation error" hidden aria-hidden="true">%s</span>
 			</div><span class="validation-message" hidden role="alert"></span>',
+				$col ? ' col' : '',
 				$content,
 				jvbIcon('check-circle'),
 				jvbIcon('x-circle')
@@ -303,6 +325,15 @@
 		return static::fieldWrap($name, $input, $config);
 	}
 
+    protected static function renderHidden(string $name, mixed $value, array $config):string
+    {
+        return sprintf(
+            '<input type="hidden" name="%s" value="%s">',
+            esc_attr($name),
+            esc_attr($value)
+        );
+    }
+
 	protected static function renderTextarea(string $name, mixed $value, array $config): string
 	{
 		$rows = $config['rows'] ?? 5;
@@ -343,13 +374,19 @@
 		if (!array_key_exists('class', $config)) {
 			$config['class']=[];
 		}
-		$config['class'][] ='quantity-input';
+		$config['class'][] = 'quantity-input';
+        $config['class'][] = 'row';
+        $config['class'][] = 'nowrap';
+
+        if (array_key_exists('isCart', $config) && $config['isCart'] === true) {
+
+        }
 
 		$attrs = static::inputAttrs($name, $config);
 
 		$value = ($value !== '') ? ' value="'.esc_attr($value).'"' : '';
 		$input = sprintf(
-			'<div class="quantity">
+			'<div class="row nowrap">
 				<button type="button" class="decrease" title="%s" aria-label="Decrease %s">%s</button>
 				<input type="number"%s%s />
 				<button type="button" class="increase" title="%s" aria-label="Increase %s">%s</button>
@@ -456,19 +493,21 @@
 		if (!array_key_exists('class', $config)) {
 			$config['class'] = [];
 		}
-		$config['class'][] ='row btw';
+		$config['class'][] ='row x-btw';
 
 		$checked = filter_var($value, FILTER_VALIDATE_BOOLEAN);
 
 		$input = sprintf(
-			'<label class="toggle-switch row">
+			'<label class="switch row">
                 <input type="checkbox" value="1"%s%s />
                 <div class="slider"></div>
+                %s
                 <span class="toggle-label">%s</span>
             </label>',
 			static::inputAttrs($name, $config),
 			$checked ? ' checked' : '',
-			array_key_exists('required', $config) && $config['required']===true ? '<span class="required" aria-label="required">*</span>' : ''
+			array_key_exists('required', $config) && $config['required']===true ? '<span class="required" aria-label="required">*</span>' : '',
+			$config['label']??''
 		);
 
 		unset($config['label']);
@@ -547,17 +586,17 @@
 			$checked = in_array($optValue, $values) ? ' checked' : '';
 			$checkboxes .= sprintf(
 				'
-                    <input type="checkbox" name="%s[]" id="%s-%s" value="%s"%s />
+                    <input type="checkbox" name="%s" id="%s-%s" value="%s"%s/>
 				<label class="checkbox-option" for="%s-%s">
                     <span>%s</span>
                 </label>',
 				esc_attr($name),
 				esc_attr($name),
-				$optValue,
+				esc_attr($optValue),
 				esc_attr($optValue),
 				$checked,
 				esc_attr($name),
-				$optValue,
+				esc_attr($optValue),
 				esc_html($optLabel)
 			);
 		}
@@ -570,30 +609,53 @@
 
 	protected static function renderRadio(string $name, mixed $value, array $config): string
 	{
-		$options = $config['options'] ?? [];
+		$options    = $config['options'] ?? [];
+		$inputClass = !empty($config['inputClass']) ? ' class="' . esc_attr($config['inputClass']) . '"' : '';
+		$idPrefix   = $config['idPrefix'] ?? '';
 
 		$radios = sprintf(
 			'<fieldset>
-			<legend>%s%s</legend>',
+        <legend>%s%s</legend>',
 			array_key_exists('label', $config) ? esc_html($config['label']) : 'Select an option',
-			array_key_exists('required', $config) && $config['required']===true ? '<span class="required" aria-label="required">*</span>' : ''
+			array_key_exists('required', $config) && $config['required'] === true
+				? '<span class="required" aria-label="required">*</span>' : ''
 		);
 
-		foreach ($options as $optValue => $optLabel) {
+
+		foreach ($options as $optValue => $optConfig) {
+			$class = '';
+			if (is_array($optConfig)) {
+				$optLabel    = $optConfig['label'] ?? $optValue;
+				$optIcon     = $optConfig['icon'] ?? null;
+				if ($optIcon) {
+					$class = ' class="btn"';
+				}
+				$optDisabled = !empty($optConfig['disabled']) ? ' disabled' : '';
+			} else {
+				$optLabel    = $optConfig;
+				$optIcon     = null;
+				$optDisabled = '';
+			}
+
+			$labelContent = $optIcon
+				? jvbDashIcon($optIcon)
+				: '<span>' . esc_html($optLabel) . '</span>';
+
+			$optId = esc_attr($idPrefix . $name . '-' . $optValue);
+
 			$radios .= sprintf(
-				'
-                    <input type="radio" name="%s" id="%s-%s" value="%s"%s />
-				<label class="radio-option" for="%s-%s">
-                    <span>%s</span>
-                </label>',
+				'<input type="radio" name="%s" id="%s" value="%s"%s%s%s%s />
+            <label class="radio-option" for="%s" title="%s">%s</label>',
 				esc_attr($name),
-				esc_attr($name),
-				$optValue,
+				$optId,
 				esc_attr($optValue),
-				checked($value, $optValue,false),
-				esc_attr($name),
-				$optValue,
-				esc_html($optLabel)
+				$class,
+				checked($value, $optValue, false),
+				$optDisabled,
+				$inputClass,
+				$optId,
+				esc_html($optLabel),
+				$labelContent
 			);
 		}
 
@@ -609,7 +671,7 @@
 			//File Type
 			'subtype'	=> 'image',		//'image', 'video', 'document', 'any'
 			'accepted'	=> null,		//null = use subtype defaults, or define an array of specific MIME types
-			//Upload Behavious
+			//Upload Behaviours
 			'multiple'	=> false,		//single or multiple uploads
 			'limit'		=> 15, 			//Max number of uploads (0 = unlimited)
 			'mode'		=> 'direct',	// 'direct' or 'selection' TODO: unneeded?
@@ -618,7 +680,8 @@
 			'max_size'	=> null,		//override default size limits
 			'convert'	=> 'webp',		//Image conversion format
 			'quality'	=> 90,			//Conversion quality
-			'inputData' => []
+			'inputData' => [],
+			'data'	=> []
 		];
 		$config = array_merge($defaults, $config);
 
@@ -628,7 +691,7 @@
 			return '';
 		}
 		$validate = [
-			'subtype'	=> ['image', 'video', 'document', 'any'],
+			'subtype'	=> ['image', 'video', 'document', 'any','timeline'],
 			'mode'		=> ['direct', 'selection'],
 			'destination'=> ['meta', 'post', 'post_group']
 		];
@@ -645,7 +708,9 @@
 		//Add upload config to the datasets (handled by fieldWrap())
 		$attrs = ['subtype', 'mode', 'destination', 'max_size'];
 		foreach ($attrs as $attr) {
-			$config['data'][$attr] = $config[$attr];
+			if (array_key_exists($attr, $config)) {
+				$config['data'][$attr] = $config[$attr];
+			}
 		}
 		$config['data']['upload-field'] = '';
 		$config['data']['type'] = $config['multiple'] ? 'gallery' : 'single';
@@ -655,16 +720,9 @@
 			$content = $config['content'];
 
 			$config['data']['content'] = $content;
-			$plural =
-				JVB_CONTENT[$content]['plural']
-				?? JVB_TAXONOMY[$content]['plural']
-				?? JVB_USER[$content]['plural']
-				?? str_replace('_', ' ', $content) . 's';
-
-			$singular = JVB_CONTENT[$content]['singular']
-				?? JVB_TAXONOMY[$content]['singular']
-				?? JVB_USER[$content]['singular']
-				?? str_replace('_', ' ',$config['content']);
+			$registrar = Registrar::getInstance($content);
+			$plural = $registrar->getPlural()??str_replace('_', ' ', $content).'s';
+			$singular = $registrar->getSingular()??str_replace('_', ' ', $content);
 		}
 		if ($config['limit'] > 0) {
 			$config['data']['max-files'] = $config['limit'];
@@ -672,7 +730,13 @@
 
 		$attachmentIds = static::parseIds($value);
 
+
 		$input = sprintf(
+			'<input type="hidden" name="%s" value="%s">',
+			esc_attr($name),
+			esc_attr(!empty($attachmentIds) ? implode(',', $attachmentIds) : '')
+		);
+		$input .= sprintf(
 			'<div class="file-upload-container">
 			<div class="file-upload-wrapper">
 				<input type="file"
@@ -726,6 +790,8 @@
 		}
 
 		$input .= '</div>'; // closes .file-upload-container
+
+
 		unset($config['description']);
 		unset($config['label']);
 		return static::fieldWrap($name, $input, $config);
@@ -737,7 +803,7 @@
 					<div class="preview-actions">
 						<div class="selection-controls">
 							<div class="selected">
-								<div class="field">
+								<div class="field checkbox">
 									<input type="checkbox" id="select-all-uploads" data-select-all data-selects="item-grid" name="select-all-uploads">
 									<label for="select-all-uploads">
 										Select All
@@ -748,7 +814,7 @@
 								</div>
 							</div>
 
-							<div class="selection-actions row btw" hidden>
+							<div class="selection-actions row x-btw" hidden>
 								<button type="button" data-action="add-to-group">
 									%sGroup
 								</button>
@@ -812,9 +878,9 @@
 				protected static function renderUploadItemActions(?int $attachmentId = null):string
 				{
 					return sprintf(
-						'<div class="item-actions row btw">
-						<div class="radio-button">
-							<input type="radio" class="featured btn" name="featured" id="featured%d" hidden>
+						'<div class="item-actions row x-btw">
+						<div class="btn">
+							<input type="radio" class="featured btn" name="featured" id="featured%s" hidden>
 							<label for="featured">
 								%s%s<span class="screen-reader-text">Set as featured image</span>
 							</label>
@@ -880,12 +946,12 @@
 								'label' => 'Video Caption',
 								'data'  => ['id' => $ID]
 							],
-							'image-description' => [
-								'type'  => 'textarea',
-								'value' => $description,
-								'label' => 'Video Description',
-								'data'  => ['id' => $ID]
-							]
+//							'image-description' => [
+//								'type'  => 'textarea',
+//								'value' => $description,
+//								'label' => 'Video Description',
+//								'data'  => ['id' => $ID]
+//							]
 						]
 					];
 
@@ -948,12 +1014,12 @@
 								'label' => 'File Caption',
 								'data'  => ['id' => $ID]
 							],
-							'image-description' => [
-								'type'  => 'textarea',
-								'value' => $description,
-								'label' => 'File Description',
-								'data'  => ['id' => $ID]
-							]
+//							'image-description' => [
+//								'type'  => 'textarea',
+//								'value' => $description,
+//								'label' => 'File Description',
+//								'data'  => ['id' => $ID]
+//							]
 						]
 					];
 
@@ -966,9 +1032,9 @@
 
 					return $out;
 				}
-				public static function renderImagePreview(?int $ID = null, ?array $additionalFields = null):string
+				public static function renderImagePreview(?int $ID = null, ?array $additionalFields = null, bool $isTemplate = false):string
 				{
-					$out = static::renderUploadItemStart($ID);
+					$out = static::renderUploadItemStart($ID, $isTemplate);
 					//add image preview
 					if ($ID) {
 						$out .= jvbFormatImage($ID, 'tiny', 'medium');
@@ -1010,30 +1076,30 @@
 								'label' => 'Image Caption',
 								'data'  => ['id' => $ID]
 							],
-							'image-description' => [
-								'type'  => 'textarea',
-								'value' => $description,
-								'label' => 'Image Description',
-								'data'  => ['id' => $ID]
-							]
+//							'image-description' => [
+//								'type'  => 'textarea',
+//								'value' => $description,
+//								'label' => 'Image Description',
+//								'data'  => ['id' => $ID]
+//							]
 						]
 					];
 
 					$out .= static::render('image_data', '', $fields);
-
-					$out .= static::renderUploadItemMetaEnd();
 					if ($additionalFields) {
 						$out .= static::additionalFields($additionalFields);
 					}
+					$out .= static::renderUploadItemMetaEnd();
 
 					return $out;
 				}
 				protected static function additionalFields(array $fields):string
 				{
-					$out = '';
+					$out = '<details class="fields"><summary>'.jvbDashIcon('edit').'Edit Fields</summary>';
 					foreach ($fields as $name => $config) {
 						$out .= static::render($name, '', $config);
 					}
+					$out .= '</details>';
 					return $out;
 				}
 
@@ -1108,6 +1174,9 @@
 
 		protected static function getAcceptedTypesLabel(array $config):string
 		{
+			if (!array_key_exists('subtype', $config) || $config['subtype'] === 'timeline') {
+				$config['subtype'] = 'image';
+			}
 			$labels = [
 				'image'	=> 'JPG, JPEG, PNG, GIF, or WEBP',
 				'video'	=> 'MP4, WEBM, or MOV',
@@ -1159,18 +1228,20 @@
 			'type'		=> $config['subtype'],
 		], $config);
 
-		$icon = match ($config['subtype']) {
-			'taxonomy' => JVB_TAXONOMY[$config['taxonomy']]['icon'] ?? jvbDefaultIcon(),
-			'content' => JVB_CONTENT[$config['content']]['icon'] ?? jvbDefaultIcon(),
-			'user' => JVB_USER[$config['role']]['icon'] ?? 'user',
-			default => jvbDefaultIcon(),
-		};
+		$registrar = Registrar::getInstance($config[$config['subtype']]);
+		$icon = jvbDefaultIcon();
+		if ($registrar){
+			$icon = $registrar->getIcon()??jvbDefaultIcon();
+		}
 
 		$containerId = sprintf('%s-%s-selector', $name, $config['subtype']);
 
 		$input = sprintf(
-			'<div class="row btw">
-			<label for="%s-autocomplete">%s<span>%s</span></label>',
+			'<div class="row x-btw">
+    <input type="hidden" name="%s" value="%s">
+    <label for="%s-autocomplete">%s<span>%s</span></label>',
+			esc_attr($name),
+			esc_attr(!empty($ids) ? implode(',', $ids) : ''),
 			esc_attr($name),
 			jvbIcon($icon),
 			esc_html($config['label']),
@@ -1183,58 +1254,64 @@
 		}
 		$plural = static::getPlural($config);
 		$input .= sprintf(
-			'<div class="selected-item row" role="region" aria-label="Selected %s"></div>',
+			'<div class="selected-items row left" role="region" aria-label="Selected %s"></div>',
 			$plural[1]??''
 		);
 
+		$input .= '</div>'; //Close the first div.row.btw
+
+		$config['type'] = 'selector';
 		unset($config['label']);
 		unset($config['description']);
 		unset($config['hint']);
 		$config['skipInput'] = true;
-		return static::fieldWrap($containerId, $input, $config);
+		return static::fieldWrap($name, $input, $config);
 	}
 
 		protected static function getPlural(array $config):array
 		{
+			$single = $plural = '';
 			switch ($config['subtype']) {
 				case 'taxonomy':
-					if (array_key_exists($config['taxonomy'], JVB_TAXONOMY)) {
-						$single = JVB_TAXONOMY[$config['taxonomy']]['singular'];
-						$plural = JVB_TAXONOMY[$config['taxonomy']]['plural'];
+					$registrar = Registrar::getInstance($config['taxonomy']);
+					if ($registrar) {
+						$single = $registrar->getSingular();
+						$plural = $registrar->getPlural();
 					} else {
 						$taxonomy = get_taxonomy($config['taxonomy']);
-						if (!$taxonomy) {
-							return [];
+						if ($taxonomy) {
+							$single = $taxonomy->labels->singular_name;
+							$plural = $taxonomy->labels->name;
 						}
-						$single = $taxonomy->labels->singular_name;
-						$plural = $taxonomy->labels->name;
 					}
 					break;
 				case 'content':
-					if (array_key_exists($config['content'], JVB_CONTENT)) {
-						$single = JVB_CONTENT[$config['content']]['singular'];
-						$plural = JVB_CONTENT[$config['content']]['plural'];
+					$registrar = Registrar::getInstance($config['content']);
+					if ($registrar) {
+						$single = $registrar->getSingular();
+						$plural = $registrar->getPlural();
 					} else {
 						$postType = get_post_type_object($config['content']);
-						if (!$postType) {
-							return '';
+						if ($postType) {
+							$single = $postType->labels->singular_name;
+							$plural = $postType->labels->name;
 						}
-						$single = $postType->labels->singular_name;
-						$plural = $postType->labels->name;
+
 					}
 					break;
 
 				case 'user':
-					if (array_key_exists($config['user'], JVB_USER)) {
-						$single = JVB_USER[$config['user']]['singular'];
-						$plural = JVB_USER[$config['user']]['plural'];
+					$registrar = Registrar::getInstance($config['user']);
+
+					if ($registrar) {
+						$single = $registrar->getSingular();
+						$plural = $registrar->getPlural();
 					} else {
 						$user = get_role($config['user']);
-						if (!$user) {
-							return '';
+						if ($user) {
+							$single = 'User';
+							$plural = 'Users';
 						}
-						$single = 'User';
-						$plural = 'Users';
 					}
 					break;
 			}
@@ -1245,9 +1322,10 @@
 		{
 			switch ($config['subtype']) {
 				case 'taxonomy':
-					if (array_key_exists($config['taxonomy'], JVB_TAXONOMY)) {
-						$single = JVB_TAXONOMY[$config['taxonomy']]['singular'];
-						$plural = JVB_TAXONOMY[$config['taxonomy']]['plural'];
+					$registrar = Registrar::getInstance($config['taxonomy']);
+					if ($registrar) {
+						$single = $registrar->getSingular();
+						$plural = $registrar->getPlural();
 					} else {
 						$taxonomy = get_taxonomy($config['taxonomy']);
 						if (!$taxonomy) {
@@ -1257,16 +1335,17 @@
 						$plural = $taxonomy->labels->name;
 					}
 					$attr = sprintf(
-						' data-taxonomy="%s" data-single="%s" data-plural="%s',
+						' data-taxonomy="%s" data-single="%s" data-plural="%s"',
 						$config['taxonomy'],
 						$single,
 						$plural
 					);
 					break;
 				case 'content':
-					if (array_key_exists($config['content'], JVB_CONTENT)) {
-						$single = JVB_CONTENT[$config['content']]['singular'];
-						$plural = JVB_CONTENT[$config['content']]['plural'];
+					$registrar = Registrar::getInstance($config['content']);
+					if ($registrar) {
+						$single = $registrar->getSingular();
+						$plural = $registrar->getPlural();
 					} else {
 						$postType = get_post_type_object($config['content']);
 						if (!$postType) {
@@ -1276,7 +1355,7 @@
 						$plural = $postType->labels->name;
 					}
 					$attr = sprintf(
-						' data-content="%s" data-single="%s" data-plural="%s',
+						' data-content="%s" data-single="%s" data-plural="%s"',
 						$config['content'],
 						$single,
 						$plural
@@ -1284,9 +1363,10 @@
 					break;
 
 				case 'user':
-					if (array_key_exists($config['user'], JVB_USER)) {
-						$single = JVB_USER[$config['user']]['singular'];
-						$plural = JVB_USER[$config['user']]['plural'];
+					$registrar = Registrar::getInstance($config['user']);
+					if ($registrar){
+						$single = $registrar->getSingular();
+						$plural = $registrar->getPlural();
 					} else {
 						$user = get_role($config['user']);
 						if (!$user) {
@@ -1296,7 +1376,7 @@
 						$plural = 'Users';
 					}
 					$attr = sprintf(
-						' data-user="%s" data-single="%s" data-plural="%s',
+						' data-user="%s" data-single="%s" data-plural="%s"',
 						$config['user'],
 						$single,
 						$plural
@@ -1324,7 +1404,7 @@
 				$dataAttrs[] = 'data-selected="'.esc_attr(implode(',',$selected)).'"';
 			}
 			if ($config['autocomplete']) {
-				$dataAttrs[] = 'autocomplete';
+				$dataAttrs[] = 'data-autocomplete';
 			}
 			if (array_key_exists('hidden', $config) && $config['hidden']) {
 				$dataAttrs[] = 'hidden';
@@ -1341,15 +1421,15 @@
 				jvbIcon('plus-square')
 			);
 		}
-		protected static function buildSelectorAutocomplete(string $name, array $config):string
-		{
-			return sprintf(
-			'<input type="hidden" id="%s-autocomplete" autocomplete="off" data-ignore data-autocomplete>
-				<p class="message" hidden aria-live="polite">{ <span>Loading items</span> }</p>
-				<div class="auto-wrapper" hidden><ul class="search-results"></ul><button class="submit-term" hidden data-ignore><strong>Create: </strong> "<span></span>"</button></div>',
-				$name
-			);
-		}
+	protected static function buildSelectorAutocomplete(string $name, array $config): string
+	{
+		return sprintf(
+			'<input type="search" id="%s-autocomplete" autocomplete="off" data-ignore data-autocomplete>
+        <p class="message" hidden aria-live="polite">{ <span>Loading items</span> }</p>
+        <div class="auto-wrapper" hidden><ul class="search-results"></ul><button class="submit-term" hidden data-ignore><strong>Create: </strong> "<span></span>"</button></div>',
+			esc_attr($name)
+		);
+	}
 
 	protected static function renderTaxonomy(string $name, mixed $value, array $config): string
 	{
@@ -1370,7 +1450,10 @@
 
 	protected static function renderLocation(string $name, mixed $value, array $config): string
 	{
-		$googleMaps = JVB()->connect('maps');
+		if (!Site::hasIntegration('maps')) {
+			return '';
+		}
+		$googleMaps = GoogleMaps::getInstance();
 		if (!$googleMaps->isSetUp()) {
 			return '<div class="notice notice-warning"><p>Google Maps not configured. Please configure in Integrations settings.</p></div>';
 		}
@@ -1448,7 +1531,7 @@
 		$config['data']['tag-format'] = esc_attr($tagFormat);
 
 		$input = sprintf(
-			'<h3>%s</h3><div class="row start wrap">',
+			'<h3>%s</h3><div class="row left wrap">',
 			esc_html($config['label']??'')
 		);
 
@@ -1463,7 +1546,7 @@
 			$input .= static::render($newName, '', $fieldConfig);
 		}
 		$input .= sprintf(
-			'<button type="button" class="button add-tag">%s<span>%s</span></button></div>',
+			'<button type="button" class="button add-tag">%s<span>%s</span></button>',
 			jvbIcon('plus'),
 			$config['add_label']??'Add'
 		);
@@ -1481,7 +1564,7 @@
 
 		unset($config['label']);
 
-		return static::fieldWrap($name, $input, $config);
+		return static::fieldWrap($name, $input, $config, true);
 	}
 		protected static function renderTagItems(array $fields, mixed $value, string $name, string $tagFormat):string
 		{
@@ -1566,8 +1649,8 @@
 	{
 		$fields = $config['fields'] ?? [];
 		$rows = is_array($value) ? $value : [];
-		if(array_key_exists('row_label', $config)) {
-			$config['data']['label'] = esc_attr($config['row_label']);
+		if(array_key_exists('add_label', $config)) {
+			$config['data']['label'] = esc_attr($config['add_label']);
 		}
 
 		$input = sprintf(
@@ -1576,16 +1659,21 @@
 		);
 
 		$input .= '<div class="repeater-items">';
-		$rowTitle = array_key_exists('new_row', $config) ? $config['new_row'] : 'New Item';
+
+        $hasTitle = array_key_exists('row_label', $config);
 		if(!empty($rows)) {
 			foreach ($rows as $index=>$row) {
-				$input .= static::renderRepeaterRow($config['fields'], $row, $index, $name, $rowTitle);
+                $titleReference = $hasTitle ? $config['row_label'] : null;
+                $rowTitle = !is_null($titleReference) ? $row[$titleReference] : 'New Item';
+
+				$input .= static::renderRepeaterRow($config['fields'], $row, $index, $name, $rowTitle, $titleReference);
 			}
 		}
 		$input .= '</div>';
 
+        $titleReference = $hasTitle ? $config['row_label'] : null;
 		$input .= '<template class="'.uniqid('repeaterRow').'">';
-			$input .= static::renderRepeaterRow($config['fields'], [], '','',$rowTitle);
+			$input .= static::renderRepeaterRow($config['fields'], [], '','','New Item', $titleReference);
 		$input .= '</template>';
 
 		$input .= sprintf(
@@ -1594,29 +1682,28 @@
 		array_key_exists('add_label', $config) ? $config['add_label'] : 'Add Item'
 		);
 
+		unset($config['label']);
 		return static::fieldWrap($name, $input, $config);
 	}
-		protected static function renderRepeaterRow(array $fields, array $values, int|string $index, string $name, string $rowTitle='New Item'):string
+		protected static function renderRepeaterRow(array $fields, array $values, int|string $index, string $name, string $rowTitle='New Item', ?string $rowTitleField = null):string
 		{
 			$displayNumber = (is_string($index)) ? $index : ($index +1);
 
+
 			$output = sprintf(
-				'<div class="repeater-row" data-index="%s">
-						<button type="button" class="remove-row" title="Remove">
-							%s
-						</button>
+				'<div class="repeater-row row nowrap" data-index="%s">
+                        <span class="drag-handle row">%s</span>
 						<details%s>
-							<summary class="row btw repeater-row-header">
-								<span class="drag-handle">%s</span>
+							<summary class="row x-btw repeater-row-header">
 								<span class="row-number">#%s</span>
-								<span class="row-title">%s</span>
+								<span class="row-title"%s>%s</span>
 							</summary>
 							<div class="repeater-row-content">',
 				esc_attr($index),
-				jvbIcon('trash'),
+                jvbIcon('dots-six-vertical'),
 				is_string($index) ? ' open' : '',
-				jvbIcon('dots-six-vertical'),
 				$displayNumber,
+                is_null($rowTitleField) ? '' : 'data-label="'.$rowTitleField.'"',
 				$rowTitle
 			);
 			foreach ($fields as $fieldName => $fieldConfig) {
@@ -1625,7 +1712,11 @@
 				$output .= static::render($fullName, $fieldValue, $fieldConfig);
 			}
 
-			return $output.'</div></details></div>';
+			return $output.sprintf('</div></details><button type="button" class="remove-row" title="Remove">
+							%s
+						</button></div>',
+                    jvbIcon('trash'),
+                );
 		}
 
 	/**
@@ -1640,8 +1731,8 @@
 		$fields = $config['fields'] ?? [];
 		$values = is_array($value) ? $value : [];
 
-		$wrapper = (array_key_exists('wrap', $config)) ? 'details' : 'fieldset';
-		$legend = (array_key_exists('wrap', $config)) ? 'summary' : 'legend';
+		$wrapper = (array_key_exists('wrap', $config) && $config['wrap'] === 'details') ? 'details' : 'fieldset';
+		$legend = (array_key_exists('wrap', $config) && $config['wrap'] === 'details') ? 'summary' : 'legend';
 
 		$output = sprintf(
 			'<%s><%s>%s</%s>'
@@ -1654,7 +1745,7 @@
 
 		foreach ($fields as $fieldName => $fieldConfig) {
 			$fieldValue = $values[$fieldName] ?? '';
-			$fullName = array_key_exists('wrap', $config) ? $fieldName : "{$name}:{$fieldName}";
+			$fullName = "{$name}|{$fieldName}";
 			$output .= static::render($fullName, $fieldValue, $fieldConfig);
 		}
 
@@ -1668,7 +1759,7 @@
 	{
 		return sprintf('<dialog id="jvb-selector" aria-labelledby="modal-title" aria-modal="true">
 				<div class="wrap col">
-					<header class="modal-header">
+					<header class="row">
 						<h3 id="modal-title">Select Taxonomy</h3>
 					</header>
 
@@ -1678,8 +1769,8 @@
 					<div class="items-wrap">
 						<!-- Common/Favorite terms section -->
 						<details class="favourite-terms" hidden>
-							<summary class="title row btw">Your Go Tos:</summary>
-							<ul class="favourite-list row btw"></ul>
+							<summary class="title row x-btw">Your Go Tos:</summary>
+							<ul class="favourite-list row x-btw"></ul>
 						</details>
 
 						<!-- Pagination info -->
@@ -1697,7 +1788,7 @@
 							{ <span>loading items</span> }
 						</p>
 						<!-- Terms list -->
-						<ul class="items-container col start" role="listbox" aria-label="Available terms">
+						<ul class="items-container col top" role="listbox" aria-label="Available terms">
 							<!-- Terms will be populated here -->
 						</ul>
 
@@ -1716,7 +1807,7 @@
 
 					<!-- Create new term section -->
 					<details class="create-term" hidden>
-						<summary class="row btw">Add New Term</summary>
+						<summary class="row x-btw">Add New Term</summary>
 						<div class="create-new-term-section">
 							<form class="create-term" data-nocache data-form-id="create-term" data-save="terms">
 								<div class="form-group">
@@ -1762,33 +1853,46 @@
 			<template class="selectedTerm">
 				<div class="selected-item row">
 					<span class="item-name"></span>
-					<button type="button" class="remove-term row">%s</button>
+					<button type="button" class="remove-term">%s</button>
 				</div>
 			</template>
 			<template class="termBreadcrumb">
 				<button type="button" class="path-level"></button>
 			</template>',
-			static::search('Search terms', 'search-terms'),
+			str_replace('class="search-container', 'class="open search-container', static::search('Search terms', 'search-terms')),
 			 jvbModalActions(),
 			jvbIcon('plus-square'),
 			jvbIcon('x')
 		);
 	}
 
-	public static function search(string $placeholder = 'Search...', string $id = 'search'):string
+	public static function search(string $placeholder = 'Search...', string $id = 'search', string $label = '', string $buttonText = '',bool $buttonInside = false,  bool $hideSearch = false):string
 	{
 		$id = sanitize_title($id);
+		$label = empty($label) ? '' : sprintf(
+			'<h3>%s</h3>',
+			$label
+		);
+		$buttonText = empty($buttonText) ? '' : sprintf(
+			'<span>%s</span>',
+			$buttonText
+		);
+		$hideSearch = $hideSearch ? ' hidden' : '';
 		return sprintf(
-			'<div class="search-container row start nowrap">
-				<input type="search" id="%s" placeholder="%s">
+			'%s<div class="search-container row left nowrap%s">
+				<input type="search" id="%s" placeholder="%s"%s>
 				<button title="Clear Search" type="button" class="clear-search" aria-label="Clear search"
 					onclick="this.previousElementSibling.value = \'\'; this.previousElementSibling.focus();">%s</button>
-				<button type="button" title="Search" class="toggle search" aria-label="Toggles search input visually" onclick="this.parentNode.classList.toggle(\'open\');this.previousElementSibling.previousElementSibling.focus();">%s</button>
+				<button type="button" title="Search" class="toggle search" aria-label="Toggles search input visually" onclick="this.parentNode.classList.toggle(\'open\');this.previousElementSibling.previousElementSibling.focus();">%s%s</button>
 				</div>',
+			$label,
+			$buttonInside ? ' insideButton' : '',
 			$id,
 			$placeholder,
+			$hideSearch,
 			jvbIcon('x', ['title' => 'Clear Search']),
-			jvbIcon('magnifying-glass')
+			jvbIcon('magnifying-glass'),
+			$buttonText
 		);
 	}
 }

--
Gitblit v1.10.0