Jake Vanderwerf
2026-09-13 1aa7c404dae63c9518468fe9b579fad819f8d871
inc/registrar/helpers/MakeCalendarType.php
@@ -1,9 +1,11 @@
<?php
namespace JVBase\registrar\helpers;
use DateTime;
use JVBase\meta\Meta;
use JVBase\registrar\Registrar;
use WP_Post;
use WP_Query;
if (!defined('ABSPATH')) {
   exit;
@@ -12,7 +14,8 @@
class MakeCalendarType {
   protected string $slug;
   protected string $postType;
   protected Registrar $registrar;
   private Registrar $registrar;
   protected string $hook;
   public function __construct(string $slug, Registrar $registrar) {
      $this->slug = $slug;
      $this->postType = jvbCheckBase($slug);
@@ -23,6 +26,16 @@
      add_filter('post_type_archive_link', [$this, 'handlePostTypeArchiveLinks'], 15, 2);
      add_filter('query_vars', [$this, 'addQueryVars']);
      add_action('init', [$this, 'addCalendarRewrites']);
      $this->hook = BASE.'mark_'.$this->slug.'_passed';
      add_action($this->hook, [$this, 'markPassed']);
   }
   public function __debugInfo() {
      $vars = get_object_vars($this);
      unset($vars['registrar']);
      return $vars;
   }
   protected function addCalendarFields():void
@@ -40,54 +53,59 @@
         ],
         'date_start' => [
            'type'      => 'date',
            'label'     => __('Date', 'jvb'),
            'label'     => 'Date',
         ],
         'time_start' => [
            'type'      => 'time',
            'label'     => __('Time Start', 'jvb'),
            'label'     => 'Time Start',
         ],
         'time_end' => [
            'type'      => 'time',
            'label'     => __('Time End', 'jvb'),
            'label'     => 'Time End',
         ],
         'make_multiple' => [
            'type'      => 'true_false',
            'label'     => 'Make Multi-Day Event',
            'default'   => false,
         ],
         'date_end' => [
            'type'      => 'date',
            'label'     => __('Date End', 'jvb'),
            'condition' => [
               'field' => 'make_multiple',
               'operator' => '==',
               'value' => 1
            ]
         ],
//       'date_end' => [
//          'type'      => 'date',
//          'label'     => 'Date End',
//          'condition' => [
//             'field' => 'make_multiple',
//             'operator' => '==',
//             'value' => 1
//          ]
//       ],
         'past' => [
            'type'      => 'true_false',
            'label'     => __('Past Event', 'jvb'),
            'label'     => 'Past Event',
            'hidden'    => true,
         ],
         'year' => [
            'type'      => 'number',
            'label'     => __('Year', 'jvb'),
            'type'      => 'text',
            'subtype'   => 'number',
            'label'     => 'Year',
            'hidden'    => true,
         ],
         'month' => [
            'type'      => 'number',
            'label'     => __('Month', 'jvb'),
            'type'      => 'text',
            'subtype'   => 'number',
            'label'     => 'Month',
            'hidden'    => true,
         ],
         'day' => [
            'type'      => 'number',
            'label'     => __('Day', 'jvb'),
            'type'      => 'text',
            'subtype'   => 'number',
            'label'     => 'Day',
            'hidden'    => true,
         ],
         'schedule' => [
            'type' => 'repeater',
            'label' => 'Daily Schedule',
            'description' => 'Set specific times for multi-day events',
            'add_label' => 'Add Day',
            'row_label' => 'New Day',
            'condition' => [
               'field'  => 'make_multiple',
               'operator' => '==',
@@ -114,7 +132,8 @@
         ],
         'max_participants' => [
            'type'      => 'number',
            'label'     => __('Maximum Participants', 'jvb'),
            'label'     => 'Maximum Participants',
            'hint'      => 'Leave 0 for no maximum'
         ],
         'is_free' => [
            'type' => 'true_false',
@@ -149,107 +168,115 @@
            'label' => 'Drop-ins Welcome?',
            'default' => true,
         ],
         'recurrence' => [
            'type' => 'group',
            'label' => 'Event Recurrence',
            'condition' => [
               'field'  => 'status',
               'operator' => '==',
               'value'  => 'repeat',
            ],
            'fields' => [
               'recurrence_type' => [
                  'type' => 'select',
                  'label' => 'Repeats',
                  'options' => [
                     'daily' => 'Daily',
                     'weekly' => 'Weekly',
                     'monthly' => 'Monthly',
                     'custom' => 'Custom'
                  ]
               ],
               'recurrence_interval' => [
                  'type' => 'number',
                  'label' => 'Every',
                  'description' => 'Repeat every X days/weeks/months',
                  'default' => 1,
               ],
               'recurrence_days' => [
                  'type' => 'set',
                  'label' => 'On These Days',
                  'options' => [
                     'monday' => 'Monday',
                     'tuesday' => 'Tuesday',
                     'wednesday' => 'Wednesday',
                     'thursday' => 'Thursday',
                     'friday' => 'Friday',
                     'saturday' => 'Saturday',
                     'sunday' => 'Sunday'
                  ],
                  'condition' => [
                     'field' => 'recurrence_type',
                     'operator' => '==',
                     'value' => 'weekly'
                  ]
               ],
               'recurrence_ends' => [
                  'type' => 'group',
                  'label' => 'Recurrence Ends',
                  'fields' => [
                     'type' => [
                        'type' => 'select',
                        'label' => 'Recurrence Ends',
                        'options' => [
                           'never' => 'Never',
                           'after' => 'After X occurrences',
                           'on' => 'On date'
                        ]
                     ],
                     'count' => [
                        'type' => 'number',
                        'label' => 'Number of occurrences',
                        'condition' => [
                           'field' => 'type',
                           'operator' => '==',
                           'value' => 'after'
                        ]
                     ],
                     'date' => [
                        'type' => 'date',
                        'label' => 'End date',
                        'condition' => [
                           'field' => 'type',
                           'operator' => '==',
                           'value' => 'on'
                        ]
                     ]
                  ],
               ],
               'rsvp_required' => [
                  'type' => 'true_false',
                  'label' => 'RSVP Required?'
               ],
               'rsvp_limit' => [
                  'type' => 'number',
                  'label' => 'RSVP Limit',
                  'condition' => [
                     'field' => 'rsvp_required',
                     'operator' => '==',
                     'value' => 1
                  ]
               ],
               'rsvp_deadline' => [
                  'type' => 'datetime',
                  'label' => 'RSVP Deadline',
                  'condition' => [
                     'field' => 'rsvp_required',
                     'operator' => '==',
                     'value' => 1
                  ]
               ],
         //TODO
         //RECURRENCE
//       'make_recurring' => [
//          'type' => 'true_false',
//          'label' => 'Make Repeating Event',
//          'default' => 0,
//       ],
//       'recurrence_type' => [
//          'type' => 'select',
//          'label' => 'Repeats',
//          'options' => [
//             'daily' => 'Daily',
//             'weekly' => 'Weekly',
//             'monthly' => 'Monthly',
//             'custom' => 'Custom'
//          ],
//          'condition' => [
//             'field'  => 'make_recurring',
//             'operator' => '==',
//             'value'  => '1',
//          ],
//       ],
//       'recurrence_interval' => [
//          'type' => 'number',
//          'label' => 'Repeat',
//          'description' => 'Repeat every X days/weeks/months',
//          'default' => 1,
//
//          'condition' => [
//             'field'  => 'make_recurring',
//             'operator' => '==',
//             'value'  => '1',
//          ],
//       ],
//       'recurrence_days' => [
//          'type' => 'set',
//          'label' => 'On These Days',
//          'options' => [
//             'monday' => 'Monday',
//             'tuesday' => 'Tuesday',
//             'wednesday' => 'Wednesday',
//             'thursday' => 'Thursday',
//             'friday' => 'Friday',
//             'saturday' => 'Saturday',
//             'sunday' => 'Sunday'
//          ],
//          'condition' => [
//             'field' => 'recurrence_type',
//             'operator' => '==',
//             'value' => 'weekly'
//          ]
//       ],
//       'recurrence_ends' => [
//          'type' => 'select',
//          'label' => 'Recurrence Ends',
//          'options' => [
//             'never' => 'Never',
//             'after' => 'After X occurrences',
//             'on' => 'On date'
//          ],
//          'condition' => [
//             'field'  => 'make_recurring',
//             'operator' => '==',
//             'value'  => '1',
//          ],
//       ],
//       'recurrence_ends_number' => [
//          'type' => 'number',
//          'label' => 'Number of occurrences',
//          'condition' => [
//             'field'  => 'recurrence_ends',
//             'operator' => '==',
//             'value'  => 'after',
//          ],
//       ],
//       'recurrence_ends_date' => [
//          'type' => 'date',
//          'label' => 'End date',
//          'condition' => [
//             'field' => 'recurrence_ends',
//             'operator' => '==',
//             'value' => 'on'
//          ]
//       ],
         //RSVP
         'rsvp_required' => [
            'type' => 'true_false',
            'label' => 'RSVP Required?'
         ],
         'rsvp_limit' => [
            'type' => 'number',
            'label' => 'RSVP Limit',
            'condition' => [
               'field' => 'rsvp_required',
               'operator' => '==',
               'value' => 1
            ]
         ]
         ],
         'rsvp_deadline' => [
            'type' => 'datetime',
            'label' => 'RSVP Deadline',
            'condition' => [
               'field' => 'rsvp_required',
               'operator' => '==',
               'value' => 1
            ]
         ],
      ];
      foreach ($fields as $name => $config) {
@@ -290,15 +317,27 @@
         $get = ['year', 'month','day'];
         $values = Meta::forPost($post->ID)->getAll($get);
         foreach ($values as $key => $value) {
         if (empty($values['year']) || empty($values['month']) || empty($values['day'])) {
            $value = Meta::forPost($post->ID)->get('date_start');
            if (!empty($value)) {
               $url = str_replace("%e$key%", $value, $url);
               $date = new DateTime($value, wp_timezone());
               $year = $date->format('Y');
               $month = $date->format('m');
               $day = $date->format('d');
               $values = [
                  'year'  => $year,
                  'month' => $month,
                  'day'   => $day
               ];
               Meta::forPost($post->ID)->setAll($values);
            }
         }
         $doubleCheck = ['eyear', 'emonth', 'eday'];
         foreach ($doubleCheck as $check) {
            if (str_contains($url, $check)) {
               $url = str_replace("/%e$check%", '', $url);
         foreach ($values as $key => $value) {
            if (!empty($value) && $value !== 0) {
               $url = str_replace("%e$key%", $value, $url);
            } else {
               $url = str_replace("/%e$key%", '', $url);
            }
         }
      }
@@ -321,10 +360,106 @@
      return $vars;
   }
   protected function scheduleMarkPassed():void
   {
      if (!wp_next_scheduled($this->hook)) {
         $time = strtotime('tomorrow at 12:01am');
         wp_schedule_event($time, 'daily', $this->hook);
      }
   }
      public function markPassed():void
      {
         $now = date('Y-m-d');
         $items = new WP_Query([
            'post_type'       => $this->postType,
            'posts_per_page'  => -1,
            'post_status'     => 'publish',
            'meta_query'      => [
               'relation'  => 'AND',
               [
                  'key' => BASE.'past',
                  'value'  => '1',
                  'compare'=> '!='
               ],
               [
                  'key' => BASE.'date_start',
                  'value'  => $now,
                  'compare'   => '<',
                  'type'   => 'DATETIME'
               ]
            ],
            'fields' => 'ids',
         ]);
         if ($items->have_posts()) {
            foreach ($items->posts as $ID) {
               $meta = Meta::forPost($ID);
               $meta->set('past', '1');
            }
         }
      }
   public function addCalendarRewrites():void
   {
      $this->scheduleMarkPassed();
      add_rewrite_tag('%eyear%', '([^&]+)');
      add_rewrite_tag('%emonth%', '([^&]+)');
      add_rewrite_tag('%eday%', '([^&]+)');
      $registrar = Registrar::getInstance($this->slug);
      $base = $registrar->registrar->rewrite['slug']??$this->slug;
      // Adds the rewrite rule to capture URLs with year, month, and day.
      add_rewrite_rule(
         '^'.$base.'/([0-9]{4})/([0-9]{2})/([0-9]{2})/?$',
         'index.php?post_type='.$this->postType.'&eyear=$matches[1]&emonth=$matches[2]&eday=$matches[3]',
         'top'
      );
         add_rewrite_rule(
            '^'.$base.'/([0-9]{4})/([0-9]{2})/([0-9]{2})/page/([0-9-]+)/?$',
            'index.php?post_type='.$this->postType.'&eyear=$matches[1]&emonth=$matches[2]&eday=$matches[3]&paged=$matches[4]',
            'top'
         );
      // Adds the rewrite rule to capture URLs with year, month only.
      add_rewrite_rule(
         '^'.$base.'/([0-9]{4})/([0-9]{2})/?$',
         'index.php?post_type='.$this->postType.'&eyear=$matches[1]&emonth=$matches[2]',
         'top'
      );
         add_rewrite_rule(
            '^'.$base.'/([0-9]{4})/([0-9]{2})/page/([0-9-]+)/?$',
            'index.php?post_type='.$this->postType.'&eyear=$matches[1]&emonth=$matches[2]&paged=$matches[3]',
            'top'
         );
      // Adds the rewrite rule to capture URLs with year only.
      add_rewrite_rule(
         '^'.$base.'/([0-9]{4})/?$',
         'index.php?post_type='.$this->postType.'&eyear=$matches[1]',
         'top'
      );
         add_rewrite_rule(
            '^'.$base.'/([0-9]{4})/page/([0-9-]+)/?$',
            'index.php?post_type='.$this->postType.'&eyear=$matches[1]&paged=$matches[2]',
            'top'
         );
      // Adds the rewrite rule for all events
      add_rewrite_rule(
         '^'.$base.'/?$',
         'index.php?post_type='.$this->postType,
         'top'
      );
         add_rewrite_rule(
            '^'.$base.'/page/([0-9-]+)/?$',
            'index.php?post_type='.$this->postType.'&paged=$matches[1]',
            'top'
         );
      add_rewrite_rule(
         "^{$base}/([^/]+)/?$",
         "index.php?post_type={$this->postType}&name=\$matches[1]",
         'top'
      );
   }
}