Jake Vanderwerf
2026-09-14 7935d26cd16a4f8f69a59a44e27a7263b60e54bf
=Simple Calendar block up and running
15 files modified
1 files added
538 ■■■■■ changed files
build/event/index.asset.php 2 ●●●●● patch | view | raw | blame | history
build/event/style-index-rtl.css 2 ●●●●● patch | view | raw | blame | history
build/event/style-index.css 2 ●●●●● patch | view | raw | blame | history
build/simple-calendar/index.asset.php 2 ●●●●● patch | view | raw | blame | history
build/simple-calendar/style-index-rtl.css 2 ●●●●● patch | view | raw | blame | history
build/simple-calendar/style-index.css 2 ●●●●● patch | view | raw | blame | history
inc/blocks/EventBlock.php 147 ●●●●● patch | view | raw | blame | history
inc/blocks/SimpleCalendarBlock.php 70 ●●●●● patch | view | raw | blame | history
inc/helpers/Events.php 183 ●●●●● patch | view | raw | blame | history
inc/helpers/all.php 1 ●●●●● patch | view | raw | blame | history
inc/helpers/terms.php 9 ●●●●● patch | view | raw | blame | history
inc/integrations/SyncToPost.php 6 ●●●●● patch | view | raw | blame | history
inc/integrations/SyncToTerm.php 6 ●●●●● patch | view | raw | blame | history
inc/integrations/SyncToUser.php 6 ●●●●● patch | view | raw | blame | history
src/event/style.scss 5 ●●●●● patch | view | raw | blame | history
src/simple-calendar/style.scss 93 ●●●●● patch | view | raw | blame | history
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');
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}
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}
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');
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}
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}
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
    {
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]??'';
    }
}
inc/helpers/Events.php
New file
@@ -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;
    }
}
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');
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>' : '';
}
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;
        }
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;
        }
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
src/event/style.scss
@@ -15,6 +15,11 @@
        }
    }
    > img {
        max-width: min(250px, 80vw);
        margin: 0 auto;
    }
    header {
        --wrap: nowrap!important;
        gap: 1rem;
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;
        }
    }
}