| | |
| | | <?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; |
| | |
| | | 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); |
| | |
| | | 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 |
| | |
| | | ], |
| | | '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' => '==', |
| | |
| | | ], |
| | | 'max_participants' => [ |
| | | 'type' => 'number', |
| | | 'label' => __('Maximum Participants', 'jvb'), |
| | | 'label' => 'Maximum Participants', |
| | | 'hint' => 'Leave 0 for no maximum' |
| | | ], |
| | | 'is_free' => [ |
| | | 'type' => 'true_false', |
| | |
| | | '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) { |
| | |
| | | $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); |
| | | } |
| | | } |
| | | } |
| | |
| | | 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' |
| | | ); |
| | | |
| | | } |
| | | } |