From 7935d26cd16a4f8f69a59a44e27a7263b60e54bf Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Mon, 14 Sep 2026 19:05:30 +0000
Subject: [PATCH] =Simple Calendar block up and running

---
 inc/blocks/EventBlock.php                 |  147 +--------------
 src/event/style.scss                      |    5 
 src/simple-calendar/style.scss            |   93 ++++++++++
 build/event/style-index-rtl.css           |    2 
 inc/helpers/Events.php                    |  183 ++++++++++++++++++++
 inc/integrations/SyncToTerm.php           |    6 
 build/simple-calendar/style-index.css     |    2 
 inc/integrations/SyncToPost.php           |    6 
 build/event/index.asset.php               |    2 
 inc/blocks/SimpleCalendarBlock.php        |   70 ++++---
 build/event/style-index.css               |    2 
 inc/helpers/all.php                       |    1 
 inc/integrations/SyncToUser.php           |    6 
 build/simple-calendar/style-index-rtl.css |    2 
 build/simple-calendar/index.asset.php     |    2 
 inc/helpers/terms.php                     |    9 
 16 files changed, 367 insertions(+), 171 deletions(-)

diff --git a/build/event/index.asset.php b/build/event/index.asset.php
index 992cc06..7c3f012 100644
--- a/build/event/index.asset.php
+++ b/build/event/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n'), 'version' => 'cb644be845ba8e59afd4');
+<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n'), 'version' => 'e8a24b15f984ecd60ea6');
diff --git a/build/event/style-index-rtl.css b/build/event/style-index-rtl.css
index a9078f0..d619b4f 100644
--- a/build/event/style-index-rtl.css
+++ b/build/event/style-index-rtl.css
@@ -1 +1 @@
-.event-block .tags{--gap:1rem}.event-block .tags .tag{background-color:rgb(var(--action-0));border-radius:4px;color:rgb(var(--action-contrast));display:flex;font-size:var(--txt-x-small);gap:.5rem;padding:.25rem .5rem 0;text-transform:uppercase}.event-block header{--wrap:nowrap!important;gap:1rem}.event-block header h1{margin:0}.event-block .calendar.col{border:2px solid rgb(var(--action-0));border-radius:.5rem;width:var(--btn_);--align:stretch;--gap:0}.event-block .calendar.col span{line-height:.8;text-align:center;text-transform:uppercase}.event-block .calendar.col .weekday{background-color:rgb(var(--action-0));color:rgb(var(--action-contrast));font-family:var(--heading);font-weight:var(--fw-h-bold);line-height:1.4;margin-bottom:.5rem}.event-block .calendar.col .day{font-size:var(--txt-xx-large)}.event-block .gallery figure{aspect-ratio:1;max-width:min(15vw,8rem)!important;object-fit:cover}.event-block figcaption{display:none}
+.event-block .tags{--gap:1rem}.event-block .tags .tag{background-color:rgb(var(--action-0));border-radius:4px;color:rgb(var(--action-contrast));display:flex;font-size:var(--txt-x-small);gap:.5rem;padding:.25rem .5rem 0;text-transform:uppercase}.event-block>img{margin:0 auto;max-width:min(250px,80vw)}.event-block header{--wrap:nowrap!important;gap:1rem}.event-block header h1{margin:0}.event-block .calendar.col{border:2px solid rgb(var(--action-0));border-radius:.5rem;width:var(--btn_);--align:stretch;--gap:0}.event-block .calendar.col span{line-height:.8;text-align:center;text-transform:uppercase}.event-block .calendar.col .weekday{background-color:rgb(var(--action-0));color:rgb(var(--action-contrast));font-family:var(--heading);font-weight:var(--fw-h-bold);line-height:1.4;margin-bottom:.5rem}.event-block .calendar.col .day{font-size:var(--txt-xx-large)}.event-block .gallery figure{aspect-ratio:1;max-width:min(15vw,8rem)!important;object-fit:cover}.event-block figcaption{display:none}
diff --git a/build/event/style-index.css b/build/event/style-index.css
index a9078f0..d619b4f 100644
--- a/build/event/style-index.css
+++ b/build/event/style-index.css
@@ -1 +1 @@
-.event-block .tags{--gap:1rem}.event-block .tags .tag{background-color:rgb(var(--action-0));border-radius:4px;color:rgb(var(--action-contrast));display:flex;font-size:var(--txt-x-small);gap:.5rem;padding:.25rem .5rem 0;text-transform:uppercase}.event-block header{--wrap:nowrap!important;gap:1rem}.event-block header h1{margin:0}.event-block .calendar.col{border:2px solid rgb(var(--action-0));border-radius:.5rem;width:var(--btn_);--align:stretch;--gap:0}.event-block .calendar.col span{line-height:.8;text-align:center;text-transform:uppercase}.event-block .calendar.col .weekday{background-color:rgb(var(--action-0));color:rgb(var(--action-contrast));font-family:var(--heading);font-weight:var(--fw-h-bold);line-height:1.4;margin-bottom:.5rem}.event-block .calendar.col .day{font-size:var(--txt-xx-large)}.event-block .gallery figure{aspect-ratio:1;max-width:min(15vw,8rem)!important;object-fit:cover}.event-block figcaption{display:none}
+.event-block .tags{--gap:1rem}.event-block .tags .tag{background-color:rgb(var(--action-0));border-radius:4px;color:rgb(var(--action-contrast));display:flex;font-size:var(--txt-x-small);gap:.5rem;padding:.25rem .5rem 0;text-transform:uppercase}.event-block>img{margin:0 auto;max-width:min(250px,80vw)}.event-block header{--wrap:nowrap!important;gap:1rem}.event-block header h1{margin:0}.event-block .calendar.col{border:2px solid rgb(var(--action-0));border-radius:.5rem;width:var(--btn_);--align:stretch;--gap:0}.event-block .calendar.col span{line-height:.8;text-align:center;text-transform:uppercase}.event-block .calendar.col .weekday{background-color:rgb(var(--action-0));color:rgb(var(--action-contrast));font-family:var(--heading);font-weight:var(--fw-h-bold);line-height:1.4;margin-bottom:.5rem}.event-block .calendar.col .day{font-size:var(--txt-xx-large)}.event-block .gallery figure{aspect-ratio:1;max-width:min(15vw,8rem)!important;object-fit:cover}.event-block figcaption{display:none}
diff --git a/build/simple-calendar/index.asset.php b/build/simple-calendar/index.asset.php
index b0acfbb..d5ed7ba 100644
--- a/build/simple-calendar/index.asset.php
+++ b/build/simple-calendar/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-i18n'), 'version' => 'c9d53040b1ae8b423795');
+<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-i18n'), 'version' => '25242b79f9cae31bcb49');
diff --git a/build/simple-calendar/style-index-rtl.css b/build/simple-calendar/style-index-rtl.css
index 6b1fe8f..aaa398d 100644
--- a/build/simple-calendar/style-index-rtl.css
+++ b/build/simple-calendar/style-index-rtl.css
@@ -1 +1 @@
-p.empty{background-color:rgb(var(--base));border:2px dashed rgba(var(--base-200));border-radius:var(--radius);font-style:italic;text-align:center}details{margin:2rem 0}details h2{margin:0}nav.calendar.types.types{height:max-content}
+p.empty{background-color:rgb(var(--base));border:2px dashed rgba(var(--base-200));border-radius:var(--radius);font-style:italic;text-align:center}details{margin:2rem 0}details h2{margin:0}.simple-calendar nav.calendar.types{height:max-content}.simple-calendar nav.calendar.types a,.simple-calendar nav.calendar.types li,.simple-calendar nav.calendar.types ul{height:var(--chipchip)}.simple-calendar nav.calendar.types ul{--justify:flex-start}.simple-calendar nav.calendar.types details{display:block;margin:0}.simple-calendar nav.calendar.types details summary{display:flex;width:100%}.simple-calendar .calendar.col{border:2px solid rgb(var(--action-0));border-radius:.5rem;width:var(--btn_);--align:stretch;--gap:0}.simple-calendar .calendar.col span{line-height:.8;text-align:center;text-transform:uppercase}.simple-calendar .calendar.col .weekday{background-color:rgb(var(--action-0));color:rgb(var(--action-contrast));font-family:var(--heading);font-weight:var(--fw-h-bold);line-height:1.4;margin-bottom:.5rem}.simple-calendar .calendar.col .day{font-size:var(--txt-xx-large)}.simple-calendar details#calendar,.simple-calendar details#past{display:block}.simple-calendar .item-list{list-style:none;margin:0;min-width:100%}.simple-calendar .item-list>li{padding:1rem .25rem;width:100%}.simple-calendar .item-list>li+li{border-top:1px solid rgb(var(--base-200));margin-top:1rem}.simple-calendar .item-list>li>img{margin:0 auto;max-width:250px}.simple-calendar .item-list>li .header{--gap:1rem;--wrap:nowrap}.simple-calendar .item-list>li h3{margin:0}.simple-calendar .item-list>li .meta{display:flex;gap:1rem}.simple-calendar .tags{--gap:1rem}.simple-calendar .tags .tag{background-color:rgb(var(--action-0));border-radius:4px;color:rgb(var(--action-contrast));display:flex;font-size:var(--txt-x-small);gap:.5rem;padding:.25rem .5rem 0;text-transform:uppercase}
diff --git a/build/simple-calendar/style-index.css b/build/simple-calendar/style-index.css
index 6b1fe8f..aaa398d 100644
--- a/build/simple-calendar/style-index.css
+++ b/build/simple-calendar/style-index.css
@@ -1 +1 @@
-p.empty{background-color:rgb(var(--base));border:2px dashed rgba(var(--base-200));border-radius:var(--radius);font-style:italic;text-align:center}details{margin:2rem 0}details h2{margin:0}nav.calendar.types.types{height:max-content}
+p.empty{background-color:rgb(var(--base));border:2px dashed rgba(var(--base-200));border-radius:var(--radius);font-style:italic;text-align:center}details{margin:2rem 0}details h2{margin:0}.simple-calendar nav.calendar.types{height:max-content}.simple-calendar nav.calendar.types a,.simple-calendar nav.calendar.types li,.simple-calendar nav.calendar.types ul{height:var(--chipchip)}.simple-calendar nav.calendar.types ul{--justify:flex-start}.simple-calendar nav.calendar.types details{display:block;margin:0}.simple-calendar nav.calendar.types details summary{display:flex;width:100%}.simple-calendar .calendar.col{border:2px solid rgb(var(--action-0));border-radius:.5rem;width:var(--btn_);--align:stretch;--gap:0}.simple-calendar .calendar.col span{line-height:.8;text-align:center;text-transform:uppercase}.simple-calendar .calendar.col .weekday{background-color:rgb(var(--action-0));color:rgb(var(--action-contrast));font-family:var(--heading);font-weight:var(--fw-h-bold);line-height:1.4;margin-bottom:.5rem}.simple-calendar .calendar.col .day{font-size:var(--txt-xx-large)}.simple-calendar details#calendar,.simple-calendar details#past{display:block}.simple-calendar .item-list{list-style:none;margin:0;min-width:100%}.simple-calendar .item-list>li{padding:1rem .25rem;width:100%}.simple-calendar .item-list>li+li{border-top:1px solid rgb(var(--base-200));margin-top:1rem}.simple-calendar .item-list>li>img{margin:0 auto;max-width:250px}.simple-calendar .item-list>li .header{--gap:1rem;--wrap:nowrap}.simple-calendar .item-list>li h3{margin:0}.simple-calendar .item-list>li .meta{display:flex;gap:1rem}.simple-calendar .tags{--gap:1rem}.simple-calendar .tags .tag{background-color:rgb(var(--action-0));border-radius:4px;color:rgb(var(--action-contrast));display:flex;font-size:var(--txt-x-small);gap:.5rem;padding:.25rem .5rem 0;text-transform:uppercase}
diff --git a/inc/blocks/EventBlock.php b/inc/blocks/EventBlock.php
index acfd31e..9b531ba 100644
--- a/inc/blocks/EventBlock.php
+++ b/inc/blocks/EventBlock.php
@@ -3,6 +3,7 @@
 
 
 use DateTime;
+use JVBase\helpers\Events;
 use JVBase\meta\Meta;
 use JVBase\utility\Image;
 use WP_Block;
@@ -38,27 +39,8 @@
 		$values = $meta->getAll();
 
 		$out = '<section class="event-block">';
-		$out .= '<div class="event tags row right">';
-			$get = ['is_free' => 'Free', 'rsvp_required' => 'Must RSVP', 'public' => 'Private Event'];
-			foreach ($get as $k => $g) {
-				$check = !empty($values[$k]) && $values[$k] === '1';
-				if ($k === 'public') {
-					$check = !$check;
-				}
-				$icon = match ($k) {
-					'is_free'   => jvbIcon('check-circle'),
-					'rsvp_required'   => jvbIcon('envelope'),
-					'public'   => jvbIcon('lock-key'),
-				};
-				if ($check) {
-					$out .= sprintf(
-						'<div class="tag">%s%s</div>',
-						$icon,
-						$g
-					);
-				}
-			}
-		$out .= '</div>';
+		$out .= Events::tags($values);
+
 		if (!empty($values['post_thumbnail'])) {
 			$out .= jvbFormatImage($values['post_thumbnail']);
 		}
@@ -70,7 +52,7 @@
 					$values['post_title']
 				);
 			}
-			$out .= $this->calendarDay($values['date_start']??'');
+			$out .= Events::calendarDay($values['date_start']??'');
 
 		$out .= '</header>';
 
@@ -79,23 +61,24 @@
 				'<ul class="time term-list row left"><li class="title">%s</li>',
 				jvbIcon('clock')
 			);
-				$out .= $this->formatDay($values['date_start']??'', $values['time_start']??'', $values['time_end']??'');
+				$out .= sprintf(
+					'<li>%s</li>',
+					Events::formatDay($values['date_start']??'', $values['time_start']??'', $values['time_end']??'')
+				);
 				foreach ($values['schedule']??[] as $date) {
-					$out .= $this->formatDay($date['date'], $date['time_start'], $date['time_end'], $date['notes']);
+					$out .= sprintf(
+						'<li>%s</li>',
+						Events::formatDay($date['date'], $date['time_start'], $date['time_end'], $date['notes'])
+					);
 				}
 			$out .= '</ul>';
 
-				$out .= $this->location($values['location']??[], $values['location_notes']??'');
+				$out .= Events::location($values);
 
 			$out .= $this->price($values['cost']??'', $values['ticket_url']??'');
 			$out .= $this->participants($values['max_participants']??'');
 
-			$get = ['city', 'event_category'];
-			foreach ($get as $g) {
-				if (!empty($values[$g])) {
-					$out .= jvbMetaTermList($values[$g], $g);
-				}
-			}
+			$out .= Events::terms($values);
 
 			$out .= $this->rsvp($values['rsvp_required']??'', $values['rsvp_limit']??'', $values['rsvp_deadline']);
 
@@ -111,108 +94,6 @@
 		jvbRenderGallery();
 	}
 
-	protected function calendarDay(string $day):string
-	{
-		$out = '';
-		if (!empty($day)) {
-			$date = new DateTime($day, wp_timezone());
-			$weekday = $date->format('D');
-			$num = $date->format('d');
-			$month = $date->format('M');
-
-			$out .= sprintf(
-				'<div class="col calendar">
-						<span class="weekday">%s</span>
-						<span class="month">%s</span>
-						<span class="day">%d</span>
-					</div>',
-				$weekday,
-				$month,
-				$num
-			);
-		}
-		return $out;
-	}
-	protected function renderLocationString(array $location):string
-	{
-		if (!array_key_exists('address', $location) ||
-			!array_key_exists('street', $location) ||
-			!array_key_exists('city', $location) ||
-			!array_key_exists('province', $location) ||
-			!array_key_exists('country', $location)) {
-			return '';
-		}
-
-		return sprintf(
-			'<p class="location">%s%s<br>%s, %s %s</p>',
-			$location['address'],
-			$location['street'],
-			$location['city'],
-			$location['province'],
-			$location['country'] === 'CA' ? '' : $location['country']
-		);
-	}
-
-	protected function formatDay(string $date, string $start, string $end, string $notes = ''):string
-	{
-		$out = '<li>';
-		if (!empty($date)) {
-			$out .= sprintf(
-				'<time datetime="%s">%s</time><br>',
-				date('c', strtotime($date)),
-				date('F j, Y', strtotime($date))
-			);
-		}
-		$doit = false;
-
-		if (!empty($start)) {
-			$doit = true;
-			$d = strtotime($date.' '.$start);
-			$out .= sprintf(
-				'<time datetime="%s">%s</time>',
-				date('c', $d),
-				date('g:ia', $d)
-			);
-		}
-		if (!empty($end)) {
-			if ($doit) {
-				$out .= ' - ';
-			}
-			$d = strtotime($date.' '.$end);
-			$out .= sprintf(
-				'<time datetime="%s">%s</time>',
-				date('c', $d),
-				date('g:ia', $d)
-			);
-
-		}
-		if (!empty($notes)) {
-			$out .= wpautop($notes);
-		}
-
-		$out .= '</li>';
-		return $out;
-	}
-
-	protected function location(array $location, string $notes = ''):string
-	{
-		$out = '';
-		if (!empty($location['address']??'')) {
-			$out .= sprintf(
-				'<ul class="location term-list row left">
-					<li class="title">%sLocation</li>
-					<li>%s</li>
-					<li>%s</li>
-					%s
-					</ul>',
-				jvbIcon('map-pin'),
-				$this->renderLocationString($location),
-				jvbLocationLinks($location),
-				empty($notes) ? '' : '<li>'.$notes.'</li>',
-			);
-		}
-		return $out;
-	}
 
 	protected function price(string $price, string $url):string
 	{
diff --git a/inc/blocks/SimpleCalendarBlock.php b/inc/blocks/SimpleCalendarBlock.php
index c83d0a3..41eaa2b 100644
--- a/inc/blocks/SimpleCalendarBlock.php
+++ b/inc/blocks/SimpleCalendarBlock.php
@@ -2,6 +2,7 @@
 namespace JVBase\blocks;
 
 use DateTime;
+use JVBase\helpers\Events;
 use JVBase\managers\Cache;
 use JVBase\meta\Meta;
 use JVBase\registrar\Registrar;
@@ -154,7 +155,7 @@
 				$title .= sprintf(
 					' %s %s',
 					is_tax() ? 'happening on' : 'in',
-					$this->getMonthName((int)$this->has('emonth')),
+					Events::getMonthName((int)$this->has('emonth')),
 				);
 			}
 			if ($this->has('eday')) {
@@ -188,7 +189,8 @@
 				}
 				if (!empty($out)) {
 					$content = sprintf(
-				'<ul class="term-list content"><li class="label">Content:</li>%s</ul>',
+				'<details class="content row start"><summary>%sBy Content</summary><ul class="term-list content">%s</ul></details>',
+						jvbIcon('calendar-alt'),
 						implode('', $out)
 					);
 				}
@@ -213,10 +215,13 @@
 						}
 					}
 					if (!empty($out)) {
+						$inst = Registrar::getInstance($slug);
 						$taxonomies .= sprintf(
-							'<ul class="term-list row start %s"><li class="label">%s</li>%s</ul>',
+							'<details class="%s row start"><summary>%sBy %s</summary><ul class="term-list row start %s">%s</ul></details>',
+							$inst->getSlug(),
+							jvbIcon($inst->getIcon()??'folder'),
+							$inst->getSingular(),
 							$slug,
-							$title,
 							implode('', $out)
 						);
 					}
@@ -225,10 +230,10 @@
 
 			$dates = $this->getDateNavigation();
 
-			if (!is_post_type_archive($this->content[0]) || $this->isDatedArchive()) {
+			if (!is_post_type_archive($this->firstContent()) || $this->isDatedArchive()) {
 				echo sprintf(
 					'<a href="%s" class="btn chip">All Events</a>',
-					get_post_type_archive_link($this->content[0])
+					get_post_type_archive_link($this->firstContent())
 				);
 			}
 			if (!empty($content) || !empty($taxonomies) || !empty($dates)) {
@@ -306,7 +311,7 @@
 
 							foreach ($months as $month => $days) {
 								$m = intval($month);
-								$monthName = $this->getMonthName($m);
+								$monthName = Events::getMonthName($m);
 
 								$out .= sprintf(
 									'<li><a href="%s/%d/%s" title="View all posts in %s, %d">%s</a></li>',
@@ -368,7 +373,7 @@
 		$events = implode('', array_map([$this, 'formatItem'], $items->posts));
 
 		$events = empty($events) ? '<p class="empty">Nothing here yet</p>' : sprintf(
-			'<ul class="item-list">%s</ul>',
+			'<ul class="item-list col">%s</ul>',
 			$events
 		);
 		$total = $items->max_num_pages;
@@ -400,6 +405,7 @@
 			'post_status'	=> 'publish',
 			'orderby'		=> 'meta_value',
 			'meta_key'		=> BASE.'date_start',
+			'order'			=> 'ASC',
 			'meta_type'		=> 'DATETIME',
 			'posts_per_page'=> 30,
 			'fields'		=> 'ids',
@@ -449,22 +455,38 @@
 	{
 		$meta = Meta::forPost($ID);
 		$type = jvbNoBase(get_post_type($ID));
+		if (empty($meta->get('date_start'))) {
+			return '';
+		}
 		$date = strtotime($meta->get('date_start'));
+		$img = empty($meta->get('post_thumbnail')) ? '' : jvbFormatImage($meta->get('post_thumbnail'), 'tiny', 'medium');
+		$fields = $meta->getAll();
 		return sprintf(
 	'<li class="item %s">
 				%s
-				<h3>
-					<a href="%s" title="Learn More">%s</a>
-					<small><time datetime="%s">%s</time></small>
-				</h3>
+				%s
+				<div class="row start header">
+					%s
+					<h3>
+						<a href="%s" title="Learn More">%s</a>
+					</h3>
+				</div>
+				<div class="meta">
+					<p>%s</p>
+					%s
+					%s
+				</div>
 				%s
 			</li>',
 			$type,
-			empty($meta->get('post_thumbnail')) ? '' : jvbFormatImage($meta->get('post_thumbnail'), 'tiny', 'medium'),
+			Events::tags($fields),
+			$img,
+			Events::calendarDay($fields['date_start']),
 			get_the_permalink($ID),
 			$meta->get('post_title'),
-			date('c', $date),
-			date('F j, Y', $date),
+			Events::formatDay($meta->get('date_start'), $meta->get('time_start'), $meta->get('time_end')),
+			Events::location($fields),
+			Events::terms($fields, false),
 			empty($meta->get('post_excerpt')) ? '' : wpautop($meta->get('post_excerpt'))
 		);
 	}
@@ -490,21 +512,9 @@
 			false;
 	}
 
-	protected function getMonthName(int $num):string
+
+	protected function firstContent():string
 	{
-		return match($num) {
-			1 => 'January',
-			2 => 'February',
-			3 => 'March',
-			4 => 'April',
-			5 => 'May',
-			6 => 'June',
-			7 => 'July',
-			8 => 'August',
-			9 => 'September',
-			10 => 'October',
-			11 => 'November',
-			12 => 'December',
-		};
+		return array_keys($this->content)[0]??'';
 	}
 }
diff --git a/inc/helpers/Events.php b/inc/helpers/Events.php
new file mode 100644
index 0000000..2c467a4
--- /dev/null
+++ b/inc/helpers/Events.php
@@ -0,0 +1,183 @@
+<?php
+
+namespace JVBase\helpers;
+use DateTime;
+use Exception;
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+/**
+ * Helper class that renders fields based on the presets from MakeCalendarType.php
+ */
+class Events {
+	public static function tags(array $fields):string
+	{
+		$out = '<div class="event tags row right">';
+		$get = ['is_free' => 'Free', 'rsvp_required' => 'Must RSVP', 'public' => 'Private Event'];
+		foreach ($get as $k => $g) {
+			$check = !empty($fields[$k]) && $fields[$k] === '1';
+			if ($k === 'public') {
+				$check = !$check;
+			}
+			$icon = match ($k) {
+				'is_free'   => jvbIcon('check-circle'),
+				'rsvp_required'   => jvbIcon('envelope'),
+				'public'   => jvbIcon('lock-key'),
+			};
+			if ($check) {
+				$out .= sprintf(
+					'<div class="tag">%s%s</div>',
+					$icon,
+					$g
+				);
+			}
+		}
+		$out .= '</div>';
+		return $out;
+	}
+
+	/**
+	 * @param string $date
+	 *
+	 * @return string
+	 */
+	public static function calendarDay(string $date):string
+	{
+
+		if (empty($date)) {
+			return '';
+		}
+		try {
+			$date = new DateTime($date, wp_timezone());
+			$weekday = $date->format('D');
+			$num = $date->format('d');
+			$month = $date->format('M');
+
+			return sprintf(
+				'<div class="col calendar">
+						<span class="weekday">%s</span>
+						<span class="month">%s</span>
+						<span class="day">%d</span>
+					</div>',
+				$weekday,
+				$month,
+				$num
+			);
+		} catch (Exception $e){
+			return '';
+		}
+	}
+
+	public static function formatDay(string $date, string $start, string $end, string $notes = ''):string
+	{
+		$out = '';
+		if (!empty($date)) {
+			$out .= sprintf(
+				'<time datetime="%s">%s</time><br>',
+				date('c', strtotime($date)),
+				date('F j, Y', strtotime($date))
+			);
+		}
+		$doit = false;
+
+		if (!empty($start)) {
+			$doit = true;
+			$d = strtotime($date.' '.$start);
+			$out .= sprintf(
+				'<time datetime="%s">%s</time>',
+				date('c', $d),
+				date('g:ia', $d)
+			);
+		}
+		if (!empty($end)) {
+			if ($doit) {
+				$out .= ' - ';
+			}
+			$d = strtotime($date.' '.$end);
+			$out .= sprintf(
+				'<time datetime="%s">%s</time>',
+				date('c', $d),
+				date('g:ia', $d)
+			);
+
+		}
+		if (!empty($notes)) {
+			$out .= wpautop($notes);
+		}
+
+		return $out;
+	}
+
+	public static function getMonthName(int $num):string
+	{
+		return match($num) {
+			1 => 'January',
+			2 => 'February',
+			3 => 'March',
+			4 => 'April',
+			5 => 'May',
+			6 => 'June',
+			7 => 'July',
+			8 => 'August',
+			9 => 'September',
+			10 => 'October',
+			11 => 'November',
+			12 => 'December',
+		};
+	}
+
+	public static function location(array $fields):string
+	{
+		$out = '';
+		if (!array_key_exists('location', $fields)) {
+			return '';
+		}
+		if (!empty($fields['location']['address']??'')) {
+			$out .= sprintf(
+				'<ul class="location term-list row left">
+					<li class="title">%sLocation</li>
+					<li>%s</li>
+					<li>%s</li>
+					%s
+					</ul>',
+				jvbIcon('map-pin'),
+				self::renderLocationString($fields['location']),
+				jvbLocationLinks($fields['location']),
+				empty($location['location_notes']??'') ? '' : '<li>'.$fields['location_notes'].'</li>',
+			);
+		}
+		return $out;
+	}
+		public static function renderLocationString(array $location):string
+		{
+			if (!array_key_exists('address', $location) ||
+			    !array_key_exists('street', $location) ||
+			    !array_key_exists('city', $location) ||
+			    !array_key_exists('province', $location) ||
+			    !array_key_exists('country', $location)) {
+				return '';
+			}
+
+			return sprintf(
+				'<p class="location">%s%s<br>%s, %s %s</p>',
+				$location['address'],
+				$location['street'],
+				$location['city'],
+				$location['province'],
+				$location['country'] === 'CA' ? '' : $location['country']
+			);
+		}
+	public static function terms(array $fields, bool $showTaxonomy = true):string
+	{
+		$out = '';
+		$get = ['city', 'event_category'];
+		foreach ($get as $g) {
+			if (!empty($fields[$g])) {
+				$out .= jvbMetaTermList($fields[$g], $g, true, $showTaxonomy);
+			}
+		}
+		return $out;
+	}
+}
diff --git a/inc/helpers/all.php b/inc/helpers/all.php
index 38add59..cc68bac 100644
--- a/inc/helpers/all.php
+++ b/inc/helpers/all.php
@@ -5,6 +5,7 @@
 }
 
 require(JVB_DIR . '/inc/helpers/breadcrumbs.php');
+require(JVB_DIR . '/inc/helpers/Events.php');
 //require(JVB_DIR . '/inc/helpers/cache.php');
 require(JVB_DIR . '/inc/helpers/commonPages.php');
 require(JVB_DIR . '/inc/helpers/crud.php');
diff --git a/inc/helpers/terms.php b/inc/helpers/terms.php
index 6c0f7c0..e5878be 100644
--- a/inc/helpers/terms.php
+++ b/inc/helpers/terms.php
@@ -56,7 +56,7 @@
     return $out;
 }
 
-function jvbMetaTermList(string $value, string $tax, bool $icon = true):string
+function jvbMetaTermList(string $value, string $tax, bool $icon = true, bool $showTaxonomy = true):string
 {
 	if ($value === '') {
 		return '';
@@ -75,7 +75,12 @@
 	$registrar = Registrar::getInstance($tax);
 	$icon = ($icon && $registrar) ? $registrar->getIcon() : '';
 	$icon = ($icon === '') ? '' : jvbIcon($icon);
-	$title = $registrar ? '<li class="title">'.$icon.$registrar->getSingular().'</li>' : '';
+	$singular = '';
+	if ($registrar) {
+		$singular = $showTaxonomy ? $registrar->getSingular() : '<span class="screen-reader-text">'.$registrar->getSingular().'</span>';
+	}
+
+	$title = $registrar ? '<li class="title">'.$icon.$singular.'</li>' : '';
 	return (!empty($out)) ? '<ul class="term-list row left '.jvbNoBase($tax).'">'.$title.implode('',$out).'</ul>' : '';
 }
 
diff --git a/inc/integrations/SyncToPost.php b/inc/integrations/SyncToPost.php
index d30867d..ca233a1 100644
--- a/inc/integrations/SyncToPost.php
+++ b/inc/integrations/SyncToPost.php
@@ -87,6 +87,9 @@
 	 */
 	protected function handleTheSavePost(int $postID, WP_Post $post, bool $update, array $settings):void
 	{
+		if (!$this->isSetUp()) {
+			return;
+		}
 		error_log('==== ['.$this->title.']::handleTheSavePost ====');
 		$this->queueOperation(self::$syncTo, [
 			'posts'   => [$postID],
@@ -110,6 +113,9 @@
 	}
 	public function handleDeletePost(int $postID):void
 	{
+		if (!$this->isSetUp()) {
+			return;
+		}
 		if (!$this->canSync['delete']) {
 			return;
 		}
diff --git a/inc/integrations/SyncToTerm.php b/inc/integrations/SyncToTerm.php
index 2056579..02f7805 100644
--- a/inc/integrations/SyncToTerm.php
+++ b/inc/integrations/SyncToTerm.php
@@ -73,6 +73,9 @@
 	 */
 	protected function handleTheSaveTerm(int $termID, bool $update, string $taxonomy, array $settings):void
 	{
+		if (!$this->isSetUp()) {
+			return;
+		}
 		error_log('==== ['.$this->title.']::handleTheSaveTerm ====');
 		//TODO: Figure out some sort of permissions for if the user can share this term, particularly for content types
 		//TODO: If this is a content type, it likely has its own integration. This is an edmonton.ink problem, so I'm offloading it for now
@@ -98,6 +101,9 @@
 	}
 	public function handleDeleteTerm(int $termID, string $taxonomy):void
 	{
+		if (!$this->isSetUp()) {
+			return;
+		}
 		if (!$this->canSync['delete']) {
 			return;
 		}
diff --git a/inc/integrations/SyncToUser.php b/inc/integrations/SyncToUser.php
index ea8a0ec..f3400ee 100644
--- a/inc/integrations/SyncToUser.php
+++ b/inc/integrations/SyncToUser.php
@@ -36,6 +36,9 @@
 	}
 	protected function handleUpdateUser(int $userID):void
 	{
+		if (!$this->isSetUp()) {
+			return;
+		}
 		if (isset(self::$syncing['users'][$userID])) {
 			return;
 		}
@@ -142,6 +145,9 @@
 	 */
 	protected function handleTheSaveUser(int $userID):void
 	{
+		if (!$this->isSetUp()) {
+			return;
+		}
 		error_log('==== ['.$this->title.']::handleTheSaveUser ====');
 		//TODO: This is likely only for stuff like customers.
 		//If we have multiple stores connected, we may have to queue operations to update every connection's customer account if they made an order with that store
diff --git a/src/event/style.scss b/src/event/style.scss
index 8319146..4c7d265 100644
--- a/src/event/style.scss
+++ b/src/event/style.scss
@@ -15,6 +15,11 @@
 		}
 	}
 
+	> img {
+		max-width: min(250px, 80vw);
+		margin: 0 auto;
+	}
+
 	header {
 		--wrap: nowrap!important;
 		gap: 1rem;
diff --git a/src/simple-calendar/style.scss b/src/simple-calendar/style.scss
index 6b0cfac..137390e 100644
--- a/src/simple-calendar/style.scss
+++ b/src/simple-calendar/style.scss
@@ -19,5 +19,98 @@
 
 	nav.calendar.types {
 		height: max-content;
+		ul,li, a {
+			height: var(--chipchip);
+		}
+		ul {
+			--justify: flex-start;
+		}
+		details {
+			margin: 0;
+			display: block;
+
+			summary {
+				width: 100%;
+				display: flex;
+			}
+
+		}
+	}
+
+	.calendar.col {
+		border-radius: .5rem;
+		border: 2px solid rgb(var(--action-0));
+		width: var(--btn_);
+		--align: stretch;
+		--gap: 0;
+
+		span {
+			text-align: center;
+			text-transform: uppercase;
+			line-height: .8;
+		}
+		.weekday {
+			background-color: rgb(var(--action-0));
+			color: rgb(var(--action-contrast));
+			font-weight: var(--fw-h-bold);
+			font-family: var(--heading);
+			line-height: 1.4;
+			margin-bottom: .5rem;
+		}
+
+		.day {
+			font-size: var(--txt-xx-large);
+		}
+	}
+	details {
+		&#calendar, &#past {
+			display: block;
+		}
+	}
+	.item-list {
+		list-style: none;
+		margin: 0;
+		min-width: 100%;
+
+		> li {
+			width: 100%;
+			padding: 1rem .25rem;
+
+			+ li {
+				margin-top: 1rem;
+				border-top: 1px solid rgb(var(--base-200));
+			}
+
+			>img {
+				max-width: 250px;
+				margin: 0 auto;
+			}
+
+			.header {
+				--gap: 1rem;
+				--wrap: nowrap;
+			}
+			h3 {
+				margin: 0;
+			}
+			.meta {
+				display: flex;
+				gap: 1rem;
+			}
+		}
+	}
+	.tags {
+		--gap: 1rem;
+
+		.tag {
+			display: flex;
+			gap: .5rem;
+			background-color: rgb(var(--action-0));
+			color: rgb(var(--action-contrast));
+			font-size: var(--txt-x-small);
+			text-transform: uppercase;
+			border-radius: 4px;
+			padding: .25rem .5rem 0;
+		}
 	}
 }

--
Gitblit v1.10.0