Completed
Branch master (87d3f3)
by
unknown
03:30
created
core/db_classes/EE_Event.class.php 1 patch
Indentation   +1633 added lines, -1633 removed lines patch added patch discarded remove patch
@@ -16,1640 +16,1640 @@
 block discarded – undo
16 16
  */
17 17
 class EE_Event extends EE_CPT_Base implements EEI_Line_Item_Object, EEI_Admin_Links, EEI_Has_Icon, EEI_Event
18 18
 {
19
-    /**
20
-     * cached value for the the logical active status for the event
21
-     *
22
-     * @see get_active_status()
23
-     * @var string
24
-     */
25
-    protected $_active_status = '';
26
-
27
-    /**
28
-     * This is just used for caching the Primary Datetime for the Event on initial retrieval
29
-     *
30
-     * @var EE_Datetime
31
-     */
32
-    protected $_Primary_Datetime;
33
-
34
-    /**
35
-     * @var EventSpacesCalculator $available_spaces_calculator
36
-     */
37
-    protected $available_spaces_calculator;
38
-
39
-
40
-    /**
41
-     * @param array  $props_n_values          incoming values
42
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
43
-     *                                        used.)
44
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
45
-     *                                        date_format and the second value is the time format
46
-     * @return EE_Event
47
-     * @throws EE_Error
48
-     * @throws ReflectionException
49
-     */
50
-    public static function new_instance($props_n_values = [], $timezone = null, $date_formats = []): EE_Event
51
-    {
52
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
53
-        return $has_object ?: new self($props_n_values, false, $timezone, $date_formats);
54
-    }
55
-
56
-
57
-    /**
58
-     * @param array  $props_n_values  incoming values from the database
59
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
60
-     *                                the website will be used.
61
-     * @return EE_Event
62
-     * @throws EE_Error
63
-     * @throws ReflectionException
64
-     */
65
-    public static function new_instance_from_db($props_n_values = [], $timezone = null): EE_Event
66
-    {
67
-        return new self($props_n_values, true, $timezone);
68
-    }
69
-
70
-
71
-    /**
72
-     * @return EventSpacesCalculator
73
-     * @throws EE_Error
74
-     * @throws ReflectionException
75
-     */
76
-    public function getAvailableSpacesCalculator(): EventSpacesCalculator
77
-    {
78
-        if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
79
-            $this->available_spaces_calculator = new EventSpacesCalculator($this);
80
-        }
81
-        return $this->available_spaces_calculator;
82
-    }
83
-
84
-
85
-    /**
86
-     * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
87
-     *
88
-     * @param string $field_name
89
-     * @param mixed  $field_value
90
-     * @param bool   $use_default
91
-     * @throws EE_Error
92
-     * @throws ReflectionException
93
-     */
94
-    public function set($field_name, $field_value, $use_default = false)
95
-    {
96
-        switch ($field_name) {
97
-            case 'status':
98
-                $this->set_status($field_value, $use_default);
99
-                break;
100
-            default:
101
-                parent::set($field_name, $field_value, $use_default);
102
-        }
103
-    }
104
-
105
-
106
-    /**
107
-     *    set_status
108
-     * Checks if event status is being changed to SOLD OUT
109
-     * and updates event meta data with previous event status
110
-     * so that we can revert things if/when the event is no longer sold out
111
-     *
112
-     * @param string $status
113
-     * @param bool   $use_default
114
-     * @return void
115
-     * @throws EE_Error
116
-     * @throws ReflectionException
117
-     */
118
-    public function set_status($status = '', $use_default = false)
119
-    {
120
-        // if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
121
-        if (empty($status) && ! $use_default) {
122
-            return;
123
-        }
124
-        // get current Event status
125
-        $old_status = $this->status();
126
-        // if status has changed
127
-        if ($old_status !== $status) {
128
-            // TO sold_out
129
-            if ($status === EEM_Event::sold_out) {
130
-                // save the previous event status so that we can revert if the event is no longer sold out
131
-                $this->add_post_meta('_previous_event_status', $old_status);
132
-                do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $status);
133
-                // OR FROM  sold_out
134
-            } elseif ($old_status === EEM_Event::sold_out) {
135
-                $this->delete_post_meta('_previous_event_status');
136
-                do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $status);
137
-            }
138
-            // clear out the active status so that it gets reset the next time it is requested
139
-            $this->_active_status = null;
140
-            // update status
141
-            parent::set('status', $status, $use_default);
142
-            do_action('AHEE__EE_Event__set_status__after_update', $this);
143
-            return;
144
-        }
145
-        // even though the old value matches the new value, it's still good to
146
-        // allow the parent set method to have a say
147
-        parent::set('status', $status, $use_default);
148
-    }
149
-
150
-
151
-    /**
152
-     * Gets all the datetimes for this event
153
-     *
154
-     * @param array|null $query_params
155
-     * @return EE_Base_Class[]|EE_Datetime[]
156
-     * @throws EE_Error
157
-     * @throws ReflectionException
158
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
159
-     */
160
-    public function datetimes(?array $query_params = []): array
161
-    {
162
-        return $this->get_many_related('Datetime', $query_params);
163
-    }
164
-
165
-
166
-    /**
167
-     * Gets all the datetimes for this event that are currently ACTIVE,
168
-     * meaning the datetime has started and has not yet ended.
169
-     *
170
-     * @param int|null   $start_date   timestamp to use for event date start time, defaults to NOW unless set to 0
171
-     * @param array|null $query_params will recursively replace default values
172
-     * @throws EE_Error
173
-     * @throws ReflectionException
174
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
175
-     */
176
-    public function activeDatetimes(?int $start_date, ?array $query_params = []): array
177
-    {
178
-        // if start date is null, then use current time
179
-        $start_date = $start_date ?? time();
180
-        $where      = [];
181
-        if ($start_date) {
182
-            $where['DTT_EVT_start'] = ['<', $start_date];
183
-            $where['DTT_EVT_end']   = ['>', time()];
184
-        }
185
-        $query_params = array_replace_recursive(
186
-            [
187
-                $where,
188
-                'order_by' => ['DTT_EVT_start' => 'ASC'],
189
-            ],
190
-            $query_params
191
-        );
192
-        return $this->get_many_related('Datetime', $query_params);
193
-    }
194
-
195
-
196
-    /**
197
-     * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
198
-     *
199
-     * @return EE_Base_Class[]|EE_Datetime[]
200
-     * @throws EE_Error
201
-     * @throws ReflectionException
202
-     */
203
-    public function datetimes_in_chronological_order(): array
204
-    {
205
-        return $this->get_many_related('Datetime', ['order_by' => ['DTT_EVT_start' => 'ASC']]);
206
-    }
207
-
208
-
209
-    /**
210
-     * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
211
-     * @darren, we should probably UNSET timezone on the EEM_Datetime model
212
-     * after running our query, so that this timezone isn't set for EVERY query
213
-     * on EEM_Datetime for the rest of the request, no?
214
-     *
215
-     * @param bool     $show_expired whether or not to include expired events
216
-     * @param bool     $show_deleted whether or not to include deleted events
217
-     * @param int|null $limit
218
-     * @return EE_Datetime[]
219
-     * @throws EE_Error
220
-     * @throws ReflectionException
221
-     */
222
-    public function datetimes_ordered(bool $show_expired = true, bool $show_deleted = false, ?int $limit = null): array
223
-    {
224
-        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
225
-            $this->ID(),
226
-            $show_expired,
227
-            $show_deleted,
228
-            $limit
229
-        );
230
-    }
231
-
232
-
233
-    /**
234
-     * Returns one related datetime. Mostly only used by some legacy code.
235
-     *
236
-     * @return EE_Base_Class|EE_Datetime
237
-     * @throws EE_Error
238
-     * @throws ReflectionException
239
-     */
240
-    public function first_datetime(): EE_Datetime
241
-    {
242
-        return $this->get_first_related('Datetime');
243
-    }
244
-
245
-
246
-    /**
247
-     * Returns the 'primary' datetime for the event
248
-     *
249
-     * @param bool $try_to_exclude_expired
250
-     * @param bool $try_to_exclude_deleted
251
-     * @return EE_Datetime|null
252
-     * @throws EE_Error
253
-     * @throws ReflectionException
254
-     */
255
-    public function primary_datetime(
256
-        bool $try_to_exclude_expired = true,
257
-        bool $try_to_exclude_deleted = true
258
-    ): ?EE_Datetime {
259
-        if (! empty($this->_Primary_Datetime)) {
260
-            return $this->_Primary_Datetime;
261
-        }
262
-        $this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
263
-            $this->ID(),
264
-            $try_to_exclude_expired,
265
-            $try_to_exclude_deleted
266
-        );
267
-        return $this->_Primary_Datetime;
268
-    }
269
-
270
-
271
-    /**
272
-     * Gets all the tickets available for purchase of this event
273
-     *
274
-     * @param array|null $query_params
275
-     * @return EE_Base_Class[]|EE_Ticket[]
276
-     * @throws EE_Error
277
-     * @throws ReflectionException
278
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
279
-     */
280
-    public function tickets(?array $query_params = []): array
281
-    {
282
-        // first get all datetimes
283
-        $datetimes = $this->datetimes_ordered();
284
-        if (! $datetimes) {
285
-            return [];
286
-        }
287
-        $datetime_ids = [];
288
-        foreach ($datetimes as $datetime) {
289
-            $datetime_ids[] = $datetime->ID();
290
-        }
291
-        $where_params = ['Datetime.DTT_ID' => ['IN', $datetime_ids]];
292
-        // if incoming $query_params has where conditions let's merge but not override existing.
293
-        if (is_array($query_params) && isset($query_params[0])) {
294
-            $where_params = array_merge($query_params[0], $where_params);
295
-            unset($query_params[0]);
296
-        }
297
-        // now add $where_params to $query_params
298
-        $query_params[0] = $where_params;
299
-        return EEM_Ticket::instance()->get_all($query_params);
300
-    }
301
-
302
-
303
-    /**
304
-     * get all unexpired not-trashed tickets
305
-     *
306
-     * @return EE_Ticket[]
307
-     * @throws EE_Error
308
-     * @throws ReflectionException
309
-     */
310
-    public function active_tickets(): array
311
-    {
312
-        return $this->tickets(
313
-            [
314
-                [
315
-                    'TKT_end_date' => ['>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')],
316
-                    'TKT_deleted'  => false,
317
-                ],
318
-            ]
319
-        );
320
-    }
321
-
322
-
323
-    /**
324
-     * @return int
325
-     * @throws EE_Error
326
-     * @throws ReflectionException
327
-     */
328
-    public function additional_limit(): int
329
-    {
330
-        return $this->get('EVT_additional_limit');
331
-    }
332
-
333
-
334
-    /**
335
-     * @return bool
336
-     * @throws EE_Error
337
-     * @throws ReflectionException
338
-     */
339
-    public function allow_overflow(): bool
340
-    {
341
-        return $this->get('EVT_allow_overflow');
342
-    }
343
-
344
-
345
-    /**
346
-     * @return string
347
-     * @throws EE_Error
348
-     * @throws ReflectionException
349
-     */
350
-    public function created(): string
351
-    {
352
-        return $this->get('EVT_created');
353
-    }
354
-
355
-
356
-    /**
357
-     * @return string
358
-     * @throws EE_Error
359
-     * @throws ReflectionException
360
-     */
361
-    public function description(): string
362
-    {
363
-        return $this->get('EVT_desc');
364
-    }
365
-
366
-
367
-    /**
368
-     * Runs do_shortcode and wpautop on the description
369
-     *
370
-     * @return string of html
371
-     * @throws EE_Error
372
-     * @throws ReflectionException
373
-     */
374
-    public function description_filtered(): string
375
-    {
376
-        return $this->get_pretty('EVT_desc');
377
-    }
378
-
379
-
380
-    /**
381
-     * @return bool
382
-     * @throws EE_Error
383
-     * @throws ReflectionException
384
-     */
385
-    public function display_description(): bool
386
-    {
387
-        return $this->get('EVT_display_desc');
388
-    }
389
-
390
-
391
-    /**
392
-     * @return bool
393
-     * @throws EE_Error
394
-     * @throws ReflectionException
395
-     */
396
-    public function display_ticket_selector(): bool
397
-    {
398
-        return (bool) $this->get('EVT_display_ticket_selector');
399
-    }
400
-
401
-
402
-    /**
403
-     * @return string
404
-     * @throws EE_Error
405
-     * @throws ReflectionException
406
-     */
407
-    public function external_url(): ?string
408
-    {
409
-        return $this->get('EVT_external_URL') ?? '';
410
-    }
411
-
412
-
413
-    /**
414
-     * @return bool
415
-     * @throws EE_Error
416
-     * @throws ReflectionException
417
-     */
418
-    public function member_only(): bool
419
-    {
420
-        return $this->get('EVT_member_only');
421
-    }
422
-
423
-
424
-    /**
425
-     * @return string
426
-     * @throws EE_Error
427
-     * @throws ReflectionException
428
-     */
429
-    public function phone(): string
430
-    {
431
-        return $this->get('EVT_phone');
432
-    }
433
-
434
-
435
-    /**
436
-     * @return string
437
-     * @throws EE_Error
438
-     * @throws ReflectionException
439
-     */
440
-    public function modified(): string
441
-    {
442
-        return $this->get('EVT_modified');
443
-    }
444
-
445
-
446
-    /**
447
-     * @return string
448
-     * @throws EE_Error
449
-     * @throws ReflectionException
450
-     */
451
-    public function name(): string
452
-    {
453
-        return $this->get('EVT_name');
454
-    }
455
-
456
-
457
-    /**
458
-     * @return int
459
-     * @throws EE_Error
460
-     * @throws ReflectionException
461
-     */
462
-    public function order(): int
463
-    {
464
-        return $this->get('EVT_order');
465
-    }
466
-
467
-
468
-    /**
469
-     * @return string
470
-     * @throws EE_Error
471
-     * @throws ReflectionException
472
-     */
473
-    public function default_registration_status(): string
474
-    {
475
-        $event_default_registration_status = $this->get('EVT_default_registration_status');
476
-        return ! empty($event_default_registration_status)
477
-            ? $event_default_registration_status
478
-            : EE_Registry::instance()->CFG->registration->default_STS_ID;
479
-    }
480
-
481
-
482
-    /**
483
-     * @param int|null    $num_words
484
-     * @param string|null $more
485
-     * @param bool        $not_full_desc
486
-     * @return string
487
-     * @throws EE_Error
488
-     * @throws ReflectionException
489
-     */
490
-    public function short_description(?int $num_words = 55, string $more = null, bool $not_full_desc = false): string
491
-    {
492
-        $short_desc = $this->get('EVT_short_desc');
493
-        if (! empty($short_desc) || $not_full_desc) {
494
-            return $short_desc;
495
-        }
496
-        $full_desc = $this->get('EVT_desc');
497
-        return wp_trim_words($full_desc, $num_words, $more);
498
-    }
499
-
500
-
501
-    /**
502
-     * @return string
503
-     * @throws EE_Error
504
-     * @throws ReflectionException
505
-     */
506
-    public function slug(): string
507
-    {
508
-        return $this->get('EVT_slug');
509
-    }
510
-
511
-
512
-    /**
513
-     * @return string
514
-     * @throws EE_Error
515
-     * @throws ReflectionException
516
-     */
517
-    public function timezone_string(): string
518
-    {
519
-        return $this->get('EVT_timezone_string');
520
-    }
521
-
522
-
523
-    /**
524
-     * @return string
525
-     * @throws EE_Error
526
-     * @throws ReflectionException
527
-     * @deprecated
528
-     */
529
-    public function visible_on(): string
530
-    {
531
-        EE_Error::doing_it_wrong(
532
-            __METHOD__,
533
-            esc_html__(
534
-                'This method has been deprecated and there is no replacement for it.',
535
-                'event_espresso'
536
-            ),
537
-            '5.0.0.rc.002'
538
-        );
539
-        return $this->get('EVT_visible_on');
540
-    }
541
-
542
-
543
-    /**
544
-     * @return int
545
-     * @throws EE_Error
546
-     * @throws ReflectionException
547
-     */
548
-    public function wp_user(): int
549
-    {
550
-        return $this->get('EVT_wp_user');
551
-    }
552
-
553
-
554
-    /**
555
-     * @return bool
556
-     * @throws EE_Error
557
-     * @throws ReflectionException
558
-     */
559
-    public function donations(): bool
560
-    {
561
-        return $this->get('EVT_donations');
562
-    }
563
-
564
-
565
-    /**
566
-     * @param int $limit
567
-     * @throws EE_Error
568
-     * @throws ReflectionException
569
-     */
570
-    public function set_additional_limit(int $limit)
571
-    {
572
-        $this->set('EVT_additional_limit', $limit);
573
-    }
574
-
575
-
576
-    /**
577
-     * @param $created
578
-     * @throws EE_Error
579
-     * @throws ReflectionException
580
-     */
581
-    public function set_created($created)
582
-    {
583
-        $this->set('EVT_created', $created);
584
-    }
585
-
586
-
587
-    /**
588
-     * @param $desc
589
-     * @throws EE_Error
590
-     * @throws ReflectionException
591
-     */
592
-    public function set_description($desc)
593
-    {
594
-        $this->set('EVT_desc', $desc);
595
-    }
596
-
597
-
598
-    /**
599
-     * @param $display_desc
600
-     * @throws EE_Error
601
-     * @throws ReflectionException
602
-     */
603
-    public function set_display_description($display_desc)
604
-    {
605
-        $this->set('EVT_display_desc', $display_desc);
606
-    }
607
-
608
-
609
-    /**
610
-     * @param $display_ticket_selector
611
-     * @throws EE_Error
612
-     * @throws ReflectionException
613
-     */
614
-    public function set_display_ticket_selector($display_ticket_selector)
615
-    {
616
-        $this->set('EVT_display_ticket_selector', $display_ticket_selector);
617
-    }
618
-
619
-
620
-    /**
621
-     * @param $external_url
622
-     * @throws EE_Error
623
-     * @throws ReflectionException
624
-     */
625
-    public function set_external_url($external_url)
626
-    {
627
-        $this->set('EVT_external_URL', $external_url);
628
-    }
629
-
630
-
631
-    /**
632
-     * @param $member_only
633
-     * @throws EE_Error
634
-     * @throws ReflectionException
635
-     */
636
-    public function set_member_only($member_only)
637
-    {
638
-        $this->set('EVT_member_only', $member_only);
639
-    }
640
-
641
-
642
-    /**
643
-     * @param $event_phone
644
-     * @throws EE_Error
645
-     * @throws ReflectionException
646
-     */
647
-    public function set_event_phone($event_phone)
648
-    {
649
-        $this->set('EVT_phone', $event_phone);
650
-    }
651
-
652
-
653
-    /**
654
-     * @param $modified
655
-     * @throws EE_Error
656
-     * @throws ReflectionException
657
-     */
658
-    public function set_modified($modified)
659
-    {
660
-        $this->set('EVT_modified', $modified);
661
-    }
662
-
663
-
664
-    /**
665
-     * @param $name
666
-     * @throws EE_Error
667
-     * @throws ReflectionException
668
-     */
669
-    public function set_name($name)
670
-    {
671
-        $this->set('EVT_name', $name);
672
-    }
673
-
674
-
675
-    /**
676
-     * @param $order
677
-     * @throws EE_Error
678
-     * @throws ReflectionException
679
-     */
680
-    public function set_order($order)
681
-    {
682
-        $this->set('EVT_order', $order);
683
-    }
684
-
685
-
686
-    /**
687
-     * @param $short_desc
688
-     * @throws EE_Error
689
-     * @throws ReflectionException
690
-     */
691
-    public function set_short_description($short_desc)
692
-    {
693
-        $this->set('EVT_short_desc', $short_desc);
694
-    }
695
-
696
-
697
-    /**
698
-     * @param $slug
699
-     * @throws EE_Error
700
-     * @throws ReflectionException
701
-     */
702
-    public function set_slug($slug)
703
-    {
704
-        $this->set('EVT_slug', $slug);
705
-    }
706
-
707
-
708
-    /**
709
-     * @param $timezone_string
710
-     * @throws EE_Error
711
-     * @throws ReflectionException
712
-     */
713
-    public function set_timezone_string($timezone_string)
714
-    {
715
-        $this->set('EVT_timezone_string', $timezone_string);
716
-    }
717
-
718
-
719
-    /**
720
-     * @param $visible_on
721
-     * @throws EE_Error
722
-     * @throws ReflectionException
723
-     * @deprecated
724
-     */
725
-    public function set_visible_on($visible_on)
726
-    {
727
-        EE_Error::doing_it_wrong(
728
-            __METHOD__,
729
-            esc_html__(
730
-                'This method has been deprecated and there is no replacement for it.',
731
-                'event_espresso'
732
-            ),
733
-            '5.0.0.rc.002'
734
-        );
735
-        $this->set('EVT_visible_on', $visible_on);
736
-    }
737
-
738
-
739
-    /**
740
-     * @param $wp_user
741
-     * @throws EE_Error
742
-     * @throws ReflectionException
743
-     */
744
-    public function set_wp_user($wp_user)
745
-    {
746
-        $this->set('EVT_wp_user', $wp_user);
747
-    }
748
-
749
-
750
-    /**
751
-     * @param $default_registration_status
752
-     * @throws EE_Error
753
-     * @throws ReflectionException
754
-     */
755
-    public function set_default_registration_status($default_registration_status)
756
-    {
757
-        $this->set('EVT_default_registration_status', $default_registration_status);
758
-    }
759
-
760
-
761
-    /**
762
-     * @param $donations
763
-     * @throws EE_Error
764
-     * @throws ReflectionException
765
-     */
766
-    public function set_donations($donations)
767
-    {
768
-        $this->set('EVT_donations', $donations);
769
-    }
770
-
771
-
772
-    /**
773
-     * Adds a venue to this event
774
-     *
775
-     * @param int|EE_Venue /int $venue_id_or_obj
776
-     * @return EE_Base_Class|EE_Venue
777
-     * @throws EE_Error
778
-     * @throws ReflectionException
779
-     */
780
-    public function add_venue($venue_id_or_obj): EE_Venue
781
-    {
782
-        return $this->_add_relation_to($venue_id_or_obj, 'Venue');
783
-    }
784
-
785
-
786
-    /**
787
-     * Removes a venue from the event
788
-     *
789
-     * @param EE_Venue /int $venue_id_or_obj
790
-     * @return EE_Base_Class|EE_Venue
791
-     * @throws EE_Error
792
-     * @throws ReflectionException
793
-     */
794
-    public function remove_venue($venue_id_or_obj): EE_Venue
795
-    {
796
-        $venue_id_or_obj = ! empty($venue_id_or_obj) ? $venue_id_or_obj : $this->venue();
797
-        return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
798
-    }
799
-
800
-
801
-    /**
802
-     * Gets the venue related to the event. May provide additional $query_params if desired
803
-     *
804
-     * @param array $query_params
805
-     * @return int
806
-     * @throws EE_Error
807
-     * @throws ReflectionException
808
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
809
-     */
810
-    public function venue_ID(array $query_params = []): int
811
-    {
812
-        $venue = $this->get_first_related('Venue', $query_params);
813
-        return $venue instanceof EE_Venue ? $venue->ID() : 0;
814
-    }
815
-
816
-
817
-    /**
818
-     * Gets the venue related to the event. May provide additional $query_params if desired
819
-     *
820
-     * @param array $query_params
821
-     * @return EE_Base_Class|EE_Venue|null
822
-     * @throws EE_Error
823
-     * @throws ReflectionException
824
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
825
-     */
826
-    public function venue(array $query_params = []): ?EE_Venue
827
-    {
828
-        return $this->get_first_related('Venue', $query_params);
829
-    }
830
-
831
-
832
-    /**
833
-     * @param array $query_params
834
-     * @return EE_Base_Class[]|EE_Venue[]
835
-     * @throws EE_Error
836
-     * @throws ReflectionException
837
-     * @deprecated $VID:$
838
-     */
839
-    public function venues(array $query_params = []): array
840
-    {
841
-        return [$this->venue($query_params)];
842
-    }
843
-
844
-
845
-    /**
846
-     * check if event id is present and if event is published
847
-     *
848
-     * @return boolean true yes, false no
849
-     * @throws EE_Error
850
-     * @throws ReflectionException
851
-     */
852
-    private function _has_ID_and_is_published(): bool
853
-    {
854
-        // first check if event id is present and not NULL,
855
-        // then check if this event is published (or any of the equivalent "published" statuses)
856
-        return
857
-            $this->ID() && $this->ID() !== null
858
-            && (
859
-                $this->status() === 'publish'
860
-                || $this->status() === EEM_Event::sold_out
861
-                || $this->status() === EEM_Event::postponed
862
-                || $this->status() === EEM_Event::cancelled
863
-            );
864
-    }
865
-
866
-
867
-    /**
868
-     * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
869
-     *
870
-     * @return boolean true yes, false no
871
-     * @throws EE_Error
872
-     * @throws ReflectionException
873
-     */
874
-    public function is_upcoming(): bool
875
-    {
876
-        // check if event id is present and if this event is published
877
-        if ($this->is_inactive()) {
878
-            return false;
879
-        }
880
-        // set initial value
881
-        $upcoming = false;
882
-        // next let's get all datetimes and loop through them
883
-        $datetimes = $this->datetimes_in_chronological_order();
884
-        foreach ($datetimes as $datetime) {
885
-            if ($datetime instanceof EE_Datetime) {
886
-                // if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
887
-                if ($datetime->is_expired()) {
888
-                    continue;
889
-                }
890
-                // if this dtt is active then we return false.
891
-                if ($datetime->is_active()) {
892
-                    return false;
893
-                }
894
-                // otherwise let's check upcoming status
895
-                $upcoming = $datetime->is_upcoming();
896
-            }
897
-        }
898
-        return $upcoming;
899
-    }
900
-
901
-
902
-    /**
903
-     * @return bool
904
-     * @throws EE_Error
905
-     * @throws ReflectionException
906
-     */
907
-    public function is_active(): bool
908
-    {
909
-        // check if event id is present and if this event is published
910
-        if ($this->is_inactive()) {
911
-            return false;
912
-        }
913
-        // set initial value
914
-        $active = false;
915
-        // next let's get all datetimes and loop through them
916
-        $datetimes = $this->datetimes_in_chronological_order();
917
-        foreach ($datetimes as $datetime) {
918
-            if ($datetime instanceof EE_Datetime) {
919
-                // if this dtt is expired then we continue cause one of the other datetimes might be active.
920
-                if ($datetime->is_expired()) {
921
-                    continue;
922
-                }
923
-                // if this dtt is upcoming then we return false.
924
-                if ($datetime->is_upcoming()) {
925
-                    return false;
926
-                }
927
-                // otherwise let's check active status
928
-                $active = $datetime->is_active();
929
-            }
930
-        }
931
-        return $active;
932
-    }
933
-
934
-
935
-    /**
936
-     * @return bool
937
-     * @throws EE_Error
938
-     * @throws ReflectionException
939
-     */
940
-    public function is_expired(): bool
941
-    {
942
-        // check if event id is present and if this event is published
943
-        if ($this->is_inactive()) {
944
-            return false;
945
-        }
946
-        // set initial value
947
-        $expired = false;
948
-        // first let's get all datetimes and loop through them
949
-        $datetimes = $this->datetimes_in_chronological_order();
950
-        foreach ($datetimes as $datetime) {
951
-            if ($datetime instanceof EE_Datetime) {
952
-                // if this dtt is upcoming or active then we return false.
953
-                if ($datetime->is_upcoming() || $datetime->is_active()) {
954
-                    return false;
955
-                }
956
-                // otherwise let's check active status
957
-                $expired = $datetime->is_expired();
958
-            }
959
-        }
960
-        return $expired;
961
-    }
962
-
963
-
964
-    /**
965
-     * @return bool
966
-     * @throws EE_Error
967
-     * @throws ReflectionException
968
-     */
969
-    public function is_inactive(): bool
970
-    {
971
-        // check if event id is present and if this event is published
972
-        if ($this->_has_ID_and_is_published()) {
973
-            return false;
974
-        }
975
-        return true;
976
-    }
977
-
978
-
979
-    /**
980
-     * calculate spaces remaining based on "saleable" tickets
981
-     *
982
-     * @param array|null $tickets
983
-     * @param bool       $filtered
984
-     * @return int|float
985
-     * @throws EE_Error
986
-     * @throws DomainException
987
-     * @throws UnexpectedEntityException
988
-     * @throws ReflectionException
989
-     */
990
-    public function spaces_remaining(?array $tickets = [], ?bool $filtered = true)
991
-    {
992
-        $this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
993
-        $spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
994
-        return $filtered
995
-            ? apply_filters(
996
-                'FHEE_EE_Event__spaces_remaining',
997
-                $spaces_remaining,
998
-                $this,
999
-                $tickets
1000
-            )
1001
-            : $spaces_remaining;
1002
-    }
1003
-
1004
-
1005
-    /**
1006
-     *    perform_sold_out_status_check
1007
-     *    checks all of this event's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
1008
-     *    available... if NOT, then the event status will get toggled to 'sold_out'
1009
-     *
1010
-     * @return bool    return the ACTUAL sold out state.
1011
-     * @throws EE_Error
1012
-     * @throws DomainException
1013
-     * @throws UnexpectedEntityException
1014
-     * @throws ReflectionException
1015
-     */
1016
-    public function perform_sold_out_status_check(): bool
1017
-    {
1018
-        // get all tickets
1019
-        $tickets     = $this->tickets(
1020
-            [
1021
-                'default_where_conditions' => 'none',
1022
-                'order_by'                 => ['TKT_qty' => 'ASC'],
1023
-            ]
1024
-        );
1025
-        $all_expired = true;
1026
-        foreach ($tickets as $ticket) {
1027
-            if (! $ticket->is_expired()) {
1028
-                $all_expired = false;
1029
-                break;
1030
-            }
1031
-        }
1032
-        // if all the tickets are just expired, then don't update the event status to sold out
1033
-        if ($all_expired) {
1034
-            return true;
1035
-        }
1036
-        $spaces_remaining = $this->spaces_remaining($tickets);
1037
-        if ($spaces_remaining < 1) {
1038
-            if ($this->status() !== EEM_CPT_Base::post_status_private) {
1039
-                $this->set_status(EEM_Event::sold_out);
1040
-                $this->save();
1041
-            }
1042
-            $sold_out = true;
1043
-        } else {
1044
-            $sold_out = false;
1045
-            // was event previously marked as sold out ?
1046
-            if ($this->status() === EEM_Event::sold_out) {
1047
-                // revert status to previous value, if it was set
1048
-                $previous_event_status = $this->get_post_meta('_previous_event_status', true);
1049
-                if ($previous_event_status) {
1050
-                    $this->set_status($previous_event_status);
1051
-                    $this->save();
1052
-                }
1053
-            }
1054
-        }
1055
-        do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
1056
-        return $sold_out;
1057
-    }
1058
-
1059
-
1060
-    /**
1061
-     * This returns the total remaining spaces for sale on this event.
1062
-     *
1063
-     * @return int|float
1064
-     * @throws EE_Error
1065
-     * @throws DomainException
1066
-     * @throws UnexpectedEntityException
1067
-     * @throws ReflectionException
1068
-     * @uses EE_Event::total_available_spaces()
1069
-     */
1070
-    public function spaces_remaining_for_sale()
1071
-    {
1072
-        return $this->total_available_spaces(true);
1073
-    }
1074
-
1075
-
1076
-    /**
1077
-     * This returns the total spaces available for an event
1078
-     * while considering all the quantities on the tickets and the reg limits
1079
-     * on the datetimes attached to this event.
1080
-     *
1081
-     * @param bool $consider_sold   Whether to consider any tickets that have already sold in our calculation.
1082
-     *                              If this is false, then we return the most tickets that could ever be sold
1083
-     *                              for this event with the datetime and tickets setup on the event under optimal
1084
-     *                              selling conditions.  Otherwise we return a live calculation of spaces available
1085
-     *                              based on tickets sold.  Depending on setup and stage of sales, this
1086
-     *                              may appear to equal remaining tickets.  However, the more tickets are
1087
-     *                              sold out, the more accurate the "live" total is.
1088
-     * @return int|float
1089
-     * @throws EE_Error
1090
-     * @throws DomainException
1091
-     * @throws UnexpectedEntityException
1092
-     * @throws ReflectionException
1093
-     */
1094
-    public function total_available_spaces(bool $consider_sold = false)
1095
-    {
1096
-        $spaces_available = $consider_sold
1097
-            ? $this->getAvailableSpacesCalculator()->spacesRemaining()
1098
-            : $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
1099
-        return apply_filters(
1100
-            'FHEE_EE_Event__total_available_spaces__spaces_available',
1101
-            $spaces_available,
1102
-            $this,
1103
-            $this->getAvailableSpacesCalculator()->getDatetimes(),
1104
-            $this->getAvailableSpacesCalculator()->getActiveTickets()
1105
-        );
1106
-    }
1107
-
1108
-
1109
-    /**
1110
-     * Checks if the event is set to sold out
1111
-     *
1112
-     * @param bool $actual  whether or not to perform calculations to not only figure the
1113
-     *                      actual status but also to flip the status if necessary to sold
1114
-     *                      out If false, we just check the existing status of the event
1115
-     * @return boolean
1116
-     * @throws EE_Error
1117
-     * @throws ReflectionException
1118
-     */
1119
-    public function is_sold_out(bool $actual = false): bool
1120
-    {
1121
-        if (! $actual) {
1122
-            return $this->status() === EEM_Event::sold_out;
1123
-        }
1124
-        return $this->perform_sold_out_status_check();
1125
-    }
1126
-
1127
-
1128
-    /**
1129
-     * Checks if the event is marked as postponed
1130
-     *
1131
-     * @return boolean
1132
-     */
1133
-    public function is_postponed(): bool
1134
-    {
1135
-        return $this->status() === EEM_Event::postponed;
1136
-    }
1137
-
1138
-
1139
-    /**
1140
-     * Checks if the event is marked as cancelled
1141
-     *
1142
-     * @return boolean
1143
-     */
1144
-    public function is_cancelled(): bool
1145
-    {
1146
-        return $this->status() === EEM_Event::cancelled;
1147
-    }
1148
-
1149
-
1150
-    /**
1151
-     * Get the logical active status in a hierarchical order for all the datetimes.  Note
1152
-     * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1153
-     * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1154
-     * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1155
-     * the event is considered expired.
1156
-     * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1157
-     * status set on the EVENT when it is not published and thus is done
1158
-     *
1159
-     * @param bool $reset
1160
-     * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1161
-     * @throws EE_Error
1162
-     * @throws ReflectionException
1163
-     */
1164
-    public function get_active_status(bool $reset = false)
1165
-    {
1166
-        // if the active status has already been set, then just use that value (unless we are resetting it)
1167
-        if (! empty($this->_active_status) && ! $reset) {
1168
-            return $this->_active_status;
1169
-        }
1170
-        // first check if event id is present on this object
1171
-        if (! $this->ID()) {
1172
-            return false;
1173
-        }
1174
-        $where_params_for_event = [['EVT_ID' => $this->ID()]];
1175
-        // if event is published:
1176
-        if (
1177
-            $this->status() === EEM_CPT_Base::post_status_publish
1178
-            || $this->status() === EEM_CPT_Base::post_status_private
1179
-        ) {
1180
-            // active?
1181
-            if (
1182
-                EEM_Datetime::instance()->get_datetime_count_for_status(
1183
-                    EE_Datetime::active,
1184
-                    $where_params_for_event
1185
-                ) > 0
1186
-            ) {
1187
-                $this->_active_status = EE_Datetime::active;
1188
-            } else {
1189
-                // upcoming?
1190
-                if (
1191
-                    EEM_Datetime::instance()->get_datetime_count_for_status(
1192
-                        EE_Datetime::upcoming,
1193
-                        $where_params_for_event
1194
-                    ) > 0
1195
-                ) {
1196
-                    $this->_active_status = EE_Datetime::upcoming;
1197
-                } else {
1198
-                    // expired?
1199
-                    if (
1200
-                        EEM_Datetime::instance()->get_datetime_count_for_status(
1201
-                            EE_Datetime::expired,
1202
-                            $where_params_for_event
1203
-                        ) > 0
1204
-                    ) {
1205
-                        $this->_active_status = EE_Datetime::expired;
1206
-                    } else {
1207
-                        // it would be odd if things make it this far
1208
-                        // because it basically means there are no datetimes attached to the event.
1209
-                        // So in this case it will just be considered inactive.
1210
-                        $this->_active_status = EE_Datetime::inactive;
1211
-                    }
1212
-                }
1213
-            }
1214
-        } else {
1215
-            // the event is not published, so let's just set it's active status according to its' post status
1216
-            switch ($this->status()) {
1217
-                case EEM_Event::sold_out:
1218
-                    $this->_active_status = EE_Datetime::sold_out;
1219
-                    break;
1220
-                case EEM_Event::cancelled:
1221
-                    $this->_active_status = EE_Datetime::cancelled;
1222
-                    break;
1223
-                case EEM_Event::postponed:
1224
-                    $this->_active_status = EE_Datetime::postponed;
1225
-                    break;
1226
-                default:
1227
-                    $this->_active_status = EE_Datetime::inactive;
1228
-            }
1229
-        }
1230
-        return $this->_active_status;
1231
-    }
1232
-
1233
-
1234
-    /**
1235
-     *    pretty_active_status
1236
-     *
1237
-     * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1238
-     * @return string
1239
-     * @throws EE_Error
1240
-     * @throws ReflectionException
1241
-     */
1242
-    public function pretty_active_status(bool $echo = true): string
1243
-    {
1244
-        $active_status = $this->get_active_status();
1245
-        $status        = "
19
+	/**
20
+	 * cached value for the the logical active status for the event
21
+	 *
22
+	 * @see get_active_status()
23
+	 * @var string
24
+	 */
25
+	protected $_active_status = '';
26
+
27
+	/**
28
+	 * This is just used for caching the Primary Datetime for the Event on initial retrieval
29
+	 *
30
+	 * @var EE_Datetime
31
+	 */
32
+	protected $_Primary_Datetime;
33
+
34
+	/**
35
+	 * @var EventSpacesCalculator $available_spaces_calculator
36
+	 */
37
+	protected $available_spaces_calculator;
38
+
39
+
40
+	/**
41
+	 * @param array  $props_n_values          incoming values
42
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
43
+	 *                                        used.)
44
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
45
+	 *                                        date_format and the second value is the time format
46
+	 * @return EE_Event
47
+	 * @throws EE_Error
48
+	 * @throws ReflectionException
49
+	 */
50
+	public static function new_instance($props_n_values = [], $timezone = null, $date_formats = []): EE_Event
51
+	{
52
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
53
+		return $has_object ?: new self($props_n_values, false, $timezone, $date_formats);
54
+	}
55
+
56
+
57
+	/**
58
+	 * @param array  $props_n_values  incoming values from the database
59
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
60
+	 *                                the website will be used.
61
+	 * @return EE_Event
62
+	 * @throws EE_Error
63
+	 * @throws ReflectionException
64
+	 */
65
+	public static function new_instance_from_db($props_n_values = [], $timezone = null): EE_Event
66
+	{
67
+		return new self($props_n_values, true, $timezone);
68
+	}
69
+
70
+
71
+	/**
72
+	 * @return EventSpacesCalculator
73
+	 * @throws EE_Error
74
+	 * @throws ReflectionException
75
+	 */
76
+	public function getAvailableSpacesCalculator(): EventSpacesCalculator
77
+	{
78
+		if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
79
+			$this->available_spaces_calculator = new EventSpacesCalculator($this);
80
+		}
81
+		return $this->available_spaces_calculator;
82
+	}
83
+
84
+
85
+	/**
86
+	 * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
87
+	 *
88
+	 * @param string $field_name
89
+	 * @param mixed  $field_value
90
+	 * @param bool   $use_default
91
+	 * @throws EE_Error
92
+	 * @throws ReflectionException
93
+	 */
94
+	public function set($field_name, $field_value, $use_default = false)
95
+	{
96
+		switch ($field_name) {
97
+			case 'status':
98
+				$this->set_status($field_value, $use_default);
99
+				break;
100
+			default:
101
+				parent::set($field_name, $field_value, $use_default);
102
+		}
103
+	}
104
+
105
+
106
+	/**
107
+	 *    set_status
108
+	 * Checks if event status is being changed to SOLD OUT
109
+	 * and updates event meta data with previous event status
110
+	 * so that we can revert things if/when the event is no longer sold out
111
+	 *
112
+	 * @param string $status
113
+	 * @param bool   $use_default
114
+	 * @return void
115
+	 * @throws EE_Error
116
+	 * @throws ReflectionException
117
+	 */
118
+	public function set_status($status = '', $use_default = false)
119
+	{
120
+		// if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
121
+		if (empty($status) && ! $use_default) {
122
+			return;
123
+		}
124
+		// get current Event status
125
+		$old_status = $this->status();
126
+		// if status has changed
127
+		if ($old_status !== $status) {
128
+			// TO sold_out
129
+			if ($status === EEM_Event::sold_out) {
130
+				// save the previous event status so that we can revert if the event is no longer sold out
131
+				$this->add_post_meta('_previous_event_status', $old_status);
132
+				do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $status);
133
+				// OR FROM  sold_out
134
+			} elseif ($old_status === EEM_Event::sold_out) {
135
+				$this->delete_post_meta('_previous_event_status');
136
+				do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $status);
137
+			}
138
+			// clear out the active status so that it gets reset the next time it is requested
139
+			$this->_active_status = null;
140
+			// update status
141
+			parent::set('status', $status, $use_default);
142
+			do_action('AHEE__EE_Event__set_status__after_update', $this);
143
+			return;
144
+		}
145
+		// even though the old value matches the new value, it's still good to
146
+		// allow the parent set method to have a say
147
+		parent::set('status', $status, $use_default);
148
+	}
149
+
150
+
151
+	/**
152
+	 * Gets all the datetimes for this event
153
+	 *
154
+	 * @param array|null $query_params
155
+	 * @return EE_Base_Class[]|EE_Datetime[]
156
+	 * @throws EE_Error
157
+	 * @throws ReflectionException
158
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
159
+	 */
160
+	public function datetimes(?array $query_params = []): array
161
+	{
162
+		return $this->get_many_related('Datetime', $query_params);
163
+	}
164
+
165
+
166
+	/**
167
+	 * Gets all the datetimes for this event that are currently ACTIVE,
168
+	 * meaning the datetime has started and has not yet ended.
169
+	 *
170
+	 * @param int|null   $start_date   timestamp to use for event date start time, defaults to NOW unless set to 0
171
+	 * @param array|null $query_params will recursively replace default values
172
+	 * @throws EE_Error
173
+	 * @throws ReflectionException
174
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
175
+	 */
176
+	public function activeDatetimes(?int $start_date, ?array $query_params = []): array
177
+	{
178
+		// if start date is null, then use current time
179
+		$start_date = $start_date ?? time();
180
+		$where      = [];
181
+		if ($start_date) {
182
+			$where['DTT_EVT_start'] = ['<', $start_date];
183
+			$where['DTT_EVT_end']   = ['>', time()];
184
+		}
185
+		$query_params = array_replace_recursive(
186
+			[
187
+				$where,
188
+				'order_by' => ['DTT_EVT_start' => 'ASC'],
189
+			],
190
+			$query_params
191
+		);
192
+		return $this->get_many_related('Datetime', $query_params);
193
+	}
194
+
195
+
196
+	/**
197
+	 * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
198
+	 *
199
+	 * @return EE_Base_Class[]|EE_Datetime[]
200
+	 * @throws EE_Error
201
+	 * @throws ReflectionException
202
+	 */
203
+	public function datetimes_in_chronological_order(): array
204
+	{
205
+		return $this->get_many_related('Datetime', ['order_by' => ['DTT_EVT_start' => 'ASC']]);
206
+	}
207
+
208
+
209
+	/**
210
+	 * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
211
+	 * @darren, we should probably UNSET timezone on the EEM_Datetime model
212
+	 * after running our query, so that this timezone isn't set for EVERY query
213
+	 * on EEM_Datetime for the rest of the request, no?
214
+	 *
215
+	 * @param bool     $show_expired whether or not to include expired events
216
+	 * @param bool     $show_deleted whether or not to include deleted events
217
+	 * @param int|null $limit
218
+	 * @return EE_Datetime[]
219
+	 * @throws EE_Error
220
+	 * @throws ReflectionException
221
+	 */
222
+	public function datetimes_ordered(bool $show_expired = true, bool $show_deleted = false, ?int $limit = null): array
223
+	{
224
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
225
+			$this->ID(),
226
+			$show_expired,
227
+			$show_deleted,
228
+			$limit
229
+		);
230
+	}
231
+
232
+
233
+	/**
234
+	 * Returns one related datetime. Mostly only used by some legacy code.
235
+	 *
236
+	 * @return EE_Base_Class|EE_Datetime
237
+	 * @throws EE_Error
238
+	 * @throws ReflectionException
239
+	 */
240
+	public function first_datetime(): EE_Datetime
241
+	{
242
+		return $this->get_first_related('Datetime');
243
+	}
244
+
245
+
246
+	/**
247
+	 * Returns the 'primary' datetime for the event
248
+	 *
249
+	 * @param bool $try_to_exclude_expired
250
+	 * @param bool $try_to_exclude_deleted
251
+	 * @return EE_Datetime|null
252
+	 * @throws EE_Error
253
+	 * @throws ReflectionException
254
+	 */
255
+	public function primary_datetime(
256
+		bool $try_to_exclude_expired = true,
257
+		bool $try_to_exclude_deleted = true
258
+	): ?EE_Datetime {
259
+		if (! empty($this->_Primary_Datetime)) {
260
+			return $this->_Primary_Datetime;
261
+		}
262
+		$this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
263
+			$this->ID(),
264
+			$try_to_exclude_expired,
265
+			$try_to_exclude_deleted
266
+		);
267
+		return $this->_Primary_Datetime;
268
+	}
269
+
270
+
271
+	/**
272
+	 * Gets all the tickets available for purchase of this event
273
+	 *
274
+	 * @param array|null $query_params
275
+	 * @return EE_Base_Class[]|EE_Ticket[]
276
+	 * @throws EE_Error
277
+	 * @throws ReflectionException
278
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
279
+	 */
280
+	public function tickets(?array $query_params = []): array
281
+	{
282
+		// first get all datetimes
283
+		$datetimes = $this->datetimes_ordered();
284
+		if (! $datetimes) {
285
+			return [];
286
+		}
287
+		$datetime_ids = [];
288
+		foreach ($datetimes as $datetime) {
289
+			$datetime_ids[] = $datetime->ID();
290
+		}
291
+		$where_params = ['Datetime.DTT_ID' => ['IN', $datetime_ids]];
292
+		// if incoming $query_params has where conditions let's merge but not override existing.
293
+		if (is_array($query_params) && isset($query_params[0])) {
294
+			$where_params = array_merge($query_params[0], $where_params);
295
+			unset($query_params[0]);
296
+		}
297
+		// now add $where_params to $query_params
298
+		$query_params[0] = $where_params;
299
+		return EEM_Ticket::instance()->get_all($query_params);
300
+	}
301
+
302
+
303
+	/**
304
+	 * get all unexpired not-trashed tickets
305
+	 *
306
+	 * @return EE_Ticket[]
307
+	 * @throws EE_Error
308
+	 * @throws ReflectionException
309
+	 */
310
+	public function active_tickets(): array
311
+	{
312
+		return $this->tickets(
313
+			[
314
+				[
315
+					'TKT_end_date' => ['>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')],
316
+					'TKT_deleted'  => false,
317
+				],
318
+			]
319
+		);
320
+	}
321
+
322
+
323
+	/**
324
+	 * @return int
325
+	 * @throws EE_Error
326
+	 * @throws ReflectionException
327
+	 */
328
+	public function additional_limit(): int
329
+	{
330
+		return $this->get('EVT_additional_limit');
331
+	}
332
+
333
+
334
+	/**
335
+	 * @return bool
336
+	 * @throws EE_Error
337
+	 * @throws ReflectionException
338
+	 */
339
+	public function allow_overflow(): bool
340
+	{
341
+		return $this->get('EVT_allow_overflow');
342
+	}
343
+
344
+
345
+	/**
346
+	 * @return string
347
+	 * @throws EE_Error
348
+	 * @throws ReflectionException
349
+	 */
350
+	public function created(): string
351
+	{
352
+		return $this->get('EVT_created');
353
+	}
354
+
355
+
356
+	/**
357
+	 * @return string
358
+	 * @throws EE_Error
359
+	 * @throws ReflectionException
360
+	 */
361
+	public function description(): string
362
+	{
363
+		return $this->get('EVT_desc');
364
+	}
365
+
366
+
367
+	/**
368
+	 * Runs do_shortcode and wpautop on the description
369
+	 *
370
+	 * @return string of html
371
+	 * @throws EE_Error
372
+	 * @throws ReflectionException
373
+	 */
374
+	public function description_filtered(): string
375
+	{
376
+		return $this->get_pretty('EVT_desc');
377
+	}
378
+
379
+
380
+	/**
381
+	 * @return bool
382
+	 * @throws EE_Error
383
+	 * @throws ReflectionException
384
+	 */
385
+	public function display_description(): bool
386
+	{
387
+		return $this->get('EVT_display_desc');
388
+	}
389
+
390
+
391
+	/**
392
+	 * @return bool
393
+	 * @throws EE_Error
394
+	 * @throws ReflectionException
395
+	 */
396
+	public function display_ticket_selector(): bool
397
+	{
398
+		return (bool) $this->get('EVT_display_ticket_selector');
399
+	}
400
+
401
+
402
+	/**
403
+	 * @return string
404
+	 * @throws EE_Error
405
+	 * @throws ReflectionException
406
+	 */
407
+	public function external_url(): ?string
408
+	{
409
+		return $this->get('EVT_external_URL') ?? '';
410
+	}
411
+
412
+
413
+	/**
414
+	 * @return bool
415
+	 * @throws EE_Error
416
+	 * @throws ReflectionException
417
+	 */
418
+	public function member_only(): bool
419
+	{
420
+		return $this->get('EVT_member_only');
421
+	}
422
+
423
+
424
+	/**
425
+	 * @return string
426
+	 * @throws EE_Error
427
+	 * @throws ReflectionException
428
+	 */
429
+	public function phone(): string
430
+	{
431
+		return $this->get('EVT_phone');
432
+	}
433
+
434
+
435
+	/**
436
+	 * @return string
437
+	 * @throws EE_Error
438
+	 * @throws ReflectionException
439
+	 */
440
+	public function modified(): string
441
+	{
442
+		return $this->get('EVT_modified');
443
+	}
444
+
445
+
446
+	/**
447
+	 * @return string
448
+	 * @throws EE_Error
449
+	 * @throws ReflectionException
450
+	 */
451
+	public function name(): string
452
+	{
453
+		return $this->get('EVT_name');
454
+	}
455
+
456
+
457
+	/**
458
+	 * @return int
459
+	 * @throws EE_Error
460
+	 * @throws ReflectionException
461
+	 */
462
+	public function order(): int
463
+	{
464
+		return $this->get('EVT_order');
465
+	}
466
+
467
+
468
+	/**
469
+	 * @return string
470
+	 * @throws EE_Error
471
+	 * @throws ReflectionException
472
+	 */
473
+	public function default_registration_status(): string
474
+	{
475
+		$event_default_registration_status = $this->get('EVT_default_registration_status');
476
+		return ! empty($event_default_registration_status)
477
+			? $event_default_registration_status
478
+			: EE_Registry::instance()->CFG->registration->default_STS_ID;
479
+	}
480
+
481
+
482
+	/**
483
+	 * @param int|null    $num_words
484
+	 * @param string|null $more
485
+	 * @param bool        $not_full_desc
486
+	 * @return string
487
+	 * @throws EE_Error
488
+	 * @throws ReflectionException
489
+	 */
490
+	public function short_description(?int $num_words = 55, string $more = null, bool $not_full_desc = false): string
491
+	{
492
+		$short_desc = $this->get('EVT_short_desc');
493
+		if (! empty($short_desc) || $not_full_desc) {
494
+			return $short_desc;
495
+		}
496
+		$full_desc = $this->get('EVT_desc');
497
+		return wp_trim_words($full_desc, $num_words, $more);
498
+	}
499
+
500
+
501
+	/**
502
+	 * @return string
503
+	 * @throws EE_Error
504
+	 * @throws ReflectionException
505
+	 */
506
+	public function slug(): string
507
+	{
508
+		return $this->get('EVT_slug');
509
+	}
510
+
511
+
512
+	/**
513
+	 * @return string
514
+	 * @throws EE_Error
515
+	 * @throws ReflectionException
516
+	 */
517
+	public function timezone_string(): string
518
+	{
519
+		return $this->get('EVT_timezone_string');
520
+	}
521
+
522
+
523
+	/**
524
+	 * @return string
525
+	 * @throws EE_Error
526
+	 * @throws ReflectionException
527
+	 * @deprecated
528
+	 */
529
+	public function visible_on(): string
530
+	{
531
+		EE_Error::doing_it_wrong(
532
+			__METHOD__,
533
+			esc_html__(
534
+				'This method has been deprecated and there is no replacement for it.',
535
+				'event_espresso'
536
+			),
537
+			'5.0.0.rc.002'
538
+		);
539
+		return $this->get('EVT_visible_on');
540
+	}
541
+
542
+
543
+	/**
544
+	 * @return int
545
+	 * @throws EE_Error
546
+	 * @throws ReflectionException
547
+	 */
548
+	public function wp_user(): int
549
+	{
550
+		return $this->get('EVT_wp_user');
551
+	}
552
+
553
+
554
+	/**
555
+	 * @return bool
556
+	 * @throws EE_Error
557
+	 * @throws ReflectionException
558
+	 */
559
+	public function donations(): bool
560
+	{
561
+		return $this->get('EVT_donations');
562
+	}
563
+
564
+
565
+	/**
566
+	 * @param int $limit
567
+	 * @throws EE_Error
568
+	 * @throws ReflectionException
569
+	 */
570
+	public function set_additional_limit(int $limit)
571
+	{
572
+		$this->set('EVT_additional_limit', $limit);
573
+	}
574
+
575
+
576
+	/**
577
+	 * @param $created
578
+	 * @throws EE_Error
579
+	 * @throws ReflectionException
580
+	 */
581
+	public function set_created($created)
582
+	{
583
+		$this->set('EVT_created', $created);
584
+	}
585
+
586
+
587
+	/**
588
+	 * @param $desc
589
+	 * @throws EE_Error
590
+	 * @throws ReflectionException
591
+	 */
592
+	public function set_description($desc)
593
+	{
594
+		$this->set('EVT_desc', $desc);
595
+	}
596
+
597
+
598
+	/**
599
+	 * @param $display_desc
600
+	 * @throws EE_Error
601
+	 * @throws ReflectionException
602
+	 */
603
+	public function set_display_description($display_desc)
604
+	{
605
+		$this->set('EVT_display_desc', $display_desc);
606
+	}
607
+
608
+
609
+	/**
610
+	 * @param $display_ticket_selector
611
+	 * @throws EE_Error
612
+	 * @throws ReflectionException
613
+	 */
614
+	public function set_display_ticket_selector($display_ticket_selector)
615
+	{
616
+		$this->set('EVT_display_ticket_selector', $display_ticket_selector);
617
+	}
618
+
619
+
620
+	/**
621
+	 * @param $external_url
622
+	 * @throws EE_Error
623
+	 * @throws ReflectionException
624
+	 */
625
+	public function set_external_url($external_url)
626
+	{
627
+		$this->set('EVT_external_URL', $external_url);
628
+	}
629
+
630
+
631
+	/**
632
+	 * @param $member_only
633
+	 * @throws EE_Error
634
+	 * @throws ReflectionException
635
+	 */
636
+	public function set_member_only($member_only)
637
+	{
638
+		$this->set('EVT_member_only', $member_only);
639
+	}
640
+
641
+
642
+	/**
643
+	 * @param $event_phone
644
+	 * @throws EE_Error
645
+	 * @throws ReflectionException
646
+	 */
647
+	public function set_event_phone($event_phone)
648
+	{
649
+		$this->set('EVT_phone', $event_phone);
650
+	}
651
+
652
+
653
+	/**
654
+	 * @param $modified
655
+	 * @throws EE_Error
656
+	 * @throws ReflectionException
657
+	 */
658
+	public function set_modified($modified)
659
+	{
660
+		$this->set('EVT_modified', $modified);
661
+	}
662
+
663
+
664
+	/**
665
+	 * @param $name
666
+	 * @throws EE_Error
667
+	 * @throws ReflectionException
668
+	 */
669
+	public function set_name($name)
670
+	{
671
+		$this->set('EVT_name', $name);
672
+	}
673
+
674
+
675
+	/**
676
+	 * @param $order
677
+	 * @throws EE_Error
678
+	 * @throws ReflectionException
679
+	 */
680
+	public function set_order($order)
681
+	{
682
+		$this->set('EVT_order', $order);
683
+	}
684
+
685
+
686
+	/**
687
+	 * @param $short_desc
688
+	 * @throws EE_Error
689
+	 * @throws ReflectionException
690
+	 */
691
+	public function set_short_description($short_desc)
692
+	{
693
+		$this->set('EVT_short_desc', $short_desc);
694
+	}
695
+
696
+
697
+	/**
698
+	 * @param $slug
699
+	 * @throws EE_Error
700
+	 * @throws ReflectionException
701
+	 */
702
+	public function set_slug($slug)
703
+	{
704
+		$this->set('EVT_slug', $slug);
705
+	}
706
+
707
+
708
+	/**
709
+	 * @param $timezone_string
710
+	 * @throws EE_Error
711
+	 * @throws ReflectionException
712
+	 */
713
+	public function set_timezone_string($timezone_string)
714
+	{
715
+		$this->set('EVT_timezone_string', $timezone_string);
716
+	}
717
+
718
+
719
+	/**
720
+	 * @param $visible_on
721
+	 * @throws EE_Error
722
+	 * @throws ReflectionException
723
+	 * @deprecated
724
+	 */
725
+	public function set_visible_on($visible_on)
726
+	{
727
+		EE_Error::doing_it_wrong(
728
+			__METHOD__,
729
+			esc_html__(
730
+				'This method has been deprecated and there is no replacement for it.',
731
+				'event_espresso'
732
+			),
733
+			'5.0.0.rc.002'
734
+		);
735
+		$this->set('EVT_visible_on', $visible_on);
736
+	}
737
+
738
+
739
+	/**
740
+	 * @param $wp_user
741
+	 * @throws EE_Error
742
+	 * @throws ReflectionException
743
+	 */
744
+	public function set_wp_user($wp_user)
745
+	{
746
+		$this->set('EVT_wp_user', $wp_user);
747
+	}
748
+
749
+
750
+	/**
751
+	 * @param $default_registration_status
752
+	 * @throws EE_Error
753
+	 * @throws ReflectionException
754
+	 */
755
+	public function set_default_registration_status($default_registration_status)
756
+	{
757
+		$this->set('EVT_default_registration_status', $default_registration_status);
758
+	}
759
+
760
+
761
+	/**
762
+	 * @param $donations
763
+	 * @throws EE_Error
764
+	 * @throws ReflectionException
765
+	 */
766
+	public function set_donations($donations)
767
+	{
768
+		$this->set('EVT_donations', $donations);
769
+	}
770
+
771
+
772
+	/**
773
+	 * Adds a venue to this event
774
+	 *
775
+	 * @param int|EE_Venue /int $venue_id_or_obj
776
+	 * @return EE_Base_Class|EE_Venue
777
+	 * @throws EE_Error
778
+	 * @throws ReflectionException
779
+	 */
780
+	public function add_venue($venue_id_or_obj): EE_Venue
781
+	{
782
+		return $this->_add_relation_to($venue_id_or_obj, 'Venue');
783
+	}
784
+
785
+
786
+	/**
787
+	 * Removes a venue from the event
788
+	 *
789
+	 * @param EE_Venue /int $venue_id_or_obj
790
+	 * @return EE_Base_Class|EE_Venue
791
+	 * @throws EE_Error
792
+	 * @throws ReflectionException
793
+	 */
794
+	public function remove_venue($venue_id_or_obj): EE_Venue
795
+	{
796
+		$venue_id_or_obj = ! empty($venue_id_or_obj) ? $venue_id_or_obj : $this->venue();
797
+		return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
798
+	}
799
+
800
+
801
+	/**
802
+	 * Gets the venue related to the event. May provide additional $query_params if desired
803
+	 *
804
+	 * @param array $query_params
805
+	 * @return int
806
+	 * @throws EE_Error
807
+	 * @throws ReflectionException
808
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
809
+	 */
810
+	public function venue_ID(array $query_params = []): int
811
+	{
812
+		$venue = $this->get_first_related('Venue', $query_params);
813
+		return $venue instanceof EE_Venue ? $venue->ID() : 0;
814
+	}
815
+
816
+
817
+	/**
818
+	 * Gets the venue related to the event. May provide additional $query_params if desired
819
+	 *
820
+	 * @param array $query_params
821
+	 * @return EE_Base_Class|EE_Venue|null
822
+	 * @throws EE_Error
823
+	 * @throws ReflectionException
824
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
825
+	 */
826
+	public function venue(array $query_params = []): ?EE_Venue
827
+	{
828
+		return $this->get_first_related('Venue', $query_params);
829
+	}
830
+
831
+
832
+	/**
833
+	 * @param array $query_params
834
+	 * @return EE_Base_Class[]|EE_Venue[]
835
+	 * @throws EE_Error
836
+	 * @throws ReflectionException
837
+	 * @deprecated $VID:$
838
+	 */
839
+	public function venues(array $query_params = []): array
840
+	{
841
+		return [$this->venue($query_params)];
842
+	}
843
+
844
+
845
+	/**
846
+	 * check if event id is present and if event is published
847
+	 *
848
+	 * @return boolean true yes, false no
849
+	 * @throws EE_Error
850
+	 * @throws ReflectionException
851
+	 */
852
+	private function _has_ID_and_is_published(): bool
853
+	{
854
+		// first check if event id is present and not NULL,
855
+		// then check if this event is published (or any of the equivalent "published" statuses)
856
+		return
857
+			$this->ID() && $this->ID() !== null
858
+			&& (
859
+				$this->status() === 'publish'
860
+				|| $this->status() === EEM_Event::sold_out
861
+				|| $this->status() === EEM_Event::postponed
862
+				|| $this->status() === EEM_Event::cancelled
863
+			);
864
+	}
865
+
866
+
867
+	/**
868
+	 * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
869
+	 *
870
+	 * @return boolean true yes, false no
871
+	 * @throws EE_Error
872
+	 * @throws ReflectionException
873
+	 */
874
+	public function is_upcoming(): bool
875
+	{
876
+		// check if event id is present and if this event is published
877
+		if ($this->is_inactive()) {
878
+			return false;
879
+		}
880
+		// set initial value
881
+		$upcoming = false;
882
+		// next let's get all datetimes and loop through them
883
+		$datetimes = $this->datetimes_in_chronological_order();
884
+		foreach ($datetimes as $datetime) {
885
+			if ($datetime instanceof EE_Datetime) {
886
+				// if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
887
+				if ($datetime->is_expired()) {
888
+					continue;
889
+				}
890
+				// if this dtt is active then we return false.
891
+				if ($datetime->is_active()) {
892
+					return false;
893
+				}
894
+				// otherwise let's check upcoming status
895
+				$upcoming = $datetime->is_upcoming();
896
+			}
897
+		}
898
+		return $upcoming;
899
+	}
900
+
901
+
902
+	/**
903
+	 * @return bool
904
+	 * @throws EE_Error
905
+	 * @throws ReflectionException
906
+	 */
907
+	public function is_active(): bool
908
+	{
909
+		// check if event id is present and if this event is published
910
+		if ($this->is_inactive()) {
911
+			return false;
912
+		}
913
+		// set initial value
914
+		$active = false;
915
+		// next let's get all datetimes and loop through them
916
+		$datetimes = $this->datetimes_in_chronological_order();
917
+		foreach ($datetimes as $datetime) {
918
+			if ($datetime instanceof EE_Datetime) {
919
+				// if this dtt is expired then we continue cause one of the other datetimes might be active.
920
+				if ($datetime->is_expired()) {
921
+					continue;
922
+				}
923
+				// if this dtt is upcoming then we return false.
924
+				if ($datetime->is_upcoming()) {
925
+					return false;
926
+				}
927
+				// otherwise let's check active status
928
+				$active = $datetime->is_active();
929
+			}
930
+		}
931
+		return $active;
932
+	}
933
+
934
+
935
+	/**
936
+	 * @return bool
937
+	 * @throws EE_Error
938
+	 * @throws ReflectionException
939
+	 */
940
+	public function is_expired(): bool
941
+	{
942
+		// check if event id is present and if this event is published
943
+		if ($this->is_inactive()) {
944
+			return false;
945
+		}
946
+		// set initial value
947
+		$expired = false;
948
+		// first let's get all datetimes and loop through them
949
+		$datetimes = $this->datetimes_in_chronological_order();
950
+		foreach ($datetimes as $datetime) {
951
+			if ($datetime instanceof EE_Datetime) {
952
+				// if this dtt is upcoming or active then we return false.
953
+				if ($datetime->is_upcoming() || $datetime->is_active()) {
954
+					return false;
955
+				}
956
+				// otherwise let's check active status
957
+				$expired = $datetime->is_expired();
958
+			}
959
+		}
960
+		return $expired;
961
+	}
962
+
963
+
964
+	/**
965
+	 * @return bool
966
+	 * @throws EE_Error
967
+	 * @throws ReflectionException
968
+	 */
969
+	public function is_inactive(): bool
970
+	{
971
+		// check if event id is present and if this event is published
972
+		if ($this->_has_ID_and_is_published()) {
973
+			return false;
974
+		}
975
+		return true;
976
+	}
977
+
978
+
979
+	/**
980
+	 * calculate spaces remaining based on "saleable" tickets
981
+	 *
982
+	 * @param array|null $tickets
983
+	 * @param bool       $filtered
984
+	 * @return int|float
985
+	 * @throws EE_Error
986
+	 * @throws DomainException
987
+	 * @throws UnexpectedEntityException
988
+	 * @throws ReflectionException
989
+	 */
990
+	public function spaces_remaining(?array $tickets = [], ?bool $filtered = true)
991
+	{
992
+		$this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
993
+		$spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
994
+		return $filtered
995
+			? apply_filters(
996
+				'FHEE_EE_Event__spaces_remaining',
997
+				$spaces_remaining,
998
+				$this,
999
+				$tickets
1000
+			)
1001
+			: $spaces_remaining;
1002
+	}
1003
+
1004
+
1005
+	/**
1006
+	 *    perform_sold_out_status_check
1007
+	 *    checks all of this event's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
1008
+	 *    available... if NOT, then the event status will get toggled to 'sold_out'
1009
+	 *
1010
+	 * @return bool    return the ACTUAL sold out state.
1011
+	 * @throws EE_Error
1012
+	 * @throws DomainException
1013
+	 * @throws UnexpectedEntityException
1014
+	 * @throws ReflectionException
1015
+	 */
1016
+	public function perform_sold_out_status_check(): bool
1017
+	{
1018
+		// get all tickets
1019
+		$tickets     = $this->tickets(
1020
+			[
1021
+				'default_where_conditions' => 'none',
1022
+				'order_by'                 => ['TKT_qty' => 'ASC'],
1023
+			]
1024
+		);
1025
+		$all_expired = true;
1026
+		foreach ($tickets as $ticket) {
1027
+			if (! $ticket->is_expired()) {
1028
+				$all_expired = false;
1029
+				break;
1030
+			}
1031
+		}
1032
+		// if all the tickets are just expired, then don't update the event status to sold out
1033
+		if ($all_expired) {
1034
+			return true;
1035
+		}
1036
+		$spaces_remaining = $this->spaces_remaining($tickets);
1037
+		if ($spaces_remaining < 1) {
1038
+			if ($this->status() !== EEM_CPT_Base::post_status_private) {
1039
+				$this->set_status(EEM_Event::sold_out);
1040
+				$this->save();
1041
+			}
1042
+			$sold_out = true;
1043
+		} else {
1044
+			$sold_out = false;
1045
+			// was event previously marked as sold out ?
1046
+			if ($this->status() === EEM_Event::sold_out) {
1047
+				// revert status to previous value, if it was set
1048
+				$previous_event_status = $this->get_post_meta('_previous_event_status', true);
1049
+				if ($previous_event_status) {
1050
+					$this->set_status($previous_event_status);
1051
+					$this->save();
1052
+				}
1053
+			}
1054
+		}
1055
+		do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
1056
+		return $sold_out;
1057
+	}
1058
+
1059
+
1060
+	/**
1061
+	 * This returns the total remaining spaces for sale on this event.
1062
+	 *
1063
+	 * @return int|float
1064
+	 * @throws EE_Error
1065
+	 * @throws DomainException
1066
+	 * @throws UnexpectedEntityException
1067
+	 * @throws ReflectionException
1068
+	 * @uses EE_Event::total_available_spaces()
1069
+	 */
1070
+	public function spaces_remaining_for_sale()
1071
+	{
1072
+		return $this->total_available_spaces(true);
1073
+	}
1074
+
1075
+
1076
+	/**
1077
+	 * This returns the total spaces available for an event
1078
+	 * while considering all the quantities on the tickets and the reg limits
1079
+	 * on the datetimes attached to this event.
1080
+	 *
1081
+	 * @param bool $consider_sold   Whether to consider any tickets that have already sold in our calculation.
1082
+	 *                              If this is false, then we return the most tickets that could ever be sold
1083
+	 *                              for this event with the datetime and tickets setup on the event under optimal
1084
+	 *                              selling conditions.  Otherwise we return a live calculation of spaces available
1085
+	 *                              based on tickets sold.  Depending on setup and stage of sales, this
1086
+	 *                              may appear to equal remaining tickets.  However, the more tickets are
1087
+	 *                              sold out, the more accurate the "live" total is.
1088
+	 * @return int|float
1089
+	 * @throws EE_Error
1090
+	 * @throws DomainException
1091
+	 * @throws UnexpectedEntityException
1092
+	 * @throws ReflectionException
1093
+	 */
1094
+	public function total_available_spaces(bool $consider_sold = false)
1095
+	{
1096
+		$spaces_available = $consider_sold
1097
+			? $this->getAvailableSpacesCalculator()->spacesRemaining()
1098
+			: $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
1099
+		return apply_filters(
1100
+			'FHEE_EE_Event__total_available_spaces__spaces_available',
1101
+			$spaces_available,
1102
+			$this,
1103
+			$this->getAvailableSpacesCalculator()->getDatetimes(),
1104
+			$this->getAvailableSpacesCalculator()->getActiveTickets()
1105
+		);
1106
+	}
1107
+
1108
+
1109
+	/**
1110
+	 * Checks if the event is set to sold out
1111
+	 *
1112
+	 * @param bool $actual  whether or not to perform calculations to not only figure the
1113
+	 *                      actual status but also to flip the status if necessary to sold
1114
+	 *                      out If false, we just check the existing status of the event
1115
+	 * @return boolean
1116
+	 * @throws EE_Error
1117
+	 * @throws ReflectionException
1118
+	 */
1119
+	public function is_sold_out(bool $actual = false): bool
1120
+	{
1121
+		if (! $actual) {
1122
+			return $this->status() === EEM_Event::sold_out;
1123
+		}
1124
+		return $this->perform_sold_out_status_check();
1125
+	}
1126
+
1127
+
1128
+	/**
1129
+	 * Checks if the event is marked as postponed
1130
+	 *
1131
+	 * @return boolean
1132
+	 */
1133
+	public function is_postponed(): bool
1134
+	{
1135
+		return $this->status() === EEM_Event::postponed;
1136
+	}
1137
+
1138
+
1139
+	/**
1140
+	 * Checks if the event is marked as cancelled
1141
+	 *
1142
+	 * @return boolean
1143
+	 */
1144
+	public function is_cancelled(): bool
1145
+	{
1146
+		return $this->status() === EEM_Event::cancelled;
1147
+	}
1148
+
1149
+
1150
+	/**
1151
+	 * Get the logical active status in a hierarchical order for all the datetimes.  Note
1152
+	 * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1153
+	 * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1154
+	 * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1155
+	 * the event is considered expired.
1156
+	 * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1157
+	 * status set on the EVENT when it is not published and thus is done
1158
+	 *
1159
+	 * @param bool $reset
1160
+	 * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1161
+	 * @throws EE_Error
1162
+	 * @throws ReflectionException
1163
+	 */
1164
+	public function get_active_status(bool $reset = false)
1165
+	{
1166
+		// if the active status has already been set, then just use that value (unless we are resetting it)
1167
+		if (! empty($this->_active_status) && ! $reset) {
1168
+			return $this->_active_status;
1169
+		}
1170
+		// first check if event id is present on this object
1171
+		if (! $this->ID()) {
1172
+			return false;
1173
+		}
1174
+		$where_params_for_event = [['EVT_ID' => $this->ID()]];
1175
+		// if event is published:
1176
+		if (
1177
+			$this->status() === EEM_CPT_Base::post_status_publish
1178
+			|| $this->status() === EEM_CPT_Base::post_status_private
1179
+		) {
1180
+			// active?
1181
+			if (
1182
+				EEM_Datetime::instance()->get_datetime_count_for_status(
1183
+					EE_Datetime::active,
1184
+					$where_params_for_event
1185
+				) > 0
1186
+			) {
1187
+				$this->_active_status = EE_Datetime::active;
1188
+			} else {
1189
+				// upcoming?
1190
+				if (
1191
+					EEM_Datetime::instance()->get_datetime_count_for_status(
1192
+						EE_Datetime::upcoming,
1193
+						$where_params_for_event
1194
+					) > 0
1195
+				) {
1196
+					$this->_active_status = EE_Datetime::upcoming;
1197
+				} else {
1198
+					// expired?
1199
+					if (
1200
+						EEM_Datetime::instance()->get_datetime_count_for_status(
1201
+							EE_Datetime::expired,
1202
+							$where_params_for_event
1203
+						) > 0
1204
+					) {
1205
+						$this->_active_status = EE_Datetime::expired;
1206
+					} else {
1207
+						// it would be odd if things make it this far
1208
+						// because it basically means there are no datetimes attached to the event.
1209
+						// So in this case it will just be considered inactive.
1210
+						$this->_active_status = EE_Datetime::inactive;
1211
+					}
1212
+				}
1213
+			}
1214
+		} else {
1215
+			// the event is not published, so let's just set it's active status according to its' post status
1216
+			switch ($this->status()) {
1217
+				case EEM_Event::sold_out:
1218
+					$this->_active_status = EE_Datetime::sold_out;
1219
+					break;
1220
+				case EEM_Event::cancelled:
1221
+					$this->_active_status = EE_Datetime::cancelled;
1222
+					break;
1223
+				case EEM_Event::postponed:
1224
+					$this->_active_status = EE_Datetime::postponed;
1225
+					break;
1226
+				default:
1227
+					$this->_active_status = EE_Datetime::inactive;
1228
+			}
1229
+		}
1230
+		return $this->_active_status;
1231
+	}
1232
+
1233
+
1234
+	/**
1235
+	 *    pretty_active_status
1236
+	 *
1237
+	 * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1238
+	 * @return string
1239
+	 * @throws EE_Error
1240
+	 * @throws ReflectionException
1241
+	 */
1242
+	public function pretty_active_status(bool $echo = true): string
1243
+	{
1244
+		$active_status = $this->get_active_status();
1245
+		$status        = "
1246 1246
         <span class='ee-status ee-status-bg--$active_status event-active-status-$active_status'>
1247 1247
             " . EEH_Template::pretty_status($active_status, false, 'sentence') . "
1248 1248
         </span >";
1249
-        if ($echo) {
1250
-            echo wp_kses($status, AllowedTags::getAllowedTags());
1251
-            return '';
1252
-        }
1253
-        return $status;
1254
-    }
1255
-
1256
-
1257
-    /**
1258
-     * @return bool|int
1259
-     * @throws EE_Error
1260
-     * @throws ReflectionException
1261
-     */
1262
-    public function get_number_of_tickets_sold()
1263
-    {
1264
-        $tkt_sold = 0;
1265
-        if (! $this->ID()) {
1266
-            return 0;
1267
-        }
1268
-        $datetimes = $this->datetimes();
1269
-        foreach ($datetimes as $datetime) {
1270
-            if ($datetime instanceof EE_Datetime) {
1271
-                $tkt_sold += $datetime->sold();
1272
-            }
1273
-        }
1274
-        return $tkt_sold;
1275
-    }
1276
-
1277
-
1278
-    /**
1279
-     * This just returns a count of all the registrations for this event
1280
-     *
1281
-     * @return int
1282
-     * @throws EE_Error
1283
-     * @throws ReflectionException
1284
-     */
1285
-    public function get_count_of_all_registrations(): int
1286
-    {
1287
-        return EEM_Event::instance()->count_related($this, 'Registration');
1288
-    }
1289
-
1290
-
1291
-    /**
1292
-     * This returns the ticket with the earliest start time that is
1293
-     * available for this event (across all datetimes attached to the event)
1294
-     *
1295
-     * @return EE_Base_Class|EE_Ticket|null
1296
-     * @throws EE_Error
1297
-     * @throws ReflectionException
1298
-     */
1299
-    public function get_ticket_with_earliest_start_time()
1300
-    {
1301
-        $where['Datetime.EVT_ID'] = $this->ID();
1302
-        $query_params             = [$where, 'order_by' => ['TKT_start_date' => 'ASC']];
1303
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1304
-    }
1305
-
1306
-
1307
-    /**
1308
-     * This returns the ticket with the latest end time that is available
1309
-     * for this event (across all datetimes attached to the event)
1310
-     *
1311
-     * @return EE_Base_Class|EE_Ticket|null
1312
-     * @throws EE_Error
1313
-     * @throws ReflectionException
1314
-     */
1315
-    public function get_ticket_with_latest_end_time()
1316
-    {
1317
-        $where['Datetime.EVT_ID'] = $this->ID();
1318
-        $query_params             = [$where, 'order_by' => ['TKT_end_date' => 'DESC']];
1319
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1320
-    }
1321
-
1322
-
1323
-    /**
1324
-     * This returns the number of different ticket types currently on sale for this event.
1325
-     *
1326
-     * @return int
1327
-     * @throws EE_Error
1328
-     * @throws ReflectionException
1329
-     */
1330
-    public function countTicketsOnSale(): int
1331
-    {
1332
-        $where = [
1333
-            'Datetime.EVT_ID' => $this->ID(),
1334
-            'TKT_start_date'  => ['<', time()],
1335
-            'TKT_end_date'    => ['>', time()],
1336
-        ];
1337
-        return EEM_Ticket::instance()->count([$where]);
1338
-    }
1339
-
1340
-
1341
-    /**
1342
-     * This returns whether there are any tickets on sale for this event.
1343
-     *
1344
-     * @return bool true = YES tickets on sale.
1345
-     * @throws EE_Error
1346
-     * @throws ReflectionException
1347
-     */
1348
-    public function tickets_on_sale(): bool
1349
-    {
1350
-        return $this->countTicketsOnSale() > 0;
1351
-    }
1352
-
1353
-
1354
-    /**
1355
-     * Gets the URL for viewing this event on the front-end. Overrides parent
1356
-     * to check for an external URL first
1357
-     *
1358
-     * @return string
1359
-     * @throws EE_Error
1360
-     * @throws ReflectionException
1361
-     */
1362
-    public function get_permalink(): string
1363
-    {
1364
-        if ($this->external_url()) {
1365
-            return $this->external_url();
1366
-        }
1367
-        return parent::get_permalink();
1368
-    }
1369
-
1370
-
1371
-    /**
1372
-     * Gets the first term for 'espresso_event_categories' we can find
1373
-     *
1374
-     * @param array $query_params
1375
-     * @return EE_Base_Class|EE_Term|null
1376
-     * @throws EE_Error
1377
-     * @throws ReflectionException
1378
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1379
-     */
1380
-    public function first_event_category(array $query_params = []): ?EE_Term
1381
-    {
1382
-        $query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1383
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1384
-        return EEM_Term::instance()->get_one($query_params);
1385
-    }
1386
-
1387
-
1388
-    /**
1389
-     * Gets all terms for 'espresso_event_categories' we can find
1390
-     *
1391
-     * @param array $query_params
1392
-     * @return EE_Base_Class[]|EE_Term[]
1393
-     * @throws EE_Error
1394
-     * @throws ReflectionException
1395
-     */
1396
-    public function get_all_event_categories(array $query_params = []): array
1397
-    {
1398
-        $query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1399
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1400
-        return EEM_Term::instance()->get_all($query_params);
1401
-    }
1402
-
1403
-
1404
-    /**
1405
-     * Adds a question group to this event
1406
-     *
1407
-     * @param EE_Question_Group|int $question_group_id_or_obj
1408
-     * @param bool                  $for_primary if true, the question group will be added for the primary
1409
-     *                                           registrant, if false will be added for others. default: false
1410
-     * @return EE_Base_Class|EE_Question_Group
1411
-     * @throws EE_Error
1412
-     * @throws InvalidArgumentException
1413
-     * @throws InvalidDataTypeException
1414
-     * @throws InvalidInterfaceException
1415
-     * @throws ReflectionException
1416
-     */
1417
-    public function add_question_group($question_group_id_or_obj, bool $for_primary = false): EE_Question_Group
1418
-    {
1419
-        // If the row already exists, it will be updated. If it doesn't, it will be inserted.
1420
-        // That's in EE_HABTM_Relation::add_relation_to().
1421
-        return $this->_add_relation_to(
1422
-            $question_group_id_or_obj,
1423
-            'Question_Group',
1424
-            [
1425
-                EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true,
1426
-            ]
1427
-        );
1428
-    }
1429
-
1430
-
1431
-    /**
1432
-     * Removes a question group from the event
1433
-     *
1434
-     * @param EE_Question_Group|int $question_group_id_or_obj
1435
-     * @param bool                  $for_primary if true, the question group will be removed from the primary
1436
-     *                                           registrant, if false will be removed from others. default: false
1437
-     * @return EE_Base_Class|EE_Question_Group|int
1438
-     * @throws EE_Error
1439
-     * @throws InvalidArgumentException
1440
-     * @throws ReflectionException
1441
-     * @throws InvalidDataTypeException
1442
-     * @throws InvalidInterfaceException
1443
-     */
1444
-    public function remove_question_group($question_group_id_or_obj, bool $for_primary = false)
1445
-    {
1446
-        // If the question group is used for the other type (primary or additional)
1447
-        // then just update it. If not, delete it outright.
1448
-        $existing_relation = $this->get_first_related(
1449
-            'Event_Question_Group',
1450
-            [
1451
-                [
1452
-                    'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj),
1453
-                ],
1454
-            ]
1455
-        );
1456
-        $field_to_update   = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1457
-        $other_field       = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1458
-        if ($existing_relation->get($other_field) === false) {
1459
-            // Delete it. It's now no longer for primary or additional question groups.
1460
-            return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1461
-        }
1462
-        // Just update it. They'll still use this question group for the other category
1463
-        $existing_relation->save(
1464
-            [
1465
-                $field_to_update => false,
1466
-            ]
1467
-        );
1468
-        return $question_group_id_or_obj;
1469
-    }
1470
-
1471
-
1472
-    /**
1473
-     * Gets all the question groups, ordering them by QSG_order ascending
1474
-     *
1475
-     * @param array $query_params
1476
-     * @return EE_Base_Class[]|EE_Question_Group[]
1477
-     * @throws EE_Error
1478
-     * @throws ReflectionException
1479
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1480
-     */
1481
-    public function question_groups(array $query_params = []): array
1482
-    {
1483
-        $query_params = ! empty($query_params) ? $query_params : ['order_by' => ['QSG_order' => 'ASC']];
1484
-        return $this->get_many_related('Question_Group', $query_params);
1485
-    }
1486
-
1487
-
1488
-    /**
1489
-     * Implementation for EEI_Has_Icon interface method.
1490
-     *
1491
-     * @return string
1492
-     * @see EEI_Visual_Representation for comments
1493
-     */
1494
-    public function get_icon(): string
1495
-    {
1496
-        return '<span class="dashicons dashicons-flag"></span>';
1497
-    }
1498
-
1499
-
1500
-    /**
1501
-     * Implementation for EEI_Admin_Links interface method.
1502
-     *
1503
-     * @return string
1504
-     * @throws EE_Error
1505
-     * @throws ReflectionException
1506
-     * @see EEI_Admin_Links for comments
1507
-     */
1508
-    public function get_admin_details_link(): string
1509
-    {
1510
-        return $this->get_admin_edit_link();
1511
-    }
1512
-
1513
-
1514
-    /**
1515
-     * Implementation for EEI_Admin_Links interface method.
1516
-     *
1517
-     * @return string
1518
-     * @throws EE_Error
1519
-     * @throws ReflectionException
1520
-     * @see EEI_Admin_Links for comments
1521
-     */
1522
-    public function get_admin_edit_link(): string
1523
-    {
1524
-        return EEH_URL::add_query_args_and_nonce(
1525
-            [
1526
-                'page'   => 'espresso_events',
1527
-                'action' => 'edit',
1528
-                'post'   => $this->ID(),
1529
-            ],
1530
-            admin_url('admin.php')
1531
-        );
1532
-    }
1533
-
1534
-
1535
-    /**
1536
-     * Implementation for EEI_Admin_Links interface method.
1537
-     *
1538
-     * @return string
1539
-     * @see EEI_Admin_Links for comments
1540
-     */
1541
-    public function get_admin_settings_link(): string
1542
-    {
1543
-        return EEH_URL::add_query_args_and_nonce(
1544
-            [
1545
-                'page'   => 'espresso_events',
1546
-                'action' => 'default_event_settings',
1547
-            ],
1548
-            admin_url('admin.php')
1549
-        );
1550
-    }
1551
-
1552
-
1553
-    /**
1554
-     * Implementation for EEI_Admin_Links interface method.
1555
-     *
1556
-     * @return string
1557
-     * @see EEI_Admin_Links for comments
1558
-     */
1559
-    public function get_admin_overview_link(): string
1560
-    {
1561
-        return EEH_URL::add_query_args_and_nonce(
1562
-            [
1563
-                'page'   => 'espresso_events',
1564
-                'action' => 'default',
1565
-            ],
1566
-            admin_url('admin.php')
1567
-        );
1568
-    }
1569
-
1570
-
1571
-    /**
1572
-     * @return string|null
1573
-     * @throws EE_Error
1574
-     * @throws ReflectionException
1575
-     */
1576
-    public function registrationFormUuid(): ?string
1577
-    {
1578
-        return $this->get('FSC_UUID') ?? '';
1579
-    }
1580
-
1581
-
1582
-    /**
1583
-     * Gets all the form sections for this event
1584
-     *
1585
-     * @return EE_Base_Class[]|EE_Form_Section[]
1586
-     * @throws EE_Error
1587
-     * @throws ReflectionException
1588
-     */
1589
-    public function registrationForm(): array
1590
-    {
1591
-        $FSC_UUID = $this->registrationFormUuid();
1592
-
1593
-        if (empty($FSC_UUID)) {
1594
-            return [];
1595
-        }
1596
-
1597
-        return EEM_Form_Section::instance()->get_all(
1598
-            [
1599
-                [
1600
-                    'OR' => [
1601
-                        'FSC_UUID'      => $FSC_UUID, // top level form
1602
-                        'FSC_belongsTo' => $FSC_UUID, // child form sections
1603
-                    ],
1604
-                ],
1605
-                'order_by' => ['FSC_order' => 'ASC'],
1606
-            ]
1607
-        );
1608
-    }
1609
-
1610
-
1611
-    /**
1612
-     * @param string $UUID
1613
-     * @throws EE_Error
1614
-     * @throws ReflectionException
1615
-     */
1616
-    public function setRegistrationFormUuid(string $UUID): void
1617
-    {
1618
-        if (! Cuid::isCuid($UUID)) {
1619
-            throw new InvalidArgumentException(
1620
-                sprintf(
1621
-                /* translators: 1: UUID value, 2: UUID generator function. */
1622
-                    esc_html__(
1623
-                        'The supplied UUID "%1$s" is invalid or missing. Please use %2$s to generate a valid one.',
1624
-                        'event_espresso'
1625
-                    ),
1626
-                    $UUID,
1627
-                    '`Cuid::cuid()`'
1628
-                )
1629
-            );
1630
-        }
1631
-        $this->set('FSC_UUID', $UUID);
1632
-    }
1633
-
1634
-
1635
-    /**
1636
-     * Get visibility status of event
1637
-     *
1638
-     * @param bool $hide_public
1639
-     * @return string
1640
-     */
1641
-    public function get_visibility_status(bool $hide_public = true): string
1642
-    {
1643
-        if ($this->status() === 'private') {
1644
-            return esc_html__('Private', 'event_espresso');
1645
-        }
1646
-        if (! empty($this->wp_post()->post_password)) {
1647
-            return esc_html__('Password Protected', 'event_espresso');
1648
-        }
1649
-        if (! $hide_public) {
1650
-            return esc_html__('Public', 'event_espresso');
1651
-        }
1652
-
1653
-        return '';
1654
-    }
1249
+		if ($echo) {
1250
+			echo wp_kses($status, AllowedTags::getAllowedTags());
1251
+			return '';
1252
+		}
1253
+		return $status;
1254
+	}
1255
+
1256
+
1257
+	/**
1258
+	 * @return bool|int
1259
+	 * @throws EE_Error
1260
+	 * @throws ReflectionException
1261
+	 */
1262
+	public function get_number_of_tickets_sold()
1263
+	{
1264
+		$tkt_sold = 0;
1265
+		if (! $this->ID()) {
1266
+			return 0;
1267
+		}
1268
+		$datetimes = $this->datetimes();
1269
+		foreach ($datetimes as $datetime) {
1270
+			if ($datetime instanceof EE_Datetime) {
1271
+				$tkt_sold += $datetime->sold();
1272
+			}
1273
+		}
1274
+		return $tkt_sold;
1275
+	}
1276
+
1277
+
1278
+	/**
1279
+	 * This just returns a count of all the registrations for this event
1280
+	 *
1281
+	 * @return int
1282
+	 * @throws EE_Error
1283
+	 * @throws ReflectionException
1284
+	 */
1285
+	public function get_count_of_all_registrations(): int
1286
+	{
1287
+		return EEM_Event::instance()->count_related($this, 'Registration');
1288
+	}
1289
+
1290
+
1291
+	/**
1292
+	 * This returns the ticket with the earliest start time that is
1293
+	 * available for this event (across all datetimes attached to the event)
1294
+	 *
1295
+	 * @return EE_Base_Class|EE_Ticket|null
1296
+	 * @throws EE_Error
1297
+	 * @throws ReflectionException
1298
+	 */
1299
+	public function get_ticket_with_earliest_start_time()
1300
+	{
1301
+		$where['Datetime.EVT_ID'] = $this->ID();
1302
+		$query_params             = [$where, 'order_by' => ['TKT_start_date' => 'ASC']];
1303
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1304
+	}
1305
+
1306
+
1307
+	/**
1308
+	 * This returns the ticket with the latest end time that is available
1309
+	 * for this event (across all datetimes attached to the event)
1310
+	 *
1311
+	 * @return EE_Base_Class|EE_Ticket|null
1312
+	 * @throws EE_Error
1313
+	 * @throws ReflectionException
1314
+	 */
1315
+	public function get_ticket_with_latest_end_time()
1316
+	{
1317
+		$where['Datetime.EVT_ID'] = $this->ID();
1318
+		$query_params             = [$where, 'order_by' => ['TKT_end_date' => 'DESC']];
1319
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1320
+	}
1321
+
1322
+
1323
+	/**
1324
+	 * This returns the number of different ticket types currently on sale for this event.
1325
+	 *
1326
+	 * @return int
1327
+	 * @throws EE_Error
1328
+	 * @throws ReflectionException
1329
+	 */
1330
+	public function countTicketsOnSale(): int
1331
+	{
1332
+		$where = [
1333
+			'Datetime.EVT_ID' => $this->ID(),
1334
+			'TKT_start_date'  => ['<', time()],
1335
+			'TKT_end_date'    => ['>', time()],
1336
+		];
1337
+		return EEM_Ticket::instance()->count([$where]);
1338
+	}
1339
+
1340
+
1341
+	/**
1342
+	 * This returns whether there are any tickets on sale for this event.
1343
+	 *
1344
+	 * @return bool true = YES tickets on sale.
1345
+	 * @throws EE_Error
1346
+	 * @throws ReflectionException
1347
+	 */
1348
+	public function tickets_on_sale(): bool
1349
+	{
1350
+		return $this->countTicketsOnSale() > 0;
1351
+	}
1352
+
1353
+
1354
+	/**
1355
+	 * Gets the URL for viewing this event on the front-end. Overrides parent
1356
+	 * to check for an external URL first
1357
+	 *
1358
+	 * @return string
1359
+	 * @throws EE_Error
1360
+	 * @throws ReflectionException
1361
+	 */
1362
+	public function get_permalink(): string
1363
+	{
1364
+		if ($this->external_url()) {
1365
+			return $this->external_url();
1366
+		}
1367
+		return parent::get_permalink();
1368
+	}
1369
+
1370
+
1371
+	/**
1372
+	 * Gets the first term for 'espresso_event_categories' we can find
1373
+	 *
1374
+	 * @param array $query_params
1375
+	 * @return EE_Base_Class|EE_Term|null
1376
+	 * @throws EE_Error
1377
+	 * @throws ReflectionException
1378
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1379
+	 */
1380
+	public function first_event_category(array $query_params = []): ?EE_Term
1381
+	{
1382
+		$query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1383
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1384
+		return EEM_Term::instance()->get_one($query_params);
1385
+	}
1386
+
1387
+
1388
+	/**
1389
+	 * Gets all terms for 'espresso_event_categories' we can find
1390
+	 *
1391
+	 * @param array $query_params
1392
+	 * @return EE_Base_Class[]|EE_Term[]
1393
+	 * @throws EE_Error
1394
+	 * @throws ReflectionException
1395
+	 */
1396
+	public function get_all_event_categories(array $query_params = []): array
1397
+	{
1398
+		$query_params[0]['Term_Taxonomy.taxonomy']     = 'espresso_event_categories';
1399
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1400
+		return EEM_Term::instance()->get_all($query_params);
1401
+	}
1402
+
1403
+
1404
+	/**
1405
+	 * Adds a question group to this event
1406
+	 *
1407
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1408
+	 * @param bool                  $for_primary if true, the question group will be added for the primary
1409
+	 *                                           registrant, if false will be added for others. default: false
1410
+	 * @return EE_Base_Class|EE_Question_Group
1411
+	 * @throws EE_Error
1412
+	 * @throws InvalidArgumentException
1413
+	 * @throws InvalidDataTypeException
1414
+	 * @throws InvalidInterfaceException
1415
+	 * @throws ReflectionException
1416
+	 */
1417
+	public function add_question_group($question_group_id_or_obj, bool $for_primary = false): EE_Question_Group
1418
+	{
1419
+		// If the row already exists, it will be updated. If it doesn't, it will be inserted.
1420
+		// That's in EE_HABTM_Relation::add_relation_to().
1421
+		return $this->_add_relation_to(
1422
+			$question_group_id_or_obj,
1423
+			'Question_Group',
1424
+			[
1425
+				EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true,
1426
+			]
1427
+		);
1428
+	}
1429
+
1430
+
1431
+	/**
1432
+	 * Removes a question group from the event
1433
+	 *
1434
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1435
+	 * @param bool                  $for_primary if true, the question group will be removed from the primary
1436
+	 *                                           registrant, if false will be removed from others. default: false
1437
+	 * @return EE_Base_Class|EE_Question_Group|int
1438
+	 * @throws EE_Error
1439
+	 * @throws InvalidArgumentException
1440
+	 * @throws ReflectionException
1441
+	 * @throws InvalidDataTypeException
1442
+	 * @throws InvalidInterfaceException
1443
+	 */
1444
+	public function remove_question_group($question_group_id_or_obj, bool $for_primary = false)
1445
+	{
1446
+		// If the question group is used for the other type (primary or additional)
1447
+		// then just update it. If not, delete it outright.
1448
+		$existing_relation = $this->get_first_related(
1449
+			'Event_Question_Group',
1450
+			[
1451
+				[
1452
+					'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj),
1453
+				],
1454
+			]
1455
+		);
1456
+		$field_to_update   = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1457
+		$other_field       = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1458
+		if ($existing_relation->get($other_field) === false) {
1459
+			// Delete it. It's now no longer for primary or additional question groups.
1460
+			return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1461
+		}
1462
+		// Just update it. They'll still use this question group for the other category
1463
+		$existing_relation->save(
1464
+			[
1465
+				$field_to_update => false,
1466
+			]
1467
+		);
1468
+		return $question_group_id_or_obj;
1469
+	}
1470
+
1471
+
1472
+	/**
1473
+	 * Gets all the question groups, ordering them by QSG_order ascending
1474
+	 *
1475
+	 * @param array $query_params
1476
+	 * @return EE_Base_Class[]|EE_Question_Group[]
1477
+	 * @throws EE_Error
1478
+	 * @throws ReflectionException
1479
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1480
+	 */
1481
+	public function question_groups(array $query_params = []): array
1482
+	{
1483
+		$query_params = ! empty($query_params) ? $query_params : ['order_by' => ['QSG_order' => 'ASC']];
1484
+		return $this->get_many_related('Question_Group', $query_params);
1485
+	}
1486
+
1487
+
1488
+	/**
1489
+	 * Implementation for EEI_Has_Icon interface method.
1490
+	 *
1491
+	 * @return string
1492
+	 * @see EEI_Visual_Representation for comments
1493
+	 */
1494
+	public function get_icon(): string
1495
+	{
1496
+		return '<span class="dashicons dashicons-flag"></span>';
1497
+	}
1498
+
1499
+
1500
+	/**
1501
+	 * Implementation for EEI_Admin_Links interface method.
1502
+	 *
1503
+	 * @return string
1504
+	 * @throws EE_Error
1505
+	 * @throws ReflectionException
1506
+	 * @see EEI_Admin_Links for comments
1507
+	 */
1508
+	public function get_admin_details_link(): string
1509
+	{
1510
+		return $this->get_admin_edit_link();
1511
+	}
1512
+
1513
+
1514
+	/**
1515
+	 * Implementation for EEI_Admin_Links interface method.
1516
+	 *
1517
+	 * @return string
1518
+	 * @throws EE_Error
1519
+	 * @throws ReflectionException
1520
+	 * @see EEI_Admin_Links for comments
1521
+	 */
1522
+	public function get_admin_edit_link(): string
1523
+	{
1524
+		return EEH_URL::add_query_args_and_nonce(
1525
+			[
1526
+				'page'   => 'espresso_events',
1527
+				'action' => 'edit',
1528
+				'post'   => $this->ID(),
1529
+			],
1530
+			admin_url('admin.php')
1531
+		);
1532
+	}
1533
+
1534
+
1535
+	/**
1536
+	 * Implementation for EEI_Admin_Links interface method.
1537
+	 *
1538
+	 * @return string
1539
+	 * @see EEI_Admin_Links for comments
1540
+	 */
1541
+	public function get_admin_settings_link(): string
1542
+	{
1543
+		return EEH_URL::add_query_args_and_nonce(
1544
+			[
1545
+				'page'   => 'espresso_events',
1546
+				'action' => 'default_event_settings',
1547
+			],
1548
+			admin_url('admin.php')
1549
+		);
1550
+	}
1551
+
1552
+
1553
+	/**
1554
+	 * Implementation for EEI_Admin_Links interface method.
1555
+	 *
1556
+	 * @return string
1557
+	 * @see EEI_Admin_Links for comments
1558
+	 */
1559
+	public function get_admin_overview_link(): string
1560
+	{
1561
+		return EEH_URL::add_query_args_and_nonce(
1562
+			[
1563
+				'page'   => 'espresso_events',
1564
+				'action' => 'default',
1565
+			],
1566
+			admin_url('admin.php')
1567
+		);
1568
+	}
1569
+
1570
+
1571
+	/**
1572
+	 * @return string|null
1573
+	 * @throws EE_Error
1574
+	 * @throws ReflectionException
1575
+	 */
1576
+	public function registrationFormUuid(): ?string
1577
+	{
1578
+		return $this->get('FSC_UUID') ?? '';
1579
+	}
1580
+
1581
+
1582
+	/**
1583
+	 * Gets all the form sections for this event
1584
+	 *
1585
+	 * @return EE_Base_Class[]|EE_Form_Section[]
1586
+	 * @throws EE_Error
1587
+	 * @throws ReflectionException
1588
+	 */
1589
+	public function registrationForm(): array
1590
+	{
1591
+		$FSC_UUID = $this->registrationFormUuid();
1592
+
1593
+		if (empty($FSC_UUID)) {
1594
+			return [];
1595
+		}
1596
+
1597
+		return EEM_Form_Section::instance()->get_all(
1598
+			[
1599
+				[
1600
+					'OR' => [
1601
+						'FSC_UUID'      => $FSC_UUID, // top level form
1602
+						'FSC_belongsTo' => $FSC_UUID, // child form sections
1603
+					],
1604
+				],
1605
+				'order_by' => ['FSC_order' => 'ASC'],
1606
+			]
1607
+		);
1608
+	}
1609
+
1610
+
1611
+	/**
1612
+	 * @param string $UUID
1613
+	 * @throws EE_Error
1614
+	 * @throws ReflectionException
1615
+	 */
1616
+	public function setRegistrationFormUuid(string $UUID): void
1617
+	{
1618
+		if (! Cuid::isCuid($UUID)) {
1619
+			throw new InvalidArgumentException(
1620
+				sprintf(
1621
+				/* translators: 1: UUID value, 2: UUID generator function. */
1622
+					esc_html__(
1623
+						'The supplied UUID "%1$s" is invalid or missing. Please use %2$s to generate a valid one.',
1624
+						'event_espresso'
1625
+					),
1626
+					$UUID,
1627
+					'`Cuid::cuid()`'
1628
+				)
1629
+			);
1630
+		}
1631
+		$this->set('FSC_UUID', $UUID);
1632
+	}
1633
+
1634
+
1635
+	/**
1636
+	 * Get visibility status of event
1637
+	 *
1638
+	 * @param bool $hide_public
1639
+	 * @return string
1640
+	 */
1641
+	public function get_visibility_status(bool $hide_public = true): string
1642
+	{
1643
+		if ($this->status() === 'private') {
1644
+			return esc_html__('Private', 'event_espresso');
1645
+		}
1646
+		if (! empty($this->wp_post()->post_password)) {
1647
+			return esc_html__('Password Protected', 'event_espresso');
1648
+		}
1649
+		if (! $hide_public) {
1650
+			return esc_html__('Public', 'event_espresso');
1651
+		}
1652
+
1653
+		return '';
1654
+	}
1655 1655
 }
Please login to merge, or discard this patch.
core/services/database/WordPressOption.php 1 patch
Indentation   +177 added lines, -177 removed lines patch added patch discarded remove patch
@@ -17,181 +17,181 @@
 block discarded – undo
17 17
  */
18 18
 abstract class WordPressOption
19 19
 {
20
-    public const NOT_SET_YET = 'wordpress-option-value-not-yet-set';
21
-
22
-    /**
23
-     * WordPress makes it difficult to determine if an option successfully saved or not,
24
-     * which is sometimes really important to know, especially if the information you are saving is critical.
25
-     * The following options allow us to have a better chance of knowing when an update actually failed
26
-     * or when everything is OK but it just didn't update because the value hasn't changed.
27
-     */
28
-    public const UPDATE_SUCCESS = 1;
29
-
30
-    public const UPDATE_NONE = 0;
31
-
32
-    public const UPDATE_ERROR = -1;
33
-
34
-    /**
35
-     * @var bool
36
-     */
37
-    private $autoload = false;
38
-
39
-    /**
40
-     * @var mixed
41
-     */
42
-    private $default_value = null;
43
-
44
-    /**
45
-     * @var string
46
-     */
47
-    private $option_name = '';
48
-
49
-    /**
50
-     * @var mixed
51
-     */
52
-    private $value = WordPressOption::NOT_SET_YET;
53
-
54
-    /**
55
-     * @var OptionEngine
56
-     */
57
-    private $option_engine;
58
-
59
-
60
-    /**
61
-     * WordPressOption constructor.
62
-     *
63
-     * @param string $option_name
64
-     * @param mixed  $default_value
65
-     * @param bool   $autoload              if true, will load the option on EVERY request
66
-     * @param bool   $is_network_option     if true, will save the option to the network as opposed to the current blog
67
-     */
68
-    public function __construct(
69
-        string $option_name,
70
-        $default_value,
71
-        bool $autoload = false,
72
-        bool $is_network_option = false
73
-    ) {
74
-        $this->setAutoload($autoload);
75
-        $this->setDefaultValue($default_value);
76
-        $this->setOptionName($option_name);
77
-        $this->option_engine = new OptionEngine($is_network_option);
78
-    }
79
-
80
-
81
-    /**
82
-     * @param bool|string $autoload
83
-     */
84
-    public function setAutoload($autoload): void
85
-    {
86
-        $this->autoload = filter_var($autoload, FILTER_VALIDATE_BOOLEAN);
87
-    }
88
-
89
-
90
-    /**
91
-     * @param mixed $default_value
92
-     */
93
-    public function setDefaultValue($default_value): void
94
-    {
95
-        $this->default_value = $default_value;
96
-    }
97
-
98
-
99
-    /**
100
-     * @param string $option_name
101
-     */
102
-    public function setOptionName(string $option_name): void
103
-    {
104
-        $this->option_name = sanitize_key($option_name);
105
-    }
106
-
107
-
108
-    /**
109
-     * @return string
110
-     */
111
-    public function optionExists(): string
112
-    {
113
-        return $this->option_engine->getOption(
114
-            $this->getOptionName(),
115
-            WordPressOption::NOT_SET_YET
116
-        ) !== WordPressOption::NOT_SET_YET;
117
-    }
118
-
119
-
120
-    /**
121
-     * @return string
122
-     */
123
-    public function getOptionName(): string
124
-    {
125
-        return $this->option_name;
126
-    }
127
-
128
-
129
-    /**
130
-     * @return false|mixed|void
131
-     */
132
-    public function loadOption()
133
-    {
134
-        if ($this->value === WordPressOption::NOT_SET_YET) {
135
-            $this->value = $this->option_engine->getOption($this->getOptionName(), $this->default_value);
136
-        }
137
-        return $this->value;
138
-    }
139
-
140
-
141
-    /**
142
-     * @param $value
143
-     * @return int
144
-     */
145
-    public function updateOption($value): int
146
-    {
147
-        // don't update if value has not changed since last update
148
-        if ($this->valueIsUnchanged($value)) {
149
-            return WordPressOption::UPDATE_NONE;
150
-        }
151
-        $this->value = $value;
152
-        // because the options for updating differ when adding an option for the first time
153
-        // we use the WordPressOption::NOT_SET_YET to determine if things already exist in the db
154
-        $updated = $this->optionExists()
155
-            ? $this->option_engine->updateOption($this->getOptionName(), $this->value)
156
-            : $this->option_engine->addOption($this->getOptionName(), $this->value, $this->autoload());
157
-
158
-        if ($updated) {
159
-            return WordPressOption::UPDATE_SUCCESS;
160
-        }
161
-        return WordPressOption::UPDATE_ERROR;
162
-    }
163
-
164
-
165
-    private function valueIsUnchanged($value): bool
166
-    {
167
-        if (is_array($value) && is_array($this->value)) {
168
-            $diff = EEH_Array::array_diff_recursive($value, $this->value);
169
-            // $diff = array_diff($value, $this->value);
170
-            return empty($diff);
171
-        }
172
-        // emulate WP's method for checking equality
173
-        return $value === $this->value && maybe_serialize($value) === maybe_serialize($this->value);
174
-    }
175
-
176
-
177
-    /**
178
-     * @return string
179
-     */
180
-    private function autoload(): string
181
-    {
182
-        return $this->autoload ? 'yes' : 'no';
183
-    }
184
-
185
-
186
-    /**
187
-     * Deletes the option from the database
188
-     * for the rest of the request
189
-     *
190
-     * @return bool
191
-     * @since  $VID:$
192
-     */
193
-    public function deleteOption(): bool
194
-    {
195
-        return $this->option_engine->deleteOption($this->getOptionName());
196
-    }
20
+	public const NOT_SET_YET = 'wordpress-option-value-not-yet-set';
21
+
22
+	/**
23
+	 * WordPress makes it difficult to determine if an option successfully saved or not,
24
+	 * which is sometimes really important to know, especially if the information you are saving is critical.
25
+	 * The following options allow us to have a better chance of knowing when an update actually failed
26
+	 * or when everything is OK but it just didn't update because the value hasn't changed.
27
+	 */
28
+	public const UPDATE_SUCCESS = 1;
29
+
30
+	public const UPDATE_NONE = 0;
31
+
32
+	public const UPDATE_ERROR = -1;
33
+
34
+	/**
35
+	 * @var bool
36
+	 */
37
+	private $autoload = false;
38
+
39
+	/**
40
+	 * @var mixed
41
+	 */
42
+	private $default_value = null;
43
+
44
+	/**
45
+	 * @var string
46
+	 */
47
+	private $option_name = '';
48
+
49
+	/**
50
+	 * @var mixed
51
+	 */
52
+	private $value = WordPressOption::NOT_SET_YET;
53
+
54
+	/**
55
+	 * @var OptionEngine
56
+	 */
57
+	private $option_engine;
58
+
59
+
60
+	/**
61
+	 * WordPressOption constructor.
62
+	 *
63
+	 * @param string $option_name
64
+	 * @param mixed  $default_value
65
+	 * @param bool   $autoload              if true, will load the option on EVERY request
66
+	 * @param bool   $is_network_option     if true, will save the option to the network as opposed to the current blog
67
+	 */
68
+	public function __construct(
69
+		string $option_name,
70
+		$default_value,
71
+		bool $autoload = false,
72
+		bool $is_network_option = false
73
+	) {
74
+		$this->setAutoload($autoload);
75
+		$this->setDefaultValue($default_value);
76
+		$this->setOptionName($option_name);
77
+		$this->option_engine = new OptionEngine($is_network_option);
78
+	}
79
+
80
+
81
+	/**
82
+	 * @param bool|string $autoload
83
+	 */
84
+	public function setAutoload($autoload): void
85
+	{
86
+		$this->autoload = filter_var($autoload, FILTER_VALIDATE_BOOLEAN);
87
+	}
88
+
89
+
90
+	/**
91
+	 * @param mixed $default_value
92
+	 */
93
+	public function setDefaultValue($default_value): void
94
+	{
95
+		$this->default_value = $default_value;
96
+	}
97
+
98
+
99
+	/**
100
+	 * @param string $option_name
101
+	 */
102
+	public function setOptionName(string $option_name): void
103
+	{
104
+		$this->option_name = sanitize_key($option_name);
105
+	}
106
+
107
+
108
+	/**
109
+	 * @return string
110
+	 */
111
+	public function optionExists(): string
112
+	{
113
+		return $this->option_engine->getOption(
114
+			$this->getOptionName(),
115
+			WordPressOption::NOT_SET_YET
116
+		) !== WordPressOption::NOT_SET_YET;
117
+	}
118
+
119
+
120
+	/**
121
+	 * @return string
122
+	 */
123
+	public function getOptionName(): string
124
+	{
125
+		return $this->option_name;
126
+	}
127
+
128
+
129
+	/**
130
+	 * @return false|mixed|void
131
+	 */
132
+	public function loadOption()
133
+	{
134
+		if ($this->value === WordPressOption::NOT_SET_YET) {
135
+			$this->value = $this->option_engine->getOption($this->getOptionName(), $this->default_value);
136
+		}
137
+		return $this->value;
138
+	}
139
+
140
+
141
+	/**
142
+	 * @param $value
143
+	 * @return int
144
+	 */
145
+	public function updateOption($value): int
146
+	{
147
+		// don't update if value has not changed since last update
148
+		if ($this->valueIsUnchanged($value)) {
149
+			return WordPressOption::UPDATE_NONE;
150
+		}
151
+		$this->value = $value;
152
+		// because the options for updating differ when adding an option for the first time
153
+		// we use the WordPressOption::NOT_SET_YET to determine if things already exist in the db
154
+		$updated = $this->optionExists()
155
+			? $this->option_engine->updateOption($this->getOptionName(), $this->value)
156
+			: $this->option_engine->addOption($this->getOptionName(), $this->value, $this->autoload());
157
+
158
+		if ($updated) {
159
+			return WordPressOption::UPDATE_SUCCESS;
160
+		}
161
+		return WordPressOption::UPDATE_ERROR;
162
+	}
163
+
164
+
165
+	private function valueIsUnchanged($value): bool
166
+	{
167
+		if (is_array($value) && is_array($this->value)) {
168
+			$diff = EEH_Array::array_diff_recursive($value, $this->value);
169
+			// $diff = array_diff($value, $this->value);
170
+			return empty($diff);
171
+		}
172
+		// emulate WP's method for checking equality
173
+		return $value === $this->value && maybe_serialize($value) === maybe_serialize($this->value);
174
+	}
175
+
176
+
177
+	/**
178
+	 * @return string
179
+	 */
180
+	private function autoload(): string
181
+	{
182
+		return $this->autoload ? 'yes' : 'no';
183
+	}
184
+
185
+
186
+	/**
187
+	 * Deletes the option from the database
188
+	 * for the rest of the request
189
+	 *
190
+	 * @return bool
191
+	 * @since  $VID:$
192
+	 */
193
+	public function deleteOption(): bool
194
+	{
195
+		return $this->option_engine->deleteOption($this->getOptionName());
196
+	}
197 197
 }
Please login to merge, or discard this patch.
core/services/request/Response.php 1 patch
Indentation   +135 added lines, -135 removed lines patch added patch discarded remove patch
@@ -14,139 +14,139 @@
 block discarded – undo
14 14
  */
15 15
 class Response implements ResponseInterface, ReservedInstanceInterface
16 16
 {
17
-    protected bool  $deactivate_plugin = false;
18
-
19
-    protected array $notice            = [];
20
-
21
-    /**
22
-     * rendered output to be returned to WP
23
-     */
24
-    protected array $output             = [];
25
-
26
-    protected array $request_headers    = [];
27
-
28
-    protected bool  $request_terminated = false;
29
-
30
-
31
-    /**
32
-     * EE_Response constructor.
33
-     */
34
-    public function __construct()
35
-    {
36
-        $this->terminateRequest(false);
37
-    }
38
-
39
-
40
-    /**
41
-     * @param $key
42
-     * @param $value
43
-     * @return    void
44
-     */
45
-    public function setNotice($key, $value)
46
-    {
47
-        $this->notice[ $key ] = $value;
48
-    }
49
-
50
-
51
-    /**
52
-     * @param $key
53
-     * @return    mixed
54
-     */
55
-    public function getNotice($key)
56
-    {
57
-        return $this->notice[ $key ] ?? null;
58
-    }
59
-
60
-
61
-    /**
62
-     * @return array
63
-     */
64
-    public function getNotices(): array
65
-    {
66
-        return $this->notice;
67
-    }
68
-
69
-
70
-    /**
71
-     * @param string $string
72
-     * @param bool   $append
73
-     */
74
-    public function addOutput(string $string, bool $append = true)
75
-    {
76
-        if ($append) {
77
-            $this->output[] = $string;
78
-            return;
79
-        }
80
-        array_unshift($this->output, $string);
81
-    }
82
-
83
-
84
-    /**
85
-     * @param bool   $as_string
86
-     * @param string $separator
87
-     * @return array|string
88
-     */
89
-    public function getOutput(bool $as_string = true, string $separator = PHP_EOL)
90
-    {
91
-        return $as_string
92
-            ? implode($separator, $this->output)
93
-            : $this->output;
94
-    }
95
-
96
-
97
-    /**
98
-     * @return boolean
99
-     */
100
-    public function requestTerminated(): bool
101
-    {
102
-        return $this->request_terminated;
103
-    }
104
-
105
-
106
-    /**
107
-     * @param bool|int|string|null $request_terminated
108
-     */
109
-    public function terminateRequest($request_terminated = true)
110
-    {
111
-        $this->request_terminated = filter_var($request_terminated, FILTER_VALIDATE_BOOLEAN);
112
-    }
113
-
114
-
115
-    /**
116
-     * @return boolean
117
-     */
118
-    public function pluginDeactivated(): bool
119
-    {
120
-        return $this->deactivate_plugin;
121
-    }
122
-
123
-
124
-    /**
125
-     * sets $deactivate_plugin to true
126
-     */
127
-    public function deactivatePlugin()
128
-    {
129
-        $this->deactivate_plugin = true;
130
-    }
131
-
132
-
133
-    /**
134
-     * @return array
135
-     * @since $VID:$
136
-     */
137
-    public function requestHeaders(): array
138
-    {
139
-        return $this->request_headers;
140
-    }
141
-
142
-
143
-    /**
144
-     * @param string $request_header
145
-     * @return void
146
-     * @since $VID:$
147
-     */
148
-    public function setRequestHeader(string $request_header): void
149
-    {
150
-        $this->request_headers[] = $request_header;
151
-    }
17
+	protected bool  $deactivate_plugin = false;
18
+
19
+	protected array $notice            = [];
20
+
21
+	/**
22
+	 * rendered output to be returned to WP
23
+	 */
24
+	protected array $output             = [];
25
+
26
+	protected array $request_headers    = [];
27
+
28
+	protected bool  $request_terminated = false;
29
+
30
+
31
+	/**
32
+	 * EE_Response constructor.
33
+	 */
34
+	public function __construct()
35
+	{
36
+		$this->terminateRequest(false);
37
+	}
38
+
39
+
40
+	/**
41
+	 * @param $key
42
+	 * @param $value
43
+	 * @return    void
44
+	 */
45
+	public function setNotice($key, $value)
46
+	{
47
+		$this->notice[ $key ] = $value;
48
+	}
49
+
50
+
51
+	/**
52
+	 * @param $key
53
+	 * @return    mixed
54
+	 */
55
+	public function getNotice($key)
56
+	{
57
+		return $this->notice[ $key ] ?? null;
58
+	}
59
+
60
+
61
+	/**
62
+	 * @return array
63
+	 */
64
+	public function getNotices(): array
65
+	{
66
+		return $this->notice;
67
+	}
68
+
69
+
70
+	/**
71
+	 * @param string $string
72
+	 * @param bool   $append
73
+	 */
74
+	public function addOutput(string $string, bool $append = true)
75
+	{
76
+		if ($append) {
77
+			$this->output[] = $string;
78
+			return;
79
+		}
80
+		array_unshift($this->output, $string);
81
+	}
82
+
83
+
84
+	/**
85
+	 * @param bool   $as_string
86
+	 * @param string $separator
87
+	 * @return array|string
88
+	 */
89
+	public function getOutput(bool $as_string = true, string $separator = PHP_EOL)
90
+	{
91
+		return $as_string
92
+			? implode($separator, $this->output)
93
+			: $this->output;
94
+	}
95
+
96
+
97
+	/**
98
+	 * @return boolean
99
+	 */
100
+	public function requestTerminated(): bool
101
+	{
102
+		return $this->request_terminated;
103
+	}
104
+
105
+
106
+	/**
107
+	 * @param bool|int|string|null $request_terminated
108
+	 */
109
+	public function terminateRequest($request_terminated = true)
110
+	{
111
+		$this->request_terminated = filter_var($request_terminated, FILTER_VALIDATE_BOOLEAN);
112
+	}
113
+
114
+
115
+	/**
116
+	 * @return boolean
117
+	 */
118
+	public function pluginDeactivated(): bool
119
+	{
120
+		return $this->deactivate_plugin;
121
+	}
122
+
123
+
124
+	/**
125
+	 * sets $deactivate_plugin to true
126
+	 */
127
+	public function deactivatePlugin()
128
+	{
129
+		$this->deactivate_plugin = true;
130
+	}
131
+
132
+
133
+	/**
134
+	 * @return array
135
+	 * @since $VID:$
136
+	 */
137
+	public function requestHeaders(): array
138
+	{
139
+		return $this->request_headers;
140
+	}
141
+
142
+
143
+	/**
144
+	 * @param string $request_header
145
+	 * @return void
146
+	 * @since $VID:$
147
+	 */
148
+	public function setRequestHeader(string $request_header): void
149
+	{
150
+		$this->request_headers[] = $request_header;
151
+	}
152 152
 }
Please login to merge, or discard this patch.
core/services/request/ResponseInterface.php 1 patch
Indentation   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -11,77 +11,77 @@
 block discarded – undo
11 11
  */
12 12
 interface ResponseInterface
13 13
 {
14
-    /**
15
-     * @param $key
16
-     * @param $value
17
-     * @return    void
18
-     */
19
-    public function setNotice($key, $value);
14
+	/**
15
+	 * @param $key
16
+	 * @param $value
17
+	 * @return    void
18
+	 */
19
+	public function setNotice($key, $value);
20 20
 
21 21
 
22
-    /**
23
-     * @param $key
24
-     * @return    mixed
25
-     */
26
-    public function getNotice($key);
22
+	/**
23
+	 * @param $key
24
+	 * @return    mixed
25
+	 */
26
+	public function getNotice($key);
27 27
 
28 28
 
29
-    /**
30
-     * @return    array
31
-     */
32
-    public function getNotices(): array;
29
+	/**
30
+	 * @return    array
31
+	 */
32
+	public function getNotices(): array;
33 33
 
34 34
 
35
-    /**
36
-     * @param string $string
37
-     * @param bool   $append
38
-     */
39
-    public function addOutput(string $string, bool $append = true);
35
+	/**
36
+	 * @param string $string
37
+	 * @param bool   $append
38
+	 */
39
+	public function addOutput(string $string, bool $append = true);
40 40
 
41 41
 
42
-    /**
43
-     * @param bool   $as_string
44
-     * @param string $separator
45
-     * @return array|string
46
-     */
47
-    public function getOutput(bool $as_string = true, string $separator = PHP_EOL);
42
+	/**
43
+	 * @param bool   $as_string
44
+	 * @param string $separator
45
+	 * @return array|string
46
+	 */
47
+	public function getOutput(bool $as_string = true, string $separator = PHP_EOL);
48 48
 
49 49
 
50
-    /**
51
-     * @return boolean
52
-     */
53
-    public function requestTerminated(): bool;
50
+	/**
51
+	 * @return boolean
52
+	 */
53
+	public function requestTerminated(): bool;
54 54
 
55 55
 
56
-    /**
57
-     * @param bool|int|string|null $request_terminated
58
-     */
59
-    public function terminateRequest($request_terminated = true);
56
+	/**
57
+	 * @param bool|int|string|null $request_terminated
58
+	 */
59
+	public function terminateRequest($request_terminated = true);
60 60
 
61 61
 
62
-    /**
63
-     * @return boolean
64
-     */
65
-    public function pluginDeactivated(): bool;
62
+	/**
63
+	 * @return boolean
64
+	 */
65
+	public function pluginDeactivated(): bool;
66 66
 
67 67
 
68
-    /**
69
-     * sets $deactivate_plugin to true
70
-     */
71
-    public function deactivatePlugin();
68
+	/**
69
+	 * sets $deactivate_plugin to true
70
+	 */
71
+	public function deactivatePlugin();
72 72
 
73 73
 
74
-    /**
75
-     * @return array
76
-     * @since $VID:$
77
-     */
78
-    public function requestHeaders(): array;
74
+	/**
75
+	 * @return array
76
+	 * @since $VID:$
77
+	 */
78
+	public function requestHeaders(): array;
79 79
 
80 80
 
81
-    /**
82
-     * @param string $request_header
83
-     * @return void
84
-     * @since $VID:$
85
-     */
86
-    public function setRequestHeader(string $request_header): void;
81
+	/**
82
+	 * @param string $request_header
83
+	 * @return void
84
+	 * @since $VID:$
85
+	 */
86
+	public function setRequestHeader(string $request_header): void;
87 87
 }
Please login to merge, or discard this patch.
core/services/i18n/LegacyTextDomainOptions.php 1 patch
Indentation   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -14,53 +14,53 @@
 block discarded – undo
14 14
  */
15 15
 class LegacyTextDomainOptions
16 16
 {
17
-    /**
18
-     * @var LoadedTextDomains
19
-     */
20
-    private $loaded_text_domains;
17
+	/**
18
+	 * @var LoadedTextDomains
19
+	 */
20
+	private $loaded_text_domains;
21 21
 
22 22
 
23
-    /**
24
-     * @param LoadedTextDomains|null $loaded_text_domains
25
-     */
26
-    public function __construct(?LoadedTextDomains $loaded_text_domains = null)
27
-    {
28
-        $this->loaded_text_domains = $loaded_text_domains ?? new LoadedTextDomains();
29
-    }
23
+	/**
24
+	 * @param LoadedTextDomains|null $loaded_text_domains
25
+	 */
26
+	public function __construct(?LoadedTextDomains $loaded_text_domains = null)
27
+	{
28
+		$this->loaded_text_domains = $loaded_text_domains ?? new LoadedTextDomains();
29
+	}
30 30
 
31 31
 
32
-    /**
33
-     * attempts to collect all of the ee_lang_check_* options stored in the database
34
-     * and add them to one single option handled by EventEspresso\core\services\i18n\LoadedTextDomains
35
-     *
36
-     * @since   $VID:$
37
-     */
38
-    public function convertToConsolidatedFormat()
39
-    {
40
-        $options = wp_load_alloptions();
41
-        foreach ($options as $slug => $values) {
42
-            if (strpos($slug, 'ee_lang_check_') === 0) {
43
-                // convert something like "ee_lang_check_en_CA_4.10.39.rc.018" to 'en_CA_4.10.39.rc.018'
44
-                $locale_version = str_replace('ee_lang_check_', '', $slug);
45
-                // split 'en_CA_4.10.39.rc.018' into [ 'en', 'CA', '4.10.39.rc.018' ]
46
-                $locale_version = explode('_', $locale_version);
47
-                $locale         = null;
48
-                $version        = null;
49
-                switch (count($locale_version)) {
50
-                    case 3:
51
-                        $locale  = "$locale_version[0]_$locale_version[1]";
52
-                        $version = $locale_version[2];
53
-                        break;
54
-                    case 2:
55
-                        $locale  = $locale_version[0];
56
-                        $version = $locale_version[1];
57
-                        break;
58
-                }
59
-                if ($locale && $version) {
60
-                    $this->loaded_text_domains->versionLoaded($locale, $version);
61
-                    delete_option($slug);
62
-                }
63
-            }
64
-        }
65
-    }
32
+	/**
33
+	 * attempts to collect all of the ee_lang_check_* options stored in the database
34
+	 * and add them to one single option handled by EventEspresso\core\services\i18n\LoadedTextDomains
35
+	 *
36
+	 * @since   $VID:$
37
+	 */
38
+	public function convertToConsolidatedFormat()
39
+	{
40
+		$options = wp_load_alloptions();
41
+		foreach ($options as $slug => $values) {
42
+			if (strpos($slug, 'ee_lang_check_') === 0) {
43
+				// convert something like "ee_lang_check_en_CA_4.10.39.rc.018" to 'en_CA_4.10.39.rc.018'
44
+				$locale_version = str_replace('ee_lang_check_', '', $slug);
45
+				// split 'en_CA_4.10.39.rc.018' into [ 'en', 'CA', '4.10.39.rc.018' ]
46
+				$locale_version = explode('_', $locale_version);
47
+				$locale         = null;
48
+				$version        = null;
49
+				switch (count($locale_version)) {
50
+					case 3:
51
+						$locale  = "$locale_version[0]_$locale_version[1]";
52
+						$version = $locale_version[2];
53
+						break;
54
+					case 2:
55
+						$locale  = $locale_version[0];
56
+						$version = $locale_version[1];
57
+						break;
58
+				}
59
+				if ($locale && $version) {
60
+					$this->loaded_text_domains->versionLoaded($locale, $version);
61
+					delete_option($slug);
62
+				}
63
+			}
64
+		}
65
+	}
66 66
 }
Please login to merge, or discard this patch.
core/helpers/EEH_Form_Fields.helper.php 1 patch
Indentation   +2065 added lines, -2065 removed lines patch added patch discarded remove patch
@@ -27,1058 +27,1058 @@  discard block
 block discarded – undo
27 27
  */
28 28
 class EEH_Form_Fields
29 29
 {
30
-    /**
31
-     *  Generates HTML for the forms used on admin pages
32
-     *
33
-     *
34
-     * @static
35
-     * @access public
36
-     * @param array $input_vars - array of input field details
37
-     *                          format:
38
-     *                          $template_form_fields['field-id'] = array(
39
-     *                          'name' => 'name_attribute',
40
-     *                          'label' => esc_html__('Field Label', 'event_espresso'), //or false
41
-     *                          'input' => 'hidden', //field input type can be 'text', 'select', 'textarea', 'hidden',
42
-     *                          'checkbox', 'wp_editor'
43
-     *                          'type' => 'int', //what "type" the value is (i.e. string, int etc)
44
-     *                          'required' => false, //boolean for whether the field is required
45
-     *                          'validation' => true, //boolean, whether to validate the field (todo)
46
-     *                          'value' => 'some_value_for_field', //what value is used for field
47
-     *                          'format' => '%d', //what format the value is (%d, %f, or %s)
48
-     *                          'db-col' => 'column_in_db' //used to indicate which column the field corresponds with
49
-     *                          in the db
50
-     *                          'options' => optiona, optionb || array('value' => 'label', '') //if the input type is
51
-     *                          "select", this allows you to set the args for the different <option> tags.
52
-     *                          'tabindex' => 1 //this allows you to set the tabindex for the field.
53
-     *                          'append_content' => '' //this allows you to send in html content to append to the
54
-     *                          field.
55
-     *                          )
56
-     * @param array $form_id    - used for defining unique identifiers for the form.
57
-     * @return string
58
-     * @todo   : at some point we can break this down into other static methods to abstract it a bit better.
59
-     */
60
-    public static function get_form_fields($input_vars = [], $form_id = false)
61
-    {
62
-
63
-        if (empty($input_vars)) {
64
-            EE_Error::add_error(
65
-                esc_html__('missing required variables for the form field generator', 'event_espresso'),
66
-                __FILE__,
67
-                __FUNCTION__,
68
-                __LINE__
69
-            );
70
-            return false;
71
-        }
72
-
73
-        $output        = "";
74
-        $inputs        = [];
75
-        $hidden_inputs = [];
76
-
77
-        // cycle thru inputs
78
-        foreach ($input_vars as $input_key => $input_value) {
79
-            $defaults = [
80
-                'append_content' => '',
81
-                'css_class'      => '',
82
-                'cols'           => 80,
83
-                'db-col'         => 'column_in_db',
84
-                'format'         => '%d',
85
-                'input'          => 'hidden',
86
-                'label'          => esc_html__('No label', 'event_espresso'),
87
-                'name'           => $input_key,
88
-                'options'        => [],
89
-                'required'       => false,
90
-                'tabindex'       => 0,
91
-                'rows'           => 10,
92
-                'type'           => 'int',
93
-                'validation'     => true,
94
-                'value'          => 'some_value_for_field',
95
-            ];
96
-
97
-            $input_value = wp_parse_args($input_value, $defaults);
98
-
99
-            $append_content = $input_value['append_content'];
100
-            $css_class      = $input_value['css_class'];
101
-            $cols           = $input_value['cols'];
102
-            $label          = $input_value['label'];
103
-            $name           = $input_value['name'];
104
-            $options        = $input_value['options'];
105
-            $required       = $input_value['required'];
106
-            $tab_index      = $input_value['tabindex'];
107
-            $rows           = $input_value['rows'];
108
-            $type           = $input_value['input'];
109
-            $value          = $input_value['value'];
110
-
111
-            $id    = $form_id ? $form_id . '-' . $input_key : $input_key;
112
-            $class = $required ? 'required ' . $css_class : $css_class;
113
-
114
-            // what type of input are we dealing with ?
115
-            switch ($type) {
116
-                case 'checkbox':
117
-                case 'radio':
118
-                    $field = self::adminMulti($value, $class, $id, $name, $required, $tab_index, $type, 1, $label);
119
-                    $field .= $append_content ?: '';
120
-                    break;
121
-
122
-                case 'hidden':
123
-                    $field           = null;
124
-                    $hidden_inputs[] = self::adminHidden($css_class, $id, $name, $value);
125
-                    break;
126
-
127
-                case 'select':
128
-                    $options = is_array($options) ? $options : explode(',', $options);
129
-                    $field   = self::adminLabel($id, $label, $required);
130
-                    $field   .= self::adminSelect($value, $class, $id, $name, $required, $tab_index, $options);
131
-                    $field   .= $append_content ?: '';
132
-                    break;
133
-
134
-                case 'textarea':
135
-                    $field = self::adminLabel($id, $label, $required);
136
-                    $field .= self::adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value);
137
-                    $field .= $append_content ?: '';
138
-                    break;
139
-
140
-                case 'wp_editor':
141
-                    $label = esc_html($label);
142
-                    $field = "<h4>{$label}</h4>";
143
-                    $field .= $append_content ?: '';
144
-                    $field .= self::adminWpEditor(
145
-                        $class,
146
-                        $id,
147
-                        $name,
148
-                        $rows,
149
-                        $tab_index,
150
-                        $value
151
-                    );
152
-                    break;
153
-
154
-                default:
155
-                    $field = self::adminLabel($id, $label, $required);
156
-                    $field .= self::adminText($class, $id, $name, $required, $tab_index, $value);
157
-                    $field .= $append_content ?: '';
158
-            }
159
-            if ($field) {
160
-                $inputs[] = $field;
161
-            }
162
-        } // end foreach( $input_vars as $input_key => $input_value )
163
-
164
-        if (! empty($inputs)) {
165
-            $glue   = "
30
+	/**
31
+	 *  Generates HTML for the forms used on admin pages
32
+	 *
33
+	 *
34
+	 * @static
35
+	 * @access public
36
+	 * @param array $input_vars - array of input field details
37
+	 *                          format:
38
+	 *                          $template_form_fields['field-id'] = array(
39
+	 *                          'name' => 'name_attribute',
40
+	 *                          'label' => esc_html__('Field Label', 'event_espresso'), //or false
41
+	 *                          'input' => 'hidden', //field input type can be 'text', 'select', 'textarea', 'hidden',
42
+	 *                          'checkbox', 'wp_editor'
43
+	 *                          'type' => 'int', //what "type" the value is (i.e. string, int etc)
44
+	 *                          'required' => false, //boolean for whether the field is required
45
+	 *                          'validation' => true, //boolean, whether to validate the field (todo)
46
+	 *                          'value' => 'some_value_for_field', //what value is used for field
47
+	 *                          'format' => '%d', //what format the value is (%d, %f, or %s)
48
+	 *                          'db-col' => 'column_in_db' //used to indicate which column the field corresponds with
49
+	 *                          in the db
50
+	 *                          'options' => optiona, optionb || array('value' => 'label', '') //if the input type is
51
+	 *                          "select", this allows you to set the args for the different <option> tags.
52
+	 *                          'tabindex' => 1 //this allows you to set the tabindex for the field.
53
+	 *                          'append_content' => '' //this allows you to send in html content to append to the
54
+	 *                          field.
55
+	 *                          )
56
+	 * @param array $form_id    - used for defining unique identifiers for the form.
57
+	 * @return string
58
+	 * @todo   : at some point we can break this down into other static methods to abstract it a bit better.
59
+	 */
60
+	public static function get_form_fields($input_vars = [], $form_id = false)
61
+	{
62
+
63
+		if (empty($input_vars)) {
64
+			EE_Error::add_error(
65
+				esc_html__('missing required variables for the form field generator', 'event_espresso'),
66
+				__FILE__,
67
+				__FUNCTION__,
68
+				__LINE__
69
+			);
70
+			return false;
71
+		}
72
+
73
+		$output        = "";
74
+		$inputs        = [];
75
+		$hidden_inputs = [];
76
+
77
+		// cycle thru inputs
78
+		foreach ($input_vars as $input_key => $input_value) {
79
+			$defaults = [
80
+				'append_content' => '',
81
+				'css_class'      => '',
82
+				'cols'           => 80,
83
+				'db-col'         => 'column_in_db',
84
+				'format'         => '%d',
85
+				'input'          => 'hidden',
86
+				'label'          => esc_html__('No label', 'event_espresso'),
87
+				'name'           => $input_key,
88
+				'options'        => [],
89
+				'required'       => false,
90
+				'tabindex'       => 0,
91
+				'rows'           => 10,
92
+				'type'           => 'int',
93
+				'validation'     => true,
94
+				'value'          => 'some_value_for_field',
95
+			];
96
+
97
+			$input_value = wp_parse_args($input_value, $defaults);
98
+
99
+			$append_content = $input_value['append_content'];
100
+			$css_class      = $input_value['css_class'];
101
+			$cols           = $input_value['cols'];
102
+			$label          = $input_value['label'];
103
+			$name           = $input_value['name'];
104
+			$options        = $input_value['options'];
105
+			$required       = $input_value['required'];
106
+			$tab_index      = $input_value['tabindex'];
107
+			$rows           = $input_value['rows'];
108
+			$type           = $input_value['input'];
109
+			$value          = $input_value['value'];
110
+
111
+			$id    = $form_id ? $form_id . '-' . $input_key : $input_key;
112
+			$class = $required ? 'required ' . $css_class : $css_class;
113
+
114
+			// what type of input are we dealing with ?
115
+			switch ($type) {
116
+				case 'checkbox':
117
+				case 'radio':
118
+					$field = self::adminMulti($value, $class, $id, $name, $required, $tab_index, $type, 1, $label);
119
+					$field .= $append_content ?: '';
120
+					break;
121
+
122
+				case 'hidden':
123
+					$field           = null;
124
+					$hidden_inputs[] = self::adminHidden($css_class, $id, $name, $value);
125
+					break;
126
+
127
+				case 'select':
128
+					$options = is_array($options) ? $options : explode(',', $options);
129
+					$field   = self::adminLabel($id, $label, $required);
130
+					$field   .= self::adminSelect($value, $class, $id, $name, $required, $tab_index, $options);
131
+					$field   .= $append_content ?: '';
132
+					break;
133
+
134
+				case 'textarea':
135
+					$field = self::adminLabel($id, $label, $required);
136
+					$field .= self::adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value);
137
+					$field .= $append_content ?: '';
138
+					break;
139
+
140
+				case 'wp_editor':
141
+					$label = esc_html($label);
142
+					$field = "<h4>{$label}</h4>";
143
+					$field .= $append_content ?: '';
144
+					$field .= self::adminWpEditor(
145
+						$class,
146
+						$id,
147
+						$name,
148
+						$rows,
149
+						$tab_index,
150
+						$value
151
+					);
152
+					break;
153
+
154
+				default:
155
+					$field = self::adminLabel($id, $label, $required);
156
+					$field .= self::adminText($class, $id, $name, $required, $tab_index, $value);
157
+					$field .= $append_content ?: '';
158
+			}
159
+			if ($field) {
160
+				$inputs[] = $field;
161
+			}
162
+		} // end foreach( $input_vars as $input_key => $input_value )
163
+
164
+		if (! empty($inputs)) {
165
+			$glue   = "
166 166
                 </li>
167 167
                 <li>
168 168
                     ";
169
-            $inputs = implode($glue, $inputs);
170
-            $output = "
169
+			$inputs = implode($glue, $inputs);
170
+			$output = "
171 171
             <ul>
172 172
                 <li>
173 173
                 {$inputs}
174 174
                 </li>
175 175
             </ul>
176 176
             ";
177
-        }
178
-        return $output . implode("\n", $hidden_inputs);
179
-    }
180
-
181
-
182
-    /**
183
-     * form_fields_array
184
-     * This utility function assembles form fields from a given structured array with field information.
185
-     * //TODO: This is an alternate generator that we may want to use instead.
186
-     *
187
-     * @param array $fields structured array of fields to assemble in the following format:
188
-     *                      [field_name] => array(
189
-     *                      ['label'] => 'label for field',
190
-     *                      ['labels'] => array('label_1', 'label_2'); //optional - if the field type is a multi select
191
-     *                      type of field you can indicated the labels for each option via this index
192
-     *                      ['extra_desc'] => 'extra description for the field', //optional
193
-     *                      ['type'] => 'textarea'|'text'|'wp_editor'|'checkbox'|'radio'|'hidden'|'select', //defaults
194
-     *                      to text
195
-     *                      ['value'] => 'value that goes in the field', //(if multi then this is an array of values
196
-     *                      and the 'default' paramater will be used for what is selected)
197
-     *                      ['default'] => 'default if the field type is multi (i.e. select or radios or checkboxes)',
198
-     *                      ['class'] => 'name-of-class(es)-for-input',
199
-     *                      ['classes'] => array('class_1', 'class_2'); //optional - if the field type is a multi
200
-     *                      select type of field you can indicate the css class for each option via this index.
201
-     *                      ['id'] => 'css-id-for-input') //defaults to 'field_name'
202
-     *                      ['unique_id'] => 1 //defaults to empty string.  This is useful for when the fields
203
-     *                      generated are going to be used in a loop and you want to make sure that the field
204
-     *                      identifiers are unique from each other.
205
-     *                      ['dimensions'] => array(100,300), //defaults to empty array.  This is used by field types
206
-     *                      such as textarea to indicate cols/rows.
207
-     *                      ['tabindex'] => '' //this allows you to set the tabindex for the field.
208
-     *                      ['wpeditor_args'] => array() //if the type of field is wpeditor then this can optionally
209
-     *                      contain an array of arguments for the editor setup.
210
-     *
211
-     * @return array         an array of inputs for form indexed by field name, and in the following structure:
212
-     *     [field_name] => array( 'label' => '{label_html}', 'field' => '{input_html}'
213
-     */
214
-    public static function get_form_fields_array($fields)
215
-    {
216
-
217
-        $form_fields = [];
218
-        $fields      = (array) $fields;
219
-
220
-        foreach ($fields as $field_name => $field_atts) {
221
-            // defaults:
222
-            $defaults = [
223
-                'class'         => '',
224
-                'classes'       => '',
225
-                'default'       => '',
226
-                'dimensions'    => ['10', '5'],
227
-                'extra_desc'    => '',
228
-                'id'            => $field_name,
229
-                'label'         => '',
230
-                'labels'        => '',
231
-                'required'      => false,
232
-                'tabindex'      => 0,
233
-                'type'          => 'text',
234
-                'unique_id'     => '',
235
-                'value'         => '',
236
-                'wpeditor_args' => [],
237
-            ];
238
-            // merge defaults with passed arguments
239
-            $_fields = wp_parse_args($field_atts, $defaults);
240
-
241
-            $class          = $_fields['class'];
242
-            $classes        = $_fields['classes'];
243
-            $default        = $_fields['default'];
244
-            $dims           = $_fields['dimensions'];
245
-            $extra_desc     = $_fields['extra_desc'];
246
-            $id             = $_fields['id'];
247
-            $label          = $_fields['label'];
248
-            $labels         = $_fields['labels'];
249
-            $required       = $_fields['required'];
250
-            $tab_index      = $_fields['tabindex'];
251
-            $type           = $_fields['type'];
252
-            $unique_id      = $_fields['unique_id'];
253
-            $value          = $_fields['value'];
254
-            $wp_editor_args = $_fields['wpeditor_args'];
255
-
256
-            // generate label
257
-            $label = ! empty($label) ? self::adminLabel($id, $label, $required) : '';
258
-            // generate field name
259
-            $name = ! empty($unique_id) ? $field_name . '[' . $unique_id . ']' : $field_name;
260
-
261
-            // we determine what we're building based on the type
262
-            switch ($type) {
263
-                case 'checkbox':
264
-                case 'radio':
265
-                    if (is_array($value)) {
266
-                        $c_input = '';
267
-                        foreach ($value as $key => $val) {
268
-                            $c_input .= self::adminMulti(
269
-                                $default,
270
-                                isset($classes[ $key ]) ? $classes[ $key ] : '',
271
-                                $field_name . '_' . $value,
272
-                                $name,
273
-                                $required,
274
-                                $tab_index,
275
-                                $type,
276
-                                $val,
277
-                                isset($labels[ $key ]) ? $labels[ $key ] : ''
278
-                            );
279
-                        }
280
-                        $field = $c_input;
281
-                    } else {
282
-                        $field = self::adminMulti(
283
-                            $default,
284
-                            $class,
285
-                            $id,
286
-                            $name,
287
-                            $required,
288
-                            $tab_index,
289
-                            $type,
290
-                            $value,
291
-                            $_fields['label']
292
-                        );
293
-                    }
294
-                    break;
295
-
296
-                case 'hidden':
297
-                    $field = self::adminHidden($class, $id, $name, $value);
298
-                    break;
299
-
300
-                case 'select':
301
-                    $options = [];
302
-                    foreach ($value as $key => $val) {
303
-                        $options[ $val ] = isset($labels[ $key ]) ? $labels[ $key ] : '';
304
-                    }
305
-                    $field = self::adminSelect($default, $class, $id, $name, $required, $tab_index, $options);
306
-                    break;
307
-
308
-                case 'textarea':
309
-                    $field =
310
-                        self::adminTextarea($class, $dims[0], $id, $name, $required, $dims[1], $tab_index, $value);
311
-                    break;
312
-
313
-                case 'wp_editor':
314
-                    $field = self::adminWpEditor(
315
-                        $class,
316
-                        $_fields['id'],
317
-                        $name,
318
-                        $dims[1],
319
-                        $tab_index,
320
-                        $value,
321
-                        $wp_editor_args
322
-                    );
323
-                    break;
324
-
325
-                default:
326
-                    $field = self::adminText($class, $id, $name, $required, $tab_index, $value);
327
-            }
328
-
329
-            $form_fields[ $field_name ] = ['label' => $label, 'field' => $field . $extra_desc];
330
-        }
331
-
332
-        return $form_fields;
333
-    }
334
-
335
-
336
-    /**
337
-     * @param string $class
338
-     * @param string $id
339
-     * @param string $name
340
-     * @param string $value
341
-     * @return string
342
-     * @since   4.10.14.p
343
-     */
344
-    private static function adminHidden($class, $id, $name, $value)
345
-    {
346
-        $id    = esc_attr($id);
347
-        $name  = esc_attr($name);
348
-        $class = esc_attr($class);
349
-        return "
177
+		}
178
+		return $output . implode("\n", $hidden_inputs);
179
+	}
180
+
181
+
182
+	/**
183
+	 * form_fields_array
184
+	 * This utility function assembles form fields from a given structured array with field information.
185
+	 * //TODO: This is an alternate generator that we may want to use instead.
186
+	 *
187
+	 * @param array $fields structured array of fields to assemble in the following format:
188
+	 *                      [field_name] => array(
189
+	 *                      ['label'] => 'label for field',
190
+	 *                      ['labels'] => array('label_1', 'label_2'); //optional - if the field type is a multi select
191
+	 *                      type of field you can indicated the labels for each option via this index
192
+	 *                      ['extra_desc'] => 'extra description for the field', //optional
193
+	 *                      ['type'] => 'textarea'|'text'|'wp_editor'|'checkbox'|'radio'|'hidden'|'select', //defaults
194
+	 *                      to text
195
+	 *                      ['value'] => 'value that goes in the field', //(if multi then this is an array of values
196
+	 *                      and the 'default' paramater will be used for what is selected)
197
+	 *                      ['default'] => 'default if the field type is multi (i.e. select or radios or checkboxes)',
198
+	 *                      ['class'] => 'name-of-class(es)-for-input',
199
+	 *                      ['classes'] => array('class_1', 'class_2'); //optional - if the field type is a multi
200
+	 *                      select type of field you can indicate the css class for each option via this index.
201
+	 *                      ['id'] => 'css-id-for-input') //defaults to 'field_name'
202
+	 *                      ['unique_id'] => 1 //defaults to empty string.  This is useful for when the fields
203
+	 *                      generated are going to be used in a loop and you want to make sure that the field
204
+	 *                      identifiers are unique from each other.
205
+	 *                      ['dimensions'] => array(100,300), //defaults to empty array.  This is used by field types
206
+	 *                      such as textarea to indicate cols/rows.
207
+	 *                      ['tabindex'] => '' //this allows you to set the tabindex for the field.
208
+	 *                      ['wpeditor_args'] => array() //if the type of field is wpeditor then this can optionally
209
+	 *                      contain an array of arguments for the editor setup.
210
+	 *
211
+	 * @return array         an array of inputs for form indexed by field name, and in the following structure:
212
+	 *     [field_name] => array( 'label' => '{label_html}', 'field' => '{input_html}'
213
+	 */
214
+	public static function get_form_fields_array($fields)
215
+	{
216
+
217
+		$form_fields = [];
218
+		$fields      = (array) $fields;
219
+
220
+		foreach ($fields as $field_name => $field_atts) {
221
+			// defaults:
222
+			$defaults = [
223
+				'class'         => '',
224
+				'classes'       => '',
225
+				'default'       => '',
226
+				'dimensions'    => ['10', '5'],
227
+				'extra_desc'    => '',
228
+				'id'            => $field_name,
229
+				'label'         => '',
230
+				'labels'        => '',
231
+				'required'      => false,
232
+				'tabindex'      => 0,
233
+				'type'          => 'text',
234
+				'unique_id'     => '',
235
+				'value'         => '',
236
+				'wpeditor_args' => [],
237
+			];
238
+			// merge defaults with passed arguments
239
+			$_fields = wp_parse_args($field_atts, $defaults);
240
+
241
+			$class          = $_fields['class'];
242
+			$classes        = $_fields['classes'];
243
+			$default        = $_fields['default'];
244
+			$dims           = $_fields['dimensions'];
245
+			$extra_desc     = $_fields['extra_desc'];
246
+			$id             = $_fields['id'];
247
+			$label          = $_fields['label'];
248
+			$labels         = $_fields['labels'];
249
+			$required       = $_fields['required'];
250
+			$tab_index      = $_fields['tabindex'];
251
+			$type           = $_fields['type'];
252
+			$unique_id      = $_fields['unique_id'];
253
+			$value          = $_fields['value'];
254
+			$wp_editor_args = $_fields['wpeditor_args'];
255
+
256
+			// generate label
257
+			$label = ! empty($label) ? self::adminLabel($id, $label, $required) : '';
258
+			// generate field name
259
+			$name = ! empty($unique_id) ? $field_name . '[' . $unique_id . ']' : $field_name;
260
+
261
+			// we determine what we're building based on the type
262
+			switch ($type) {
263
+				case 'checkbox':
264
+				case 'radio':
265
+					if (is_array($value)) {
266
+						$c_input = '';
267
+						foreach ($value as $key => $val) {
268
+							$c_input .= self::adminMulti(
269
+								$default,
270
+								isset($classes[ $key ]) ? $classes[ $key ] : '',
271
+								$field_name . '_' . $value,
272
+								$name,
273
+								$required,
274
+								$tab_index,
275
+								$type,
276
+								$val,
277
+								isset($labels[ $key ]) ? $labels[ $key ] : ''
278
+							);
279
+						}
280
+						$field = $c_input;
281
+					} else {
282
+						$field = self::adminMulti(
283
+							$default,
284
+							$class,
285
+							$id,
286
+							$name,
287
+							$required,
288
+							$tab_index,
289
+							$type,
290
+							$value,
291
+							$_fields['label']
292
+						);
293
+					}
294
+					break;
295
+
296
+				case 'hidden':
297
+					$field = self::adminHidden($class, $id, $name, $value);
298
+					break;
299
+
300
+				case 'select':
301
+					$options = [];
302
+					foreach ($value as $key => $val) {
303
+						$options[ $val ] = isset($labels[ $key ]) ? $labels[ $key ] : '';
304
+					}
305
+					$field = self::adminSelect($default, $class, $id, $name, $required, $tab_index, $options);
306
+					break;
307
+
308
+				case 'textarea':
309
+					$field =
310
+						self::adminTextarea($class, $dims[0], $id, $name, $required, $dims[1], $tab_index, $value);
311
+					break;
312
+
313
+				case 'wp_editor':
314
+					$field = self::adminWpEditor(
315
+						$class,
316
+						$_fields['id'],
317
+						$name,
318
+						$dims[1],
319
+						$tab_index,
320
+						$value,
321
+						$wp_editor_args
322
+					);
323
+					break;
324
+
325
+				default:
326
+					$field = self::adminText($class, $id, $name, $required, $tab_index, $value);
327
+			}
328
+
329
+			$form_fields[ $field_name ] = ['label' => $label, 'field' => $field . $extra_desc];
330
+		}
331
+
332
+		return $form_fields;
333
+	}
334
+
335
+
336
+	/**
337
+	 * @param string $class
338
+	 * @param string $id
339
+	 * @param string $name
340
+	 * @param string $value
341
+	 * @return string
342
+	 * @since   4.10.14.p
343
+	 */
344
+	private static function adminHidden($class, $id, $name, $value)
345
+	{
346
+		$id    = esc_attr($id);
347
+		$name  = esc_attr($name);
348
+		$class = esc_attr($class);
349
+		return "
350 350
         <input name='{$name}' type='hidden' id='{$id}' class='{$class}' value='{$value}' />";
351
-    }
352
-
353
-
354
-    /**
355
-     * @param string $id
356
-     * @param string $label
357
-     * @param string $required
358
-     * @return string
359
-     * @since   4.10.14.p
360
-     */
361
-    private static function adminLabel($id, $label, $required)
362
-    {
363
-        $id       = esc_attr($id);
364
-        $label    = esc_html($label);
365
-        $required = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? " <span>*</span>" : '';
366
-        return "<label for='{$id}'>{$label}{$required}</label>";
367
-    }
368
-
369
-
370
-    /**
371
-     * @param string $default
372
-     * @param string $class
373
-     * @param string $id
374
-     * @param string $name
375
-     * @param string $required
376
-     * @param int    $tab_index
377
-     * @param string $type
378
-     * @param string $value
379
-     * @param string $label
380
-     * @return string
381
-     * @since   4.10.14.p
382
-     */
383
-    private static function adminMulti($default, $class, $id, $name, $required, $tab_index, $type, $value, $label = '')
384
-    {
385
-        $id        = esc_attr($id);
386
-        $name      = esc_attr($name);
387
-        $class     = esc_attr($class);
388
-        $tab_index = absint($tab_index);
389
-        $checked   = ! empty($default) && $default == $value ? 'checked ' : '';
390
-        $required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
391
-        $input     = "
351
+	}
352
+
353
+
354
+	/**
355
+	 * @param string $id
356
+	 * @param string $label
357
+	 * @param string $required
358
+	 * @return string
359
+	 * @since   4.10.14.p
360
+	 */
361
+	private static function adminLabel($id, $label, $required)
362
+	{
363
+		$id       = esc_attr($id);
364
+		$label    = esc_html($label);
365
+		$required = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? " <span>*</span>" : '';
366
+		return "<label for='{$id}'>{$label}{$required}</label>";
367
+	}
368
+
369
+
370
+	/**
371
+	 * @param string $default
372
+	 * @param string $class
373
+	 * @param string $id
374
+	 * @param string $name
375
+	 * @param string $required
376
+	 * @param int    $tab_index
377
+	 * @param string $type
378
+	 * @param string $value
379
+	 * @param string $label
380
+	 * @return string
381
+	 * @since   4.10.14.p
382
+	 */
383
+	private static function adminMulti($default, $class, $id, $name, $required, $tab_index, $type, $value, $label = '')
384
+	{
385
+		$id        = esc_attr($id);
386
+		$name      = esc_attr($name);
387
+		$class     = esc_attr($class);
388
+		$tab_index = absint($tab_index);
389
+		$checked   = ! empty($default) && $default == $value ? 'checked ' : '';
390
+		$required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
391
+		$input     = "
392 392
         <input name='{$name}[]' type='{$type}' id='{$id}' class='{$class}' value='{$value}' {$checked} {$required} tabindex='{$tab_index}'/>";
393
-        if ($label === '') {
394
-            return $input;
395
-        }
396
-        $label = esc_html($label);
397
-        $label_class = self::appendInputSizeClass('', $label);
398
-        $label_class = $label_class ? ' class="' . $label_class . '"' : '';
399
-        return "
393
+		if ($label === '') {
394
+			return $input;
395
+		}
396
+		$label = esc_html($label);
397
+		$label_class = self::appendInputSizeClass('', $label);
398
+		$label_class = $label_class ? ' class="' . $label_class . '"' : '';
399
+		return "
400 400
         <label for='$id'{$label_class}>
401 401
             {$input}
402 402
             {$label}
403 403
         </label>";
404
-    }
405
-
406
-
407
-    /**
408
-     * @param string $default
409
-     * @param string $class
410
-     * @param string $id
411
-     * @param string $name
412
-     * @param string $required
413
-     * @param int    $tab_index
414
-     * @param array  $options
415
-     * @return string
416
-     * @since   4.10.14.p
417
-     */
418
-    private static function adminSelect($default, $class, $id, $name, $required, $tab_index, $options = [])
419
-    {
420
-        $options_array = [];
421
-        foreach ($options as $value => $label) {
422
-            $selected        = ! empty($default) && $default == $value ? 'selected' : '';
423
-            $value           = esc_attr($value);
424
-            $label           = wp_strip_all_tags($label);
425
-            $options_array[] = "<option value='{$value}' {$selected}>{$label}</option>";
426
-        }
427
-        $options_html = implode("\n", $options_array);
428
-        $id           = esc_attr($id);
429
-        $name         = esc_attr($name);
430
-        $class        = esc_attr($class);
431
-        $tab_index    = absint($tab_index);
432
-        $required     = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
433
-
434
-        $class = self::appendInputSizeClass($class, $options);
435
-
436
-        return "
404
+	}
405
+
406
+
407
+	/**
408
+	 * @param string $default
409
+	 * @param string $class
410
+	 * @param string $id
411
+	 * @param string $name
412
+	 * @param string $required
413
+	 * @param int    $tab_index
414
+	 * @param array  $options
415
+	 * @return string
416
+	 * @since   4.10.14.p
417
+	 */
418
+	private static function adminSelect($default, $class, $id, $name, $required, $tab_index, $options = [])
419
+	{
420
+		$options_array = [];
421
+		foreach ($options as $value => $label) {
422
+			$selected        = ! empty($default) && $default == $value ? 'selected' : '';
423
+			$value           = esc_attr($value);
424
+			$label           = wp_strip_all_tags($label);
425
+			$options_array[] = "<option value='{$value}' {$selected}>{$label}</option>";
426
+		}
427
+		$options_html = implode("\n", $options_array);
428
+		$id           = esc_attr($id);
429
+		$name         = esc_attr($name);
430
+		$class        = esc_attr($class);
431
+		$tab_index    = absint($tab_index);
432
+		$required     = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
433
+
434
+		$class = self::appendInputSizeClass($class, $options);
435
+
436
+		return "
437 437
         <select name='{$name}' id='{$id}' class='{$class}' {$required} tabindex='{$tab_index}'>
438 438
             {$options_html}
439 439
         </select>";
440
-    }
441
-
442
-
443
-    /**
444
-     * @param string $class
445
-     * @param string $id
446
-     * @param string $name
447
-     * @param string $required
448
-     * @param int    $tab_index
449
-     * @param string $value
450
-     * @return string
451
-     * @since   4.10.14.p
452
-     */
453
-    private static function adminText($class, $id, $name, $required, $tab_index, $value)
454
-    {
455
-        $id        = esc_attr($id);
456
-        $name      = esc_attr($name);
457
-        $class     = esc_attr($class);
458
-        $tab_index = absint($tab_index);
459
-        $required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
460
-        $class     = self::appendInputSizeClass($class, $value);
461
-        $value     = esc_attr($value);
462
-        return "
440
+	}
441
+
442
+
443
+	/**
444
+	 * @param string $class
445
+	 * @param string $id
446
+	 * @param string $name
447
+	 * @param string $required
448
+	 * @param int    $tab_index
449
+	 * @param string $value
450
+	 * @return string
451
+	 * @since   4.10.14.p
452
+	 */
453
+	private static function adminText($class, $id, $name, $required, $tab_index, $value)
454
+	{
455
+		$id        = esc_attr($id);
456
+		$name      = esc_attr($name);
457
+		$class     = esc_attr($class);
458
+		$tab_index = absint($tab_index);
459
+		$required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
460
+		$class     = self::appendInputSizeClass($class, $value);
461
+		$value     = esc_attr($value);
462
+		return "
463 463
         <input name='{$name}' type='text' id='{$id}' class='{$class}' value='{$value}' {$required} tabindex='{$tab_index}'/>";
464
-    }
465
-
466
-
467
-    /**
468
-     * @param string $class
469
-     * @param int    $cols
470
-     * @param string $id
471
-     * @param string $name
472
-     * @param string $required
473
-     * @param int    $rows
474
-     * @param int    $tab_index
475
-     * @param string $value
476
-     * @return string
477
-     * @since   4.10.14.p
478
-     */
479
-    private static function adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value)
480
-    {
481
-        $id        = esc_attr($id);
482
-        $name      = esc_attr($name);
483
-        $class     = esc_attr($class);
484
-        $cols      = absint($cols);
485
-        $rows      = absint($rows);
486
-        $value     = esc_textarea($value);
487
-        $tab_index = absint($tab_index);
488
-        $required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
489
-        return "
464
+	}
465
+
466
+
467
+	/**
468
+	 * @param string $class
469
+	 * @param int    $cols
470
+	 * @param string $id
471
+	 * @param string $name
472
+	 * @param string $required
473
+	 * @param int    $rows
474
+	 * @param int    $tab_index
475
+	 * @param string $value
476
+	 * @return string
477
+	 * @since   4.10.14.p
478
+	 */
479
+	private static function adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value)
480
+	{
481
+		$id        = esc_attr($id);
482
+		$name      = esc_attr($name);
483
+		$class     = esc_attr($class);
484
+		$cols      = absint($cols);
485
+		$rows      = absint($rows);
486
+		$value     = esc_textarea($value);
487
+		$tab_index = absint($tab_index);
488
+		$required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
489
+		return "
490 490
         <textarea name='{$name}' id='{$id}' class='{$class}' rows='{$rows}' cols='{$cols}' {$required} tabindex='{$tab_index}'>{$value}</textarea>";
491
-    }
492
-
493
-
494
-    /**
495
-     * @param string $class
496
-     * @param string $id
497
-     * @param string $name
498
-     * @param int    $rows
499
-     * @param int    $tab_index
500
-     * @param string $value
501
-     * @param array  $wp_editor_args
502
-     * @return false|string
503
-     * @since   4.10.14.p
504
-     */
505
-    private static function adminWpEditor($class, $id, $name, $rows, $tab_index, $value, $wp_editor_args = [])
506
-    {
507
-        $editor_settings = $wp_editor_args + [
508
-                'textarea_name' => esc_attr($name),
509
-                'textarea_rows' => absint($rows),
510
-                'editor_class'  => esc_attr($class),
511
-                'tabindex'      => absint($tab_index),
512
-            ];
513
-        ob_start();
514
-        wp_editor($value, esc_attr($id), $editor_settings);
515
-        return ob_get_clean();
516
-    }
517
-
518
-
519
-    /**
520
-     * espresso admin page select_input
521
-     * Turns an array into a select fields
522
-     *
523
-     * @static
524
-     * @access public
525
-     * @param string  $name       field name
526
-     * @param array   $values     option values, numbered array starting at 0, where each value is an array with a key
527
-     *                            'text' (meaning text to display' and 'id' (meaning the internal value) eg:
528
-     *                            array(1=>array('text'=>'Monday','id'=>1),2=>array('text'=>'Tuesday','id'=>2)...). or
529
-     *                            as an array of key-value pairs, where the key is to be used for the select input's
530
-     *                            name, and the value will be the text shown to the user.  Optionally you can also
531
-     *                            include an additional key of "class" which will add a specific class to the option
532
-     *                            for that value.
533
-     * @param string  $default    default value
534
-     * @param string  $parameters extra parameters
535
-     * @param string  $class      css class
536
-     * @param boolean $autosize   whether to autosize the select or not
537
-     * @return string              html string for the select input
538
-     */
539
-    public static function select_input(
540
-        $name,
541
-        $values,
542
-        $default = '',
543
-        $parameters = '',
544
-        $class = '',
545
-        $autosize = true
546
-    ) {
547
-        // if $values was submitted in the wrong format, convert it over
548
-        if (! empty($values) && (! array_key_exists(0, $values) || ! is_array($values[0]))) {
549
-            $converted_values = [];
550
-            foreach ($values as $id => $text) {
551
-                $converted_values[] = ['id' => $id, 'text' => $text];
552
-            }
553
-            $values = $converted_values;
554
-        }
555
-
556
-        $field =
557
-            '<select id="' . EEH_Formatter::ee_tep_output_string($name)
558
-            . '" name="' . EEH_Formatter::ee_tep_output_string($name)
559
-            . '"';
560
-
561
-        if (EEH_Formatter::ee_tep_not_null($parameters)) {
562
-            $field .= ' ' . $parameters;
563
-        }
564
-        $class = $autosize ? self::appendInputSizeClass($class, $values) : '';
565
-
566
-        $field .= ' class="' . $class . '">';
567
-
568
-        if (empty($default) && isset($GLOBALS[ $name ])) {
569
-            $default = stripslashes($GLOBALS[ $name ]);
570
-        }
571
-
572
-        $field .= self::selectInputOption($values, $default);
573
-        $field .= '</select>';
574
-
575
-        return $field;
576
-    }
577
-
578
-
579
-    private static function selectInputOption(array $values, $default): string
580
-    {
581
-        if (isset($values['id'], $values['text'])) {
582
-            $id = is_scalar($values['id']) ? $values['id'] : '';
583
-            $text = is_scalar($values['text']) ? $values['text'] : '';
584
-            $selected = $default == $values['id'] ? ' selected = "selected"' : '';
585
-            $html_class = isset($values['class']) ? ' class="' . $values['class'] . '"' : '';
586
-            return "<option value='{$id}'{$selected}{$html_class}>{$text}</option>";
587
-        }
588
-        $options = '';
589
-        foreach ($values as $value) {
590
-            $options .= self::selectInputOption($value, $default);
591
-        }
592
-        return $options;
593
-    }
594
-
595
-
596
-    /**
597
-     * @param mixed $value
598
-     * @return int
599
-     * @since   $VID:$
600
-     */
601
-    private static function getInputValueLength($value): int
602
-    {
603
-        if ($value instanceof EE_Question_Option) {
604
-            return self::getInputValueLength($value->desc());
605
-        }
606
-        if (is_array($value)) {
607
-            $chars = 0;
608
-            foreach ($value as $val) {
609
-                $length = self::getInputValueLength($val);
610
-                $chars = max($length, $chars);
611
-            }
612
-            return $chars;
613
-        }
614
-        // not a primitive? return something big
615
-        if (! is_scalar($value)) {
616
-            return 500;
617
-        }
618
-        return strlen((string) $value);
619
-    }
620
-
621
-
622
-    /**
623
-     * @param string $class
624
-     * @param mixed $value
625
-     * @return string
626
-     * @since   $VID:$
627
-     */
628
-    private static function appendInputSizeClass(string $class, $value): string
629
-    {
630
-        if (strpos($class, 'ee-input-width--') !== false) {
631
-            return $class;
632
-        }
633
-        $chars = self::getInputValueLength($value);
634
-        if ($chars && $chars < 5) {
635
-            return "{$class} ee-input-width--tiny";
636
-        }
637
-        if ($chars && $chars < 25) {
638
-            return "{$class} ee-input-width--small";
639
-        }
640
-        if ($chars && $chars > 100) {
641
-            return "{$class} ee-input-width--big";
642
-        }
643
-        return "{$class} ee-input-width--reg";
644
-    }
645
-
646
-
647
-    /**
648
-     * generate_question_groups_html
649
-     *
650
-     * @param array  $question_groups
651
-     * @param string $group_wrapper
652
-     * @return string HTML
653
-     * @throws EE_Error
654
-     * @throws ReflectionException
655
-     */
656
-    public static function generate_question_groups_html($question_groups = [], $group_wrapper = 'fieldset')
657
-    {
658
-
659
-        $html                            = '';
660
-        $before_question_group_questions =
661
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
662
-        $after_question_group_questions  =
663
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
664
-
665
-        if (! empty($question_groups)) {
666
-            // loop thru question groups
667
-            foreach ($question_groups as $QSG) {
668
-                // check that questions exist
669
-                if (! empty($QSG['QSG_questions'])) {
670
-                    // use fieldsets
671
-                    $html .= "\n\t"
672
-                             . '<'
673
-                             . $group_wrapper
674
-                             . ' class="espresso-question-group-wrap" id="'
675
-                             . $QSG['QSG_identifier']
676
-                             . '">';
677
-                    // group_name
678
-                    $html .= $QSG['QSG_show_group_name']
679
-                        ? "\n\t\t"
680
-                          . '<h5 class="espresso-question-group-title-h5 section-title">'
681
-                          . self::prep_answer($QSG['QSG_name'])
682
-                          . '</h5>'
683
-                        : '';
684
-                    // group_desc
685
-                    $html .= $QSG['QSG_show_group_desc'] && ! empty($QSG['QSG_desc'])
686
-                        ? '<div class="espresso-question-group-desc-pg">'
687
-                          . self::prep_answer($QSG['QSG_desc'])
688
-                          . '</div>'
689
-                        : '';
690
-
691
-                    $html .= $before_question_group_questions;
692
-                    // loop thru questions
693
-                    foreach ($QSG['QSG_questions'] as $question) {
694
-                        $QFI  = new EE_Question_Form_Input(
695
-                            $question['qst_obj'],
696
-                            $question['ans_obj'],
697
-                            $question
698
-                        );
699
-                        $html .= self::generate_form_input($QFI);
700
-                    }
701
-                    $html .= $after_question_group_questions;
702
-                    $html .= "\n\t" . '</' . $group_wrapper . '>';
703
-                }
704
-            }
705
-        }
706
-
707
-        return $html;
708
-    }
709
-
710
-
711
-    /**
712
-     * generate_question_groups_html
713
-     *
714
-     * @param array  $question_groups
715
-     * @param array  $q_meta
716
-     * @param bool   $from_admin
717
-     * @param string $group_wrapper
718
-     * @return string HTML
719
-     * @throws EE_Error
720
-     * @throws ReflectionException
721
-     */
722
-    public static function generate_question_groups_html2(
723
-        $question_groups = [],
724
-        $q_meta = [],
725
-        $from_admin = false,
726
-        $group_wrapper = 'fieldset'
727
-    ) {
728
-
729
-        $html                            = '';
730
-        $before_question_group_questions =
731
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
732
-        $after_question_group_questions  =
733
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
734
-
735
-        $default_q_meta = [
736
-            'att_nmbr'    => 1,
737
-            'ticket_id'   => '',
738
-            'input_name'  => '',
739
-            'input_id'    => '',
740
-            'input_class' => '',
741
-        ];
742
-        $q_meta         = array_merge($default_q_meta, $q_meta);
743
-
744
-        if (! empty($question_groups)) {
745
-            // loop thru question groups
746
-            foreach ($question_groups as $QSG) {
747
-                if ($QSG instanceof EE_Question_Group) {
748
-                    // check that questions exist
749
-
750
-                    $where = ['QST_deleted' => 0];
751
-                    if (! $from_admin) {
752
-                        $where['QST_admin_only'] = 0;
753
-                    }
754
-                    $questions =
755
-                        $QSG->questions([$where, 'order_by' => ['Question_Group_Question.QGQ_order' => 'ASC']]);
756
-                    if (! empty($questions)) {
757
-                        // use fieldsets
758
-                        $html .= "\n\t"
759
-                                 . '<' . $group_wrapper . ' class="espresso-question-group-wrap" '
760
-                                 . 'id="' . $QSG->get('QSG_identifier') . '">';
761
-                        // group_name
762
-                        if ($QSG->show_group_name()) {
763
-                            $html .= "\n\t\t"
764
-                                     . '<h5 class="espresso-question-group-title-h5 section-title">'
765
-                                     . $QSG->get_pretty('QSG_name')
766
-                                     . '</h5>';
767
-                        }
768
-                        // group_desc
769
-                        if ($QSG->show_group_desc()) {
770
-                            $html .= '<div class="espresso-question-group-desc-pg">'
771
-                                     . $QSG->get_pretty('QSG_desc')
772
-                                     . '</div>';
773
-                        }
774
-
775
-                        $html .= $before_question_group_questions;
776
-                        // loop thru questions
777
-                        foreach ($questions as $QST) {
778
-                            $qstn_id = $QST->is_system_question() ? $QST->system_ID() : $QST->ID();
779
-
780
-                            $answer = null;
781
-
782
-                            /** @var RequestInterface $request */
783
-                            $request      = LoaderFactory::getLoader()->getShared(RequestInterface::class);
784
-                            $request_qstn = $request->getRequestParam('qstn', [], 'string', true);
785
-                            if (! empty($request_qstn) && isset($q_meta['input_id']) && isset($q_meta['att_nmbr'])) {
786
-                                // check for answer in $request_qstn in case we are reprocessing a form after an error
787
-                                if (isset($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])) {
788
-                                    $answer = is_array($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])
789
-                                        ? $request_qstn[ $q_meta['input_id'] ][ $qstn_id ]
790
-                                        : sanitize_text_field($request_qstn[ $q_meta['input_id'] ][ $qstn_id ]);
791
-                                }
792
-                            } elseif (isset($q_meta['attendee']) && $q_meta['attendee']) {
793
-                                // attendee data from the session
794
-                                $answer =
795
-                                    isset($q_meta['attendee'][ $qstn_id ]) ? $q_meta['attendee'][ $qstn_id ] : null;
796
-                            }
797
-
798
-
799
-                            $QFI  = new EE_Question_Form_Input(
800
-                                $QST,
801
-                                EE_Answer::new_instance(
802
-                                    [
803
-                                        'ANS_ID'    => 0,
804
-                                        'QST_ID'    => 0,
805
-                                        'REG_ID'    => 0,
806
-                                        'ANS_value' => $answer,
807
-                                    ]
808
-                                ),
809
-                                $q_meta
810
-                            );
811
-                            $html .= self::generate_form_input($QFI);
812
-                        }
813
-                        $html .= $after_question_group_questions;
814
-                        $html .= "\n\t" . '</' . $group_wrapper . '>';
815
-                    }
816
-                }
817
-            }
818
-        }
819
-        return $html;
820
-    }
821
-
822
-
823
-    /**
824
-     * generate_form_input
825
-     *
826
-     * @param EE_Question_Form_Input $QFI
827
-     * @return string HTML
828
-     * @throws EE_Error
829
-     * @throws ReflectionException
830
-     */
831
-    public static function generate_form_input(EE_Question_Form_Input $QFI)
832
-    {
833
-        if (isset($QFI->QST_admin_only) && $QFI->QST_admin_only && ! is_admin()) {
834
-            return '';
835
-        }
836
-        /** @var RequestInterface $request */
837
-        $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
838
-
839
-        $QFI = self::_load_system_dropdowns($QFI);
840
-        $QFI = self::_load_specialized_dropdowns($QFI);
841
-
842
-        // we also need to verify
843
-
844
-        $display_text = $QFI->get('QST_display_text');
845
-        $input_name   = $QFI->get('QST_input_name');
846
-        $answer       = $request->getRequestParam($input_name, $QFI->get('ANS_value'));
847
-        $input_id     = $QFI->get('QST_input_id');
848
-        $input_class  = $QFI->get('QST_input_class');
849
-        //      $disabled = $QFI->get('QST_disabled') ? ' disabled="disabled"' : '';
850
-        $disabled          = $QFI->get('QST_disabled');
851
-        $required_label    = apply_filters(' FHEE__EEH_Form_Fields__generate_form_input__required_label', '<em>*</em>');
852
-        $QST_required      = $QFI->get('QST_required');
853
-        $required          =
854
-            $QST_required
855
-                ? ['label' => $required_label, 'class' => 'required needs-value', 'title' => $QST_required]
856
-                : [];
857
-        $use_html_entities = $QFI->get_meta('htmlentities');
858
-        $required_text     =
859
-            $QFI->get('QST_required_text') != ''
860
-                ? $QFI->get('QST_required_text')
861
-                : esc_html__('This field is required', 'event_espresso');
862
-        $required_text     = $QST_required
863
-            ? "\n\t\t\t"
864
-              . '<div class="required-text hidden">'
865
-              . self::prep_answer($required_text, $use_html_entities)
866
-              . '</div>'
867
-            : '';
868
-        $label_class       = $QFI->get('label_class');
869
-        $label_class       = $label_class ? "{$label_class} espresso-form-input-lbl" : 'espresso-form-input-lbl';
870
-        $QST_options       = $QFI->options(true, $answer);
871
-        $options           = is_array($QST_options) ? self::prep_answer_options($QST_options) : [];
872
-        $system_ID         = $QFI->get('QST_system');
873
-        $label_b4          = $QFI->get_meta('label_b4');
874
-        $use_desc_4_label  = $QFI->get_meta('use_desc_4_label');
875
-        $add_mobile_label  = $QFI->get_meta('add_mobile_label');
876
-
877
-
878
-        switch ($QFI->get('QST_type')) {
879
-            case 'TEXTAREA':
880
-                return EEH_Form_Fields::textarea(
881
-                    $display_text,
882
-                    $answer,
883
-                    $input_name,
884
-                    $input_id,
885
-                    $input_class,
886
-                    [],
887
-                    $required,
888
-                    $required_text,
889
-                    $label_class,
890
-                    $disabled,
891
-                    $system_ID,
892
-                    $use_html_entities,
893
-                    $add_mobile_label
894
-                );
895
-
896
-            case 'DROPDOWN':
897
-                return EEH_Form_Fields::select(
898
-                    $display_text,
899
-                    $answer,
900
-                    $options,
901
-                    $input_name,
902
-                    $input_id,
903
-                    $input_class,
904
-                    $required,
905
-                    $required_text,
906
-                    $label_class,
907
-                    $disabled,
908
-                    $system_ID,
909
-                    $use_html_entities,
910
-                    true,
911
-                    $add_mobile_label
912
-                );
913
-
914
-
915
-            case 'RADIO_BTN':
916
-                return EEH_Form_Fields::radio(
917
-                    $display_text,
918
-                    $answer,
919
-                    $options,
920
-                    $input_name,
921
-                    $input_id,
922
-                    $input_class,
923
-                    $required,
924
-                    $required_text,
925
-                    $label_class,
926
-                    $disabled,
927
-                    $system_ID,
928
-                    $use_html_entities,
929
-                    $label_b4,
930
-                    $use_desc_4_label,
931
-                    $add_mobile_label
932
-                );
933
-
934
-            case 'CHECKBOX':
935
-                return EEH_Form_Fields::checkbox(
936
-                    $display_text,
937
-                    $answer,
938
-                    $options,
939
-                    $input_name,
940
-                    $input_id,
941
-                    $input_class,
942
-                    $required,
943
-                    $required_text,
944
-                    $label_class,
945
-                    $disabled,
946
-                    $label_b4,
947
-                    $system_ID,
948
-                    $use_html_entities,
949
-                    $add_mobile_label
950
-                );
951
-
952
-            case 'DATE':
953
-                return EEH_Form_Fields::datepicker(
954
-                    $display_text,
955
-                    $answer,
956
-                    $input_name,
957
-                    $input_id,
958
-                    $input_class,
959
-                    $required,
960
-                    $required_text,
961
-                    $label_class,
962
-                    $disabled,
963
-                    $system_ID,
964
-                    $use_html_entities,
965
-                    $add_mobile_label
966
-                );
967
-
968
-            case 'TEXT':
969
-            default:
970
-                return EEH_Form_Fields::text(
971
-                    $display_text,
972
-                    $answer,
973
-                    $input_name,
974
-                    $input_id,
975
-                    $input_class,
976
-                    $required,
977
-                    $required_text,
978
-                    $label_class,
979
-                    $disabled,
980
-                    $system_ID,
981
-                    $use_html_entities,
982
-                    $add_mobile_label
983
-                );
984
-        }
985
-    }
986
-
987
-
988
-    public static function label(
989
-        string $question,
990
-        string $required_text = '',
991
-        string $required_label = '',
992
-        string $name = '',
993
-        string $label_class = '',
994
-        bool $filter = true
995
-    ): string {
996
-        $for   = ! empty($name) ? " for='{$name}'" : '';
997
-        $class = ! empty($label_class) ? " class='{$label_class}'" : '';
998
-        $label = self::prep_question($question) . $required_label;
999
-        $label_html = "
491
+	}
492
+
493
+
494
+	/**
495
+	 * @param string $class
496
+	 * @param string $id
497
+	 * @param string $name
498
+	 * @param int    $rows
499
+	 * @param int    $tab_index
500
+	 * @param string $value
501
+	 * @param array  $wp_editor_args
502
+	 * @return false|string
503
+	 * @since   4.10.14.p
504
+	 */
505
+	private static function adminWpEditor($class, $id, $name, $rows, $tab_index, $value, $wp_editor_args = [])
506
+	{
507
+		$editor_settings = $wp_editor_args + [
508
+				'textarea_name' => esc_attr($name),
509
+				'textarea_rows' => absint($rows),
510
+				'editor_class'  => esc_attr($class),
511
+				'tabindex'      => absint($tab_index),
512
+			];
513
+		ob_start();
514
+		wp_editor($value, esc_attr($id), $editor_settings);
515
+		return ob_get_clean();
516
+	}
517
+
518
+
519
+	/**
520
+	 * espresso admin page select_input
521
+	 * Turns an array into a select fields
522
+	 *
523
+	 * @static
524
+	 * @access public
525
+	 * @param string  $name       field name
526
+	 * @param array   $values     option values, numbered array starting at 0, where each value is an array with a key
527
+	 *                            'text' (meaning text to display' and 'id' (meaning the internal value) eg:
528
+	 *                            array(1=>array('text'=>'Monday','id'=>1),2=>array('text'=>'Tuesday','id'=>2)...). or
529
+	 *                            as an array of key-value pairs, where the key is to be used for the select input's
530
+	 *                            name, and the value will be the text shown to the user.  Optionally you can also
531
+	 *                            include an additional key of "class" which will add a specific class to the option
532
+	 *                            for that value.
533
+	 * @param string  $default    default value
534
+	 * @param string  $parameters extra parameters
535
+	 * @param string  $class      css class
536
+	 * @param boolean $autosize   whether to autosize the select or not
537
+	 * @return string              html string for the select input
538
+	 */
539
+	public static function select_input(
540
+		$name,
541
+		$values,
542
+		$default = '',
543
+		$parameters = '',
544
+		$class = '',
545
+		$autosize = true
546
+	) {
547
+		// if $values was submitted in the wrong format, convert it over
548
+		if (! empty($values) && (! array_key_exists(0, $values) || ! is_array($values[0]))) {
549
+			$converted_values = [];
550
+			foreach ($values as $id => $text) {
551
+				$converted_values[] = ['id' => $id, 'text' => $text];
552
+			}
553
+			$values = $converted_values;
554
+		}
555
+
556
+		$field =
557
+			'<select id="' . EEH_Formatter::ee_tep_output_string($name)
558
+			. '" name="' . EEH_Formatter::ee_tep_output_string($name)
559
+			. '"';
560
+
561
+		if (EEH_Formatter::ee_tep_not_null($parameters)) {
562
+			$field .= ' ' . $parameters;
563
+		}
564
+		$class = $autosize ? self::appendInputSizeClass($class, $values) : '';
565
+
566
+		$field .= ' class="' . $class . '">';
567
+
568
+		if (empty($default) && isset($GLOBALS[ $name ])) {
569
+			$default = stripslashes($GLOBALS[ $name ]);
570
+		}
571
+
572
+		$field .= self::selectInputOption($values, $default);
573
+		$field .= '</select>';
574
+
575
+		return $field;
576
+	}
577
+
578
+
579
+	private static function selectInputOption(array $values, $default): string
580
+	{
581
+		if (isset($values['id'], $values['text'])) {
582
+			$id = is_scalar($values['id']) ? $values['id'] : '';
583
+			$text = is_scalar($values['text']) ? $values['text'] : '';
584
+			$selected = $default == $values['id'] ? ' selected = "selected"' : '';
585
+			$html_class = isset($values['class']) ? ' class="' . $values['class'] . '"' : '';
586
+			return "<option value='{$id}'{$selected}{$html_class}>{$text}</option>";
587
+		}
588
+		$options = '';
589
+		foreach ($values as $value) {
590
+			$options .= self::selectInputOption($value, $default);
591
+		}
592
+		return $options;
593
+	}
594
+
595
+
596
+	/**
597
+	 * @param mixed $value
598
+	 * @return int
599
+	 * @since   $VID:$
600
+	 */
601
+	private static function getInputValueLength($value): int
602
+	{
603
+		if ($value instanceof EE_Question_Option) {
604
+			return self::getInputValueLength($value->desc());
605
+		}
606
+		if (is_array($value)) {
607
+			$chars = 0;
608
+			foreach ($value as $val) {
609
+				$length = self::getInputValueLength($val);
610
+				$chars = max($length, $chars);
611
+			}
612
+			return $chars;
613
+		}
614
+		// not a primitive? return something big
615
+		if (! is_scalar($value)) {
616
+			return 500;
617
+		}
618
+		return strlen((string) $value);
619
+	}
620
+
621
+
622
+	/**
623
+	 * @param string $class
624
+	 * @param mixed $value
625
+	 * @return string
626
+	 * @since   $VID:$
627
+	 */
628
+	private static function appendInputSizeClass(string $class, $value): string
629
+	{
630
+		if (strpos($class, 'ee-input-width--') !== false) {
631
+			return $class;
632
+		}
633
+		$chars = self::getInputValueLength($value);
634
+		if ($chars && $chars < 5) {
635
+			return "{$class} ee-input-width--tiny";
636
+		}
637
+		if ($chars && $chars < 25) {
638
+			return "{$class} ee-input-width--small";
639
+		}
640
+		if ($chars && $chars > 100) {
641
+			return "{$class} ee-input-width--big";
642
+		}
643
+		return "{$class} ee-input-width--reg";
644
+	}
645
+
646
+
647
+	/**
648
+	 * generate_question_groups_html
649
+	 *
650
+	 * @param array  $question_groups
651
+	 * @param string $group_wrapper
652
+	 * @return string HTML
653
+	 * @throws EE_Error
654
+	 * @throws ReflectionException
655
+	 */
656
+	public static function generate_question_groups_html($question_groups = [], $group_wrapper = 'fieldset')
657
+	{
658
+
659
+		$html                            = '';
660
+		$before_question_group_questions =
661
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
662
+		$after_question_group_questions  =
663
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
664
+
665
+		if (! empty($question_groups)) {
666
+			// loop thru question groups
667
+			foreach ($question_groups as $QSG) {
668
+				// check that questions exist
669
+				if (! empty($QSG['QSG_questions'])) {
670
+					// use fieldsets
671
+					$html .= "\n\t"
672
+							 . '<'
673
+							 . $group_wrapper
674
+							 . ' class="espresso-question-group-wrap" id="'
675
+							 . $QSG['QSG_identifier']
676
+							 . '">';
677
+					// group_name
678
+					$html .= $QSG['QSG_show_group_name']
679
+						? "\n\t\t"
680
+						  . '<h5 class="espresso-question-group-title-h5 section-title">'
681
+						  . self::prep_answer($QSG['QSG_name'])
682
+						  . '</h5>'
683
+						: '';
684
+					// group_desc
685
+					$html .= $QSG['QSG_show_group_desc'] && ! empty($QSG['QSG_desc'])
686
+						? '<div class="espresso-question-group-desc-pg">'
687
+						  . self::prep_answer($QSG['QSG_desc'])
688
+						  . '</div>'
689
+						: '';
690
+
691
+					$html .= $before_question_group_questions;
692
+					// loop thru questions
693
+					foreach ($QSG['QSG_questions'] as $question) {
694
+						$QFI  = new EE_Question_Form_Input(
695
+							$question['qst_obj'],
696
+							$question['ans_obj'],
697
+							$question
698
+						);
699
+						$html .= self::generate_form_input($QFI);
700
+					}
701
+					$html .= $after_question_group_questions;
702
+					$html .= "\n\t" . '</' . $group_wrapper . '>';
703
+				}
704
+			}
705
+		}
706
+
707
+		return $html;
708
+	}
709
+
710
+
711
+	/**
712
+	 * generate_question_groups_html
713
+	 *
714
+	 * @param array  $question_groups
715
+	 * @param array  $q_meta
716
+	 * @param bool   $from_admin
717
+	 * @param string $group_wrapper
718
+	 * @return string HTML
719
+	 * @throws EE_Error
720
+	 * @throws ReflectionException
721
+	 */
722
+	public static function generate_question_groups_html2(
723
+		$question_groups = [],
724
+		$q_meta = [],
725
+		$from_admin = false,
726
+		$group_wrapper = 'fieldset'
727
+	) {
728
+
729
+		$html                            = '';
730
+		$before_question_group_questions =
731
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
732
+		$after_question_group_questions  =
733
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
734
+
735
+		$default_q_meta = [
736
+			'att_nmbr'    => 1,
737
+			'ticket_id'   => '',
738
+			'input_name'  => '',
739
+			'input_id'    => '',
740
+			'input_class' => '',
741
+		];
742
+		$q_meta         = array_merge($default_q_meta, $q_meta);
743
+
744
+		if (! empty($question_groups)) {
745
+			// loop thru question groups
746
+			foreach ($question_groups as $QSG) {
747
+				if ($QSG instanceof EE_Question_Group) {
748
+					// check that questions exist
749
+
750
+					$where = ['QST_deleted' => 0];
751
+					if (! $from_admin) {
752
+						$where['QST_admin_only'] = 0;
753
+					}
754
+					$questions =
755
+						$QSG->questions([$where, 'order_by' => ['Question_Group_Question.QGQ_order' => 'ASC']]);
756
+					if (! empty($questions)) {
757
+						// use fieldsets
758
+						$html .= "\n\t"
759
+								 . '<' . $group_wrapper . ' class="espresso-question-group-wrap" '
760
+								 . 'id="' . $QSG->get('QSG_identifier') . '">';
761
+						// group_name
762
+						if ($QSG->show_group_name()) {
763
+							$html .= "\n\t\t"
764
+									 . '<h5 class="espresso-question-group-title-h5 section-title">'
765
+									 . $QSG->get_pretty('QSG_name')
766
+									 . '</h5>';
767
+						}
768
+						// group_desc
769
+						if ($QSG->show_group_desc()) {
770
+							$html .= '<div class="espresso-question-group-desc-pg">'
771
+									 . $QSG->get_pretty('QSG_desc')
772
+									 . '</div>';
773
+						}
774
+
775
+						$html .= $before_question_group_questions;
776
+						// loop thru questions
777
+						foreach ($questions as $QST) {
778
+							$qstn_id = $QST->is_system_question() ? $QST->system_ID() : $QST->ID();
779
+
780
+							$answer = null;
781
+
782
+							/** @var RequestInterface $request */
783
+							$request      = LoaderFactory::getLoader()->getShared(RequestInterface::class);
784
+							$request_qstn = $request->getRequestParam('qstn', [], 'string', true);
785
+							if (! empty($request_qstn) && isset($q_meta['input_id']) && isset($q_meta['att_nmbr'])) {
786
+								// check for answer in $request_qstn in case we are reprocessing a form after an error
787
+								if (isset($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])) {
788
+									$answer = is_array($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])
789
+										? $request_qstn[ $q_meta['input_id'] ][ $qstn_id ]
790
+										: sanitize_text_field($request_qstn[ $q_meta['input_id'] ][ $qstn_id ]);
791
+								}
792
+							} elseif (isset($q_meta['attendee']) && $q_meta['attendee']) {
793
+								// attendee data from the session
794
+								$answer =
795
+									isset($q_meta['attendee'][ $qstn_id ]) ? $q_meta['attendee'][ $qstn_id ] : null;
796
+							}
797
+
798
+
799
+							$QFI  = new EE_Question_Form_Input(
800
+								$QST,
801
+								EE_Answer::new_instance(
802
+									[
803
+										'ANS_ID'    => 0,
804
+										'QST_ID'    => 0,
805
+										'REG_ID'    => 0,
806
+										'ANS_value' => $answer,
807
+									]
808
+								),
809
+								$q_meta
810
+							);
811
+							$html .= self::generate_form_input($QFI);
812
+						}
813
+						$html .= $after_question_group_questions;
814
+						$html .= "\n\t" . '</' . $group_wrapper . '>';
815
+					}
816
+				}
817
+			}
818
+		}
819
+		return $html;
820
+	}
821
+
822
+
823
+	/**
824
+	 * generate_form_input
825
+	 *
826
+	 * @param EE_Question_Form_Input $QFI
827
+	 * @return string HTML
828
+	 * @throws EE_Error
829
+	 * @throws ReflectionException
830
+	 */
831
+	public static function generate_form_input(EE_Question_Form_Input $QFI)
832
+	{
833
+		if (isset($QFI->QST_admin_only) && $QFI->QST_admin_only && ! is_admin()) {
834
+			return '';
835
+		}
836
+		/** @var RequestInterface $request */
837
+		$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
838
+
839
+		$QFI = self::_load_system_dropdowns($QFI);
840
+		$QFI = self::_load_specialized_dropdowns($QFI);
841
+
842
+		// we also need to verify
843
+
844
+		$display_text = $QFI->get('QST_display_text');
845
+		$input_name   = $QFI->get('QST_input_name');
846
+		$answer       = $request->getRequestParam($input_name, $QFI->get('ANS_value'));
847
+		$input_id     = $QFI->get('QST_input_id');
848
+		$input_class  = $QFI->get('QST_input_class');
849
+		//      $disabled = $QFI->get('QST_disabled') ? ' disabled="disabled"' : '';
850
+		$disabled          = $QFI->get('QST_disabled');
851
+		$required_label    = apply_filters(' FHEE__EEH_Form_Fields__generate_form_input__required_label', '<em>*</em>');
852
+		$QST_required      = $QFI->get('QST_required');
853
+		$required          =
854
+			$QST_required
855
+				? ['label' => $required_label, 'class' => 'required needs-value', 'title' => $QST_required]
856
+				: [];
857
+		$use_html_entities = $QFI->get_meta('htmlentities');
858
+		$required_text     =
859
+			$QFI->get('QST_required_text') != ''
860
+				? $QFI->get('QST_required_text')
861
+				: esc_html__('This field is required', 'event_espresso');
862
+		$required_text     = $QST_required
863
+			? "\n\t\t\t"
864
+			  . '<div class="required-text hidden">'
865
+			  . self::prep_answer($required_text, $use_html_entities)
866
+			  . '</div>'
867
+			: '';
868
+		$label_class       = $QFI->get('label_class');
869
+		$label_class       = $label_class ? "{$label_class} espresso-form-input-lbl" : 'espresso-form-input-lbl';
870
+		$QST_options       = $QFI->options(true, $answer);
871
+		$options           = is_array($QST_options) ? self::prep_answer_options($QST_options) : [];
872
+		$system_ID         = $QFI->get('QST_system');
873
+		$label_b4          = $QFI->get_meta('label_b4');
874
+		$use_desc_4_label  = $QFI->get_meta('use_desc_4_label');
875
+		$add_mobile_label  = $QFI->get_meta('add_mobile_label');
876
+
877
+
878
+		switch ($QFI->get('QST_type')) {
879
+			case 'TEXTAREA':
880
+				return EEH_Form_Fields::textarea(
881
+					$display_text,
882
+					$answer,
883
+					$input_name,
884
+					$input_id,
885
+					$input_class,
886
+					[],
887
+					$required,
888
+					$required_text,
889
+					$label_class,
890
+					$disabled,
891
+					$system_ID,
892
+					$use_html_entities,
893
+					$add_mobile_label
894
+				);
895
+
896
+			case 'DROPDOWN':
897
+				return EEH_Form_Fields::select(
898
+					$display_text,
899
+					$answer,
900
+					$options,
901
+					$input_name,
902
+					$input_id,
903
+					$input_class,
904
+					$required,
905
+					$required_text,
906
+					$label_class,
907
+					$disabled,
908
+					$system_ID,
909
+					$use_html_entities,
910
+					true,
911
+					$add_mobile_label
912
+				);
913
+
914
+
915
+			case 'RADIO_BTN':
916
+				return EEH_Form_Fields::radio(
917
+					$display_text,
918
+					$answer,
919
+					$options,
920
+					$input_name,
921
+					$input_id,
922
+					$input_class,
923
+					$required,
924
+					$required_text,
925
+					$label_class,
926
+					$disabled,
927
+					$system_ID,
928
+					$use_html_entities,
929
+					$label_b4,
930
+					$use_desc_4_label,
931
+					$add_mobile_label
932
+				);
933
+
934
+			case 'CHECKBOX':
935
+				return EEH_Form_Fields::checkbox(
936
+					$display_text,
937
+					$answer,
938
+					$options,
939
+					$input_name,
940
+					$input_id,
941
+					$input_class,
942
+					$required,
943
+					$required_text,
944
+					$label_class,
945
+					$disabled,
946
+					$label_b4,
947
+					$system_ID,
948
+					$use_html_entities,
949
+					$add_mobile_label
950
+				);
951
+
952
+			case 'DATE':
953
+				return EEH_Form_Fields::datepicker(
954
+					$display_text,
955
+					$answer,
956
+					$input_name,
957
+					$input_id,
958
+					$input_class,
959
+					$required,
960
+					$required_text,
961
+					$label_class,
962
+					$disabled,
963
+					$system_ID,
964
+					$use_html_entities,
965
+					$add_mobile_label
966
+				);
967
+
968
+			case 'TEXT':
969
+			default:
970
+				return EEH_Form_Fields::text(
971
+					$display_text,
972
+					$answer,
973
+					$input_name,
974
+					$input_id,
975
+					$input_class,
976
+					$required,
977
+					$required_text,
978
+					$label_class,
979
+					$disabled,
980
+					$system_ID,
981
+					$use_html_entities,
982
+					$add_mobile_label
983
+				);
984
+		}
985
+	}
986
+
987
+
988
+	public static function label(
989
+		string $question,
990
+		string $required_text = '',
991
+		string $required_label = '',
992
+		string $name = '',
993
+		string $label_class = '',
994
+		bool $filter = true
995
+	): string {
996
+		$for   = ! empty($name) ? " for='{$name}'" : '';
997
+		$class = ! empty($label_class) ? " class='{$label_class}'" : '';
998
+		$label = self::prep_question($question) . $required_label;
999
+		$label_html = "
1000 1000
             {$required_text}
1001 1001
             <label{$for}{$class}>{$label}</label>";
1002
-        // filter label but ensure required text comes before it
1003
-        return $filter
1004
-            ? apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text)
1005
-            : $label_html;
1006
-    }
1007
-
1008
-
1009
-
1010
-    public static function mobileLabel(
1011
-        bool $add_mobile_label,
1012
-        string $question,
1013
-        string $required_text = '',
1014
-        string $required_label = '',
1015
-        string $label_class = '',
1016
-        string $name = ''
1017
-    ): string {
1018
-        return $add_mobile_label
1019
-            ? self::label($question, $required_text, $required_label, $name, $label_class, false)
1020
-            : '';
1021
-    }
1022
-
1023
-
1024
-    /**
1025
-     * generates HTML for a form text input
1026
-     *
1027
-     * @param string $question    label content
1028
-     * @param string $answer      form input value attribute
1029
-     * @param string $name        form input name attribute
1030
-     * @param string $id          form input css id attribute
1031
-     * @param string $class       form input css class attribute
1032
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1033
-     *                            required 'class', and required 'msg' attribute
1034
-     * @param string $label_class css class attribute for the label
1035
-     * @param string $disabled    disabled="disabled" or null
1036
-     * @return string HTML
1037
-     */
1038
-    public static function text(
1039
-        $question = false,
1040
-        $answer = null,
1041
-        $name = false,
1042
-        $id = '',
1043
-        $class = '',
1044
-        $required = false,
1045
-        $required_text = '',
1046
-        $label_class = '',
1047
-        $disabled = false,
1048
-        $system_ID = false,
1049
-        $use_html_entities = true,
1050
-        $add_mobile_label = false,
1051
-        $extra_attributes = ''
1052
-    ) {
1053
-        // need these
1054
-        if (! $question || ! $name) {
1055
-            return null;
1056
-        }
1057
-        // prep the answer
1058
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1059
-        // prep the required array
1060
-        $required = self::prep_required($required);
1061
-        // set disabled tag
1062
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1063
-        // ya gots ta have style man!!!
1064
-        $txt_class = is_admin() ? 'regular-text' : 'espresso-text-inp';
1065
-        $class     = empty($class) ? $txt_class : $class;
1066
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1067
-        $class = self::appendInputSizeClass($class, $answer);
1068
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1069
-        $extra_attributes = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', $extra_attributes);
1070
-
1071
-        $label_html = self::label($question, $required_text, $required['label'], $name, $label_class);
1072
-        $mobile_label = self::mobileLabel(
1073
-            $add_mobile_label,
1074
-            $question,
1075
-            $required_text,
1076
-            $required['label'],
1077
-            $label_class,
1078
-            $name
1079
-        );
1080
-
1081
-        $input_html = $mobile_label . '
1002
+		// filter label but ensure required text comes before it
1003
+		return $filter
1004
+			? apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text)
1005
+			: $label_html;
1006
+	}
1007
+
1008
+
1009
+
1010
+	public static function mobileLabel(
1011
+		bool $add_mobile_label,
1012
+		string $question,
1013
+		string $required_text = '',
1014
+		string $required_label = '',
1015
+		string $label_class = '',
1016
+		string $name = ''
1017
+	): string {
1018
+		return $add_mobile_label
1019
+			? self::label($question, $required_text, $required_label, $name, $label_class, false)
1020
+			: '';
1021
+	}
1022
+
1023
+
1024
+	/**
1025
+	 * generates HTML for a form text input
1026
+	 *
1027
+	 * @param string $question    label content
1028
+	 * @param string $answer      form input value attribute
1029
+	 * @param string $name        form input name attribute
1030
+	 * @param string $id          form input css id attribute
1031
+	 * @param string $class       form input css class attribute
1032
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1033
+	 *                            required 'class', and required 'msg' attribute
1034
+	 * @param string $label_class css class attribute for the label
1035
+	 * @param string $disabled    disabled="disabled" or null
1036
+	 * @return string HTML
1037
+	 */
1038
+	public static function text(
1039
+		$question = false,
1040
+		$answer = null,
1041
+		$name = false,
1042
+		$id = '',
1043
+		$class = '',
1044
+		$required = false,
1045
+		$required_text = '',
1046
+		$label_class = '',
1047
+		$disabled = false,
1048
+		$system_ID = false,
1049
+		$use_html_entities = true,
1050
+		$add_mobile_label = false,
1051
+		$extra_attributes = ''
1052
+	) {
1053
+		// need these
1054
+		if (! $question || ! $name) {
1055
+			return null;
1056
+		}
1057
+		// prep the answer
1058
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1059
+		// prep the required array
1060
+		$required = self::prep_required($required);
1061
+		// set disabled tag
1062
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1063
+		// ya gots ta have style man!!!
1064
+		$txt_class = is_admin() ? 'regular-text' : 'espresso-text-inp';
1065
+		$class     = empty($class) ? $txt_class : $class;
1066
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1067
+		$class = self::appendInputSizeClass($class, $answer);
1068
+		$class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1069
+		$extra_attributes = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', $extra_attributes);
1070
+
1071
+		$label_html = self::label($question, $required_text, $required['label'], $name, $label_class);
1072
+		$mobile_label = self::mobileLabel(
1073
+			$add_mobile_label,
1074
+			$question,
1075
+			$required_text,
1076
+			$required['label'],
1077
+			$label_class,
1078
+			$name
1079
+		);
1080
+
1081
+		$input_html = $mobile_label . '
1082 1082
             <input  type="text"
1083 1083
                     name="' . $name . '"
1084 1084
                     id="' . $id . '"
@@ -1088,1039 +1088,1039 @@  discard block
 block discarded – undo
1088 1088
                     ' . $disabled . ' ' . $extra_attributes . '
1089 1089
             />';
1090 1090
 
1091
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1092
-        return $label_html . $input_html;
1093
-    }
1094
-
1095
-
1096
-    /**
1097
-     * generates HTML for a form textarea
1098
-     *
1099
-     * @param string $question    label content
1100
-     * @param string $answer      form input value attribute
1101
-     * @param string $name        form input name attribute
1102
-     * @param string $id          form input css id attribute
1103
-     * @param string $class       form input css class attribute
1104
-     * @param array  $dimensions  array of form input rows and cols attributes : array( 'rows' => 3, 'cols' => 40 )
1105
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1106
-     *                            required 'class', and required 'msg' attribute
1107
-     * @param string $label_class css class attribute for the label
1108
-     * @param string $disabled    disabled="disabled" or null
1109
-     * @return string HTML
1110
-     */
1111
-    public static function textarea(
1112
-        $question = false,
1113
-        $answer = null,
1114
-        $name = false,
1115
-        $id = '',
1116
-        $class = '',
1117
-        $dimensions = false,
1118
-        $required = false,
1119
-        $required_text = '',
1120
-        $label_class = '',
1121
-        $disabled = false,
1122
-        $system_ID = false,
1123
-        $use_html_entities = true,
1124
-        $add_mobile_label = false
1125
-    ) {
1126
-        // need these
1127
-        if (! $question || ! $name) {
1128
-            return null;
1129
-        }
1130
-        // prep the answer
1131
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1132
-        // prep the required array
1133
-        $required = self::prep_required($required);
1134
-        // make sure $dimensions is an array
1135
-        $dimensions = is_array($dimensions) ? $dimensions : [];
1136
-        // and set some defaults
1137
-        $dimensions = array_merge(['rows' => 3, 'cols' => 40], $dimensions);
1138
-        // set disabled tag
1139
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1140
-        // ya gots ta have style man!!!
1141
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1142
-        $class     .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1143
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1144
-
1145
-        $label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1146
-        $mobile_label = self::mobileLabel(
1147
-            $add_mobile_label,
1148
-            $question,
1149
-            $required_text,
1150
-            $required['label'],
1151
-            $label_class,
1152
-            $name
1153
-        );
1154
-
1155
-        $input_html = $mobile_label
1156
-            . '<textarea name="' . $name . '" id="' . $id . '" class="' . trim($class) . '" '
1157
-            . 'rows="' . $dimensions['rows'] . '" cols="' . $dimensions['cols'] . '"  '
1158
-            . 'aria-label="' . $required['msg'] . '" ' . $disabled . ' ' . $extra . '>'
1159
-             . esc_textarea($answer)
1160
-              . '</textarea>';
1161
-
1162
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1163
-        return $label_html . $input_html;
1164
-    }
1165
-
1166
-
1167
-    /**
1168
-     * generates HTML for a form select input
1169
-     *
1170
-     * @param string $question    label content
1171
-     * @param string $answer      form input value attribute
1172
-     * @param array  $options     array of answer options where array key = option value and array value = option
1173
-     *                            display text
1174
-     * @param string $name        form input name attribute
1175
-     * @param string $id          form input css id attribute
1176
-     * @param string $class       form input css class attribute
1177
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1178
-     *                            required 'class', and required 'msg' attribute
1179
-     * @param string $label_class css class attribute for the label
1180
-     * @param string $disabled    disabled="disabled" or null
1181
-     * @return string HTML
1182
-     */
1183
-    public static function select(
1184
-        $question = false,
1185
-        $answer = null,
1186
-        $options = false,
1187
-        $name = false,
1188
-        $id = '',
1189
-        $class = '',
1190
-        $required = false,
1191
-        $required_text = '',
1192
-        $label_class = '',
1193
-        $disabled = false,
1194
-        $system_ID = false,
1195
-        $use_html_entities = true,
1196
-        $add_please_select_option = false,
1197
-        $add_mobile_label = false
1198
-    ) {
1199
-
1200
-        // need these
1201
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1202
-            return null;
1203
-        }
1204
-        // prep the answer
1205
-        $answer = is_array($answer)
1206
-            ? self::prep_answer(array_shift($answer), $use_html_entities)
1207
-            : self::prep_answer($answer, $use_html_entities);
1208
-        // prep the required array
1209
-        $required = self::prep_required($required);
1210
-        // set disabled tag
1211
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1212
-        // ya gots ta have style man!!!
1213
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1214
-        $class = self::appendInputSizeClass($class, $options);
1215
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1216
-
1217
-        $label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1218
-        $mobile_label = self::mobileLabel(
1219
-            $add_mobile_label,
1220
-            $question,
1221
-            $required_text,
1222
-            $required['label'],
1223
-            $label_class,
1224
-            $name
1225
-        );
1226
-
1227
-        $input_html = $mobile_label
1228
-            . '<select name="' . $name . '" id="' . $id . '" class="' . trim($class) . ' ' . $required['class'] . '" '
1229
-            . 'aria-label="' . esc_attr($required['msg']) . '"' . $disabled . ' ' . $extra . '>';
1230
-        // recursively count array elements, to determine total number of options
1231
-        $only_option = count($options, 1) == 1;
1232
-        if (! $only_option) {
1233
-            // if there is NO answer set and there are multiple options to choose from, then set the "please select" message as selected
1234
-            $selected   = $answer === null ? ' selected' : '';
1235
-            $input_html .= $add_please_select_option
1236
-                ? "\n\t\t\t\t"
1237
-                  . '<option value=""' . $selected . '>'
1238
-                  . esc_html__(' - please select - ', 'event_espresso')
1239
-                  . '</option>'
1240
-                : '';
1241
-        }
1242
-        foreach ($options as $key => $value) {
1243
-            // if value is an array, then create option groups, else create regular ol' options
1244
-            $input_html .= is_array($value)
1245
-                ? self::_generate_select_option_group(
1246
-                    $key,
1247
-                    $value,
1248
-                    $answer,
1249
-                    $use_html_entities
1250
-                )
1251
-                : self::_generate_select_option(
1252
-                    $value->value(),
1253
-                    $value->desc(),
1254
-                    $answer,
1255
-                    $only_option,
1256
-                    $use_html_entities
1257
-                );
1258
-        }
1259
-
1260
-        $input_html .= "\n\t\t\t" . '</select>';
1261
-
1262
-        $input_html =
1263
-            apply_filters(
1264
-                'FHEE__EEH_Form_Fields__select__before_end_wrapper',
1265
-                $input_html,
1266
-                $question,
1267
-                $answer,
1268
-                $name,
1269
-                $id,
1270
-                $class,
1271
-                $system_ID
1272
-            );
1273
-
1274
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1275
-        return $label_html . $input_html;
1276
-    }
1277
-
1278
-
1279
-    /**
1280
-     *  _generate_select_option_group
1281
-     *
1282
-     *  if  $value for a select box is an array, then the key will be used as the optgroup label
1283
-     *  and the value array will be looped thru and the elements sent to _generate_select_option
1284
-     *
1285
-     * @param mixed   $opt_group
1286
-     * @param mixed   $QSOs
1287
-     * @param mixed   $answer
1288
-     * @param boolean $use_html_entities
1289
-     * @return string
1290
-     */
1291
-    private static function _generate_select_option_group($opt_group, $QSOs, $answer, $use_html_entities = true)
1292
-    {
1293
-        $html = "\n\t\t\t\t" . '<optgroup label="' . self::prep_option_value($opt_group) . '">';
1294
-        foreach ($QSOs as $QSO) {
1295
-            $html .= self::_generate_select_option($QSO->value(), $QSO->desc(), $answer, false, $use_html_entities);
1296
-        }
1297
-        $html .= "\n\t\t\t\t" . '</optgroup>';
1298
-        return $html;
1299
-    }
1300
-
1301
-
1302
-    /**
1303
-     *  _generate_select_option
1304
-     *
1305
-     * @param mixed   $key
1306
-     * @param mixed   $value
1307
-     * @param mixed   $answer
1308
-     * @param int     $only_option
1309
-     * @param boolean $use_html_entities
1310
-     * @return string
1311
-     */
1312
-    private static function _generate_select_option(
1313
-        $key,
1314
-        $value,
1315
-        $answer,
1316
-        $only_option = false,
1317
-        $use_html_entities = true
1318
-    ) {
1319
-        $key      = self::prep_answer($key, $use_html_entities);
1320
-        $value    = self::prep_answer($value, $use_html_entities);
1321
-        $value    = ! empty($value) ? $value : $key;
1322
-        $selected = ($answer == $key || $only_option) ? 'selected' : '';
1323
-        return "\n\t\t\t\t"
1324
-               . '<option value="' . self::prep_option_value($key) . '" ' . $selected . '> '
1325
-               . $value
1326
-               . '&nbsp;&nbsp;&nbsp;</option>';
1327
-    }
1328
-
1329
-
1330
-    /**
1331
-     * generates HTML for form radio button inputs
1332
-     *
1333
-     * @param bool|string $question    label content
1334
-     * @param string      $answer      form input value attribute
1335
-     * @param array|bool  $options     array of answer options where array key = option value and array value = option
1336
-     *                                 display text
1337
-     * @param bool|string $name        form input name attribute
1338
-     * @param string      $id          form input css id attribute
1339
-     * @param string      $class       form input css class attribute
1340
-     * @param array|bool  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1341
-     *                                 required 'class', and required 'msg' attribute
1342
-     * @param string      $required_text
1343
-     * @param string      $label_class css class attribute for the label
1344
-     * @param bool|string $disabled    disabled="disabled" or null
1345
-     * @param bool        $system_ID
1346
-     * @param bool        $use_html_entities
1347
-     * @param bool        $label_b4
1348
-     * @param bool        $use_desc_4_label
1349
-     * @return string HTML
1350
-     */
1351
-    public static function radio(
1352
-        $question = false,
1353
-        $answer = null,
1354
-        $options = false,
1355
-        $name = false,
1356
-        $id = '',
1357
-        $class = '',
1358
-        $required = false,
1359
-        $required_text = '',
1360
-        $label_class = '',
1361
-        $disabled = false,
1362
-        $system_ID = false,
1363
-        $use_html_entities = true,
1364
-        $label_b4 = false,
1365
-        $use_desc_4_label = false,
1366
-        $add_mobile_label = false
1367
-    ) {
1368
-        // need these
1369
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1370
-            return null;
1371
-        }
1372
-        // prep the answer
1373
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1374
-        // prep the required array
1375
-        $required = self::prep_required($required);
1376
-        // set disabled tag
1377
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1378
-        // ya gots ta have style man!!!
1379
-        $radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1380
-        $class       = ! empty($class) ? $class : 'espresso-radio-btn-inp';
1381
-        $extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1382
-
1383
-        $label_html = self::label($question, $required_text, $required['label'], '', $label_class);
1384
-        $mobile_label = self::mobileLabel(
1385
-            $add_mobile_label,
1386
-            $question,
1387
-            $required_text,
1388
-            $required['label'],
1389
-            $label_class
1390
-        );
1391
-
1392
-        $input_html = $mobile_label
1393
-            . '<ul id="' . $id . '-ul" class="espresso-radio-btn-options-ul ' . $class . '-ul">';
1394
-
1395
-        $class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1396
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1397
-
1398
-        foreach ($options as $OPT) {
1399
-            if ($OPT instanceof EE_Question_Option) {
1400
-                $value   = self::prep_option_value($OPT->value());
1401
-                $label   = $use_desc_4_label ? $OPT->desc() : $OPT->value();
1402
-                $size    = $use_desc_4_label
1403
-                    ? self::get_label_size_class($OPT->value() . ' ' . $OPT->desc())
1404
-                    : self::get_label_size_class($OPT->value());
1405
-                $desc    = $OPT->desc();// no self::prep_answer
1406
-                $answer  = is_numeric($value) && empty($answer) ? 0 : $answer;
1407
-                $checked = (string) $value == (string) $answer ? ' checked' : '';
1408
-                $opt     = '-' . sanitize_key($value);
1409
-
1410
-                $input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1411
-                $input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-radio-btn-lbl">';
1412
-                $input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $label . '</span>&nbsp;' : '';
1413
-                $input_html .= "\n\t\t\t\t\t\t"
1414
-                               . '<input type="radio" name="' . $name . '" id="' . $id . $opt . '" '
1415
-                               . 'class="' . $class . '" value="' . $value . '" '
1416
-                               . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled
1417
-                               . $checked . ' ' . $extra . '/>';
1418
-                $input_html .= ! $label_b4
1419
-                    ? "\n\t\t\t\t\t\t"
1420
-                      . '&nbsp;<span class="espresso-radio-btn-desc">'
1421
-                      . $label
1422
-                      . '</span>'
1423
-                    : '';
1424
-                $input_html .= "\n\t\t\t\t\t" . '</label>';
1425
-                $input_html .= $use_desc_4_label
1426
-                    ? ''
1427
-                    : '<span class="espresso-radio-btn-option-desc small-text grey-text">' . $desc . '</span>';
1428
-                $input_html .= "\n\t\t\t\t" . '</li>';
1429
-            }
1430
-        }
1431
-
1432
-        $input_html .= "\n\t\t\t" . '</ul>';
1433
-
1434
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1435
-        return $label_html . $input_html;
1436
-    }
1437
-
1438
-
1439
-    /**
1440
-     * generates HTML for form checkbox inputs
1441
-     *
1442
-     * @param string $question    label content
1443
-     * @param string $answer      form input value attribute
1444
-     * @param array  $options     array of options where array key = option value and array value = option display text
1445
-     * @param string $name        form input name attribute
1446
-     * @param string $id          form input css id attribute
1447
-     * @param string $class       form input css class attribute
1448
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1449
-     *                            required 'class', and required 'msg' attribute
1450
-     * @param string $label_class css class attribute for the label
1451
-     * @param string $disabled    disabled="disabled" or null
1452
-     * @return string HTML
1453
-     */
1454
-    public static function checkbox(
1455
-        $question = false,
1456
-        $answer = null,
1457
-        $options = false,
1458
-        $name = false,
1459
-        $id = '',
1460
-        $class = '',
1461
-        $required = false,
1462
-        $required_text = '',
1463
-        $label_class = '',
1464
-        $disabled = false,
1465
-        $label_b4 = false,
1466
-        $system_ID = false,
1467
-        $use_html_entities = true,
1468
-        $add_mobile_label = false
1469
-    ) {
1470
-        // need these
1471
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1472
-            return null;
1473
-        }
1474
-        $answer = maybe_unserialize($answer);
1475
-
1476
-        // prep the answer(s)
1477
-        $answer = is_array($answer) ? $answer : [sanitize_key($answer) => $answer];
1478
-
1479
-        foreach ($answer as $key => $value) {
1480
-            $key            = self::prep_option_value($key);
1481
-            $answer[ $key ] = self::prep_answer($value, $use_html_entities);
1482
-        }
1483
-
1484
-        // prep the required array
1485
-        $required = self::prep_required($required);
1486
-        // set disabled tag
1487
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1488
-        // ya gots ta have style man!!!
1489
-        $radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1490
-        $class       = empty($class) ? 'espresso-radio-btn-inp' : $class;
1491
-        $extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1492
-
1493
-        $label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1494
-        $mobile_label = self::mobileLabel(
1495
-            $add_mobile_label,
1496
-            $question,
1497
-            $required_text,
1498
-            $required['label'],
1499
-            $label_class
1500
-        );
1501
-
1502
-        $input_html = $mobile_label
1503
-            . '<ul id="' . $id . '-ul" class="espresso-checkbox-options-ul ' . $class . '-ul">';
1504
-
1505
-        $class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1506
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1507
-
1508
-        foreach ($options as $OPT) {
1509
-            $value = $OPT->value();// self::prep_option_value( $OPT->value() );
1510
-            $size  = self::get_label_size_class($OPT->value() . ' ' . $OPT->desc());
1511
-            $text  = self::prep_answer($OPT->value());
1512
-            $desc  = $OPT->desc();
1513
-            $opt   = '-' . sanitize_key($value);
1514
-
1515
-            $checked = is_array($answer) && in_array($text, $answer) ? ' checked' : '';
1516
-
1517
-            $input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1518
-            $input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-checkbox-lbl">';
1519
-            $input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $text . '</span>&nbsp;' : '';
1520
-            $input_html .= "\n\t\t\t\t\t\t"
1521
-                           . '<input type="checkbox" name="' . $name . '[' . $OPT->ID() . ']" '
1522
-                           . 'id="' . $id . $opt . '" class="' . $class . '" value="' . $value . '" '
1523
-                           . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . $checked . ' ' . $extra . '/>';
1524
-            $input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t" . '&nbsp;<span>' . $text . '</span>' : '';
1525
-            $input_html .= "\n\t\t\t\t\t" . '</label>';
1526
-            if (! empty($desc) && $desc != $text) {
1527
-                $input_html .= "\n\t\t\t\t\t"
1528
-                               . ' &nbsp; <br/><div class="espresso-checkbox-option-desc small-text grey-text">'
1529
-                               . $desc
1530
-                               . '</div>';
1531
-            }
1532
-            $input_html .= "\n\t\t\t\t" . '</li>';
1533
-        }
1534
-
1535
-        $input_html .= "\n\t\t\t" . '</ul>';
1536
-
1537
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1538
-        return $label_html . $input_html;
1539
-    }
1540
-
1541
-
1542
-    /**
1543
-     * generates HTML for a form datepicker input
1544
-     *
1545
-     * @param string $question    label content
1546
-     * @param string $answer      form input value attribute
1547
-     * @param string $name        form input name attribute
1548
-     * @param string $id          form input css id attribute
1549
-     * @param string $class       form input css class attribute
1550
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1551
-     *                            required 'class', and required 'msg' attribute
1552
-     * @param string $label_class css class attribute for the label
1553
-     * @param string $disabled    disabled="disabled" or null
1554
-     * @return string HTML
1555
-     */
1556
-    public static function datepicker(
1557
-        $question = false,
1558
-        $answer = null,
1559
-        $name = false,
1560
-        $id = '',
1561
-        $class = '',
1562
-        $required = false,
1563
-        $required_text = '',
1564
-        $label_class = '',
1565
-        $disabled = false,
1566
-        $system_ID = false,
1567
-        $use_html_entities = true,
1568
-        $add_mobile_label = false
1569
-    ) {
1570
-        // need these
1571
-        if (! $question || ! $name) {
1572
-            return null;
1573
-        }
1574
-        // prep the answer
1575
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1576
-        // prep the required array
1577
-        $required = self::prep_required($required);
1578
-        // set disabled tag
1579
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1580
-        // ya gots ta have style man!!!
1581
-        $txt_class = is_admin() ? 'regular-text' : 'espresso-datepicker-inp';
1582
-        $class     = empty($class) ? $txt_class : $class;
1583
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1584
-        $class = self::appendInputSizeClass($class, $answer);
1585
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1586
-
1587
-        $label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1588
-        $mobile_label = self::mobileLabel(
1589
-            $add_mobile_label,
1590
-            $question,
1591
-            $required_text,
1592
-            $required['label'],
1593
-            $label_class,
1594
-            $name
1595
-        );
1596
-
1597
-        $input_html = $mobile_label
1598
-            . '<input type="text" name="' . $name . '" id="' . $id . '" '
1599
-            . 'class="' . $class . ' ' . $required['class'] . ' datepicker" value="' . $answer . '"  '
1600
-            . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . ' ' . $extra . '/>';
1601
-
1602
-        // enqueue scripts
1603
-        wp_register_style(
1604
-            'espresso-ui-theme',
1605
-            EE_GLOBAL_ASSETS_URL . 'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1606
-            [],
1607
-            EVENT_ESPRESSO_VERSION
1608
-        );
1609
-        wp_enqueue_style('espresso-ui-theme');
1610
-        wp_enqueue_script('jquery-ui-datepicker');
1611
-
1612
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1613
-        return $label_html . $input_html;
1614
-    }
1615
-
1616
-
1617
-    /**
1618
-     *  remove_label_keep_required_msg
1619
-     *  this will strip out a form input's label HTML while keeping the required text HTML that MUST be before the label
1620
-     *
1621
-     * @access public
1622
-     * @return     string
1623
-     */
1624
-    public static function remove_label_keep_required_msg($label_html, $required_text)
1625
-    {
1626
-        return $required_text;
1627
-    }
1628
-
1629
-
1630
-    /**
1631
-     * Simply returns the HTML for a hidden input of the given name and value.
1632
-     *
1633
-     * @param string $name
1634
-     * @param string $value
1635
-     * @return string HTML
1636
-     */
1637
-    public static function hidden_input($name, $value, $id = '')
1638
-    {
1639
-        $id = ! empty($id) ? $id : $name;
1640
-        return '<input id="' . $id . '" type="hidden" name="' . $name . '" value="' . $value . '"/>';
1641
-    }
1642
-
1643
-
1644
-    /**
1645
-     * prep_question
1646
-     *
1647
-     * @param string $question
1648
-     * @return string
1649
-     */
1650
-    public static function prep_question($question)
1651
-    {
1652
-        return $question;
1653
-    }
1654
-
1655
-
1656
-    /**
1657
-     *  prep_answer
1658
-     *
1659
-     * @param mixed $answer
1660
-     * @return string
1661
-     */
1662
-    public static function prep_answer($answer, $use_html_entities = true)
1663
-    {
1664
-        // make sure we convert bools first.  Otherwise (bool) false becomes an empty string which is NOT desired,
1665
-        // we want "0".
1666
-        if (is_bool($answer)) {
1667
-            $answer = $answer ? 1 : 0;
1668
-        }
1669
-        $answer = trim(stripslashes(str_replace('&#039;', "'", $answer)));
1670
-        return $use_html_entities ? htmlentities($answer, ENT_QUOTES, 'UTF-8') : $answer;
1671
-    }
1672
-
1673
-
1674
-    /**
1675
-     *  prep_answer_options
1676
-     *
1677
-     * @param array $QSOs array of EE_Question_Option objects
1678
-     * @return array
1679
-     */
1680
-    public static function prep_answer_options($QSOs = [])
1681
-    {
1682
-        $prepped_answer_options = [];
1683
-        if (is_array($QSOs) && ! empty($QSOs)) {
1684
-            foreach ($QSOs as $key => $QSO) {
1685
-                if (! $QSO instanceof EE_Question_Option) {
1686
-                    $QSO = EE_Question_Option::new_instance(
1687
-                        [
1688
-                            'QSO_value' => is_array($QSO) && isset($QSO['id'])
1689
-                                ? (string) $QSO['id']
1690
-                                : (string) $key,
1691
-                            'QSO_desc'  => is_array($QSO) && isset($QSO['text'])
1692
-                                ? (string) $QSO['text']
1693
-                                : (string) $QSO,
1694
-                        ]
1695
-                    );
1696
-                }
1697
-                if ($QSO->opt_group()) {
1698
-                    $prepped_answer_options[ $QSO->opt_group() ][] = $QSO;
1699
-                } else {
1700
-                    $prepped_answer_options[] = $QSO;
1701
-                }
1702
-            }
1703
-        }
1704
-        //      d( $prepped_answer_options );
1705
-        return $prepped_answer_options;
1706
-    }
1707
-
1708
-
1709
-    /**
1710
-     *  prep_option_value
1711
-     *
1712
-     * @param string $option_value
1713
-     * @return string
1714
-     */
1715
-    public static function prep_option_value($option_value)
1716
-    {
1717
-        return esc_attr(trim(stripslashes($option_value)));
1718
-    }
1719
-
1720
-
1721
-    /**
1722
-     *  prep_required
1723
-     *
1724
-     * @param string|array $required
1725
-     * @return array
1726
-     */
1727
-    public static function prep_required($required = [])
1728
-    {
1729
-        // make sure required is an array
1730
-        $required = is_array($required) ? $required : [];
1731
-        // and set some defaults
1732
-        return array_merge(['label' => '', 'class' => '', 'msg' => ''], $required);
1733
-    }
1734
-
1735
-
1736
-    /**
1737
-     *  get_label_size_class
1738
-     *
1739
-     * @param string $value
1740
-     * @return string
1741
-     */
1742
-    public static function get_label_size_class($value = false)
1743
-    {
1744
-        if ($value === false || $value === '') {
1745
-            return ' class="medium-lbl"';
1746
-        }
1747
-        // determine length of option value
1748
-        $val_size = strlen($value);
1749
-        switch ($val_size) {
1750
-            case $val_size < 3:
1751
-                $size = ' class="nano-lbl"';
1752
-                break;
1753
-            case $val_size < 6:
1754
-                $size = ' class="micro-lbl"';
1755
-                break;
1756
-            case $val_size < 12:
1757
-                $size = ' class="tiny-lbl"';
1758
-                break;
1759
-            case $val_size < 25:
1760
-                $size = ' class="small-lbl"';
1761
-                break;
1762
-            case $val_size > 100:
1763
-                $size = ' class="big-lbl"';
1764
-                break;
1765
-            default:
1766
-                $size = ' class="medium-lbl"';
1767
-                break;
1768
-        }
1769
-        return $size;
1770
-    }
1771
-
1772
-
1773
-    /**
1774
-     *  _load_system_dropdowns
1775
-     *
1776
-     * @param EE_Question_Form_Input $QFI
1777
-     * @return array
1778
-     * @throws EE_Error
1779
-     * @throws ReflectionException
1780
-     */
1781
-    private static function _load_system_dropdowns($QFI)
1782
-    {
1783
-        $QST_system = $QFI->get('QST_system');
1784
-        switch ($QST_system) {
1785
-            case 'state':
1786
-                $QFI = self::generate_state_dropdown($QFI);
1787
-                break;
1788
-            case 'country':
1789
-                $QFI = self::generate_country_dropdown($QFI);
1790
-                break;
1791
-            case 'admin-state':
1792
-                $QFI = self::generate_state_dropdown($QFI, true);
1793
-                break;
1794
-            case 'admin-country':
1795
-                $QFI = self::generate_country_dropdown($QFI, true);
1796
-                break;
1797
-        }
1798
-        return $QFI;
1799
-    }
1800
-
1801
-
1802
-    /**
1803
-     * This preps dropdowns that are specialized.
1804
-     *
1805
-     * @param EE_Question_Form_Input $QFI
1806
-     *
1807
-     * @return EE_Question_Form_Input
1808
-     * @throws EE_Error
1809
-     * @throws ReflectionException
1810
-     * @since  4.6.0
1811
-     */
1812
-    protected static function _load_specialized_dropdowns($QFI)
1813
-    {
1814
-        switch ($QFI->get('QST_type')) {
1815
-            case 'STATE':
1816
-                $QFI = self::generate_state_dropdown($QFI);
1817
-                break;
1818
-            case 'COUNTRY':
1819
-                $QFI = self::generate_country_dropdown($QFI);
1820
-                break;
1821
-        }
1822
-        return $QFI;
1823
-    }
1824
-
1825
-
1826
-    /**
1827
-     *    generate_state_dropdown
1828
-     *
1829
-     * @param EE_Question_Form_Input $QST
1830
-     * @param bool                   $get_all
1831
-     * @return EE_Question_Form_Input
1832
-     * @throws EE_Error
1833
-     * @throws ReflectionException
1834
-     */
1835
-    public static function generate_state_dropdown($QST, $get_all = false)
1836
-    {
1837
-        $states = $get_all
1838
-            ? EEM_State::instance()->get_all_states()
1839
-            : EEM_State::instance()->get_all_states_of_active_countries();
1840
-        if ($states && count($states) != count($QST->options())) {
1841
-            $QST->set('QST_type', 'DROPDOWN');
1842
-            // if multiple countries, we'll create option groups within the dropdown
1843
-            foreach ($states as $state) {
1844
-                if ($state instanceof EE_State) {
1845
-                    $QSO = EE_Question_Option::new_instance(
1846
-                        [
1847
-                            'QSO_value'   => $state->ID(),
1848
-                            'QSO_desc'    => $state->name(),
1849
-                            'QST_ID'      => $QST->get('QST_ID'),
1850
-                            'QSO_deleted' => false,
1851
-                        ]
1852
-                    );
1853
-                    // set option group
1854
-                    $QSO->set_opt_group($state->country()->name());
1855
-                    // add option to question
1856
-                    $QST->add_temp_option($QSO);
1857
-                }
1858
-            }
1859
-        }
1860
-        return $QST;
1861
-    }
1862
-
1863
-
1864
-    /**
1865
-     *    generate_country_dropdown
1866
-     *
1867
-     * @param      $QST
1868
-     * @param bool $get_all
1869
-     * @return array
1870
-     * @throws EE_Error
1871
-     * @throws ReflectionException
1872
-     * @internal param array $question
1873
-     */
1874
-    public static function generate_country_dropdown($QST, $get_all = false)
1875
-    {
1876
-        $countries = $get_all
1877
-            ? EEM_Country::instance()->get_all_countries()
1878
-            : EEM_Country::instance()->get_all_active_countries();
1879
-        if ($countries && count($countries) != count($QST->options())) {
1880
-            $QST->set('QST_type', 'DROPDOWN');
1881
-            // now add countries
1882
-            foreach ($countries as $country) {
1883
-                if ($country instanceof EE_Country) {
1884
-                    $QSO = EE_Question_Option::new_instance(
1885
-                        [
1886
-                            'QSO_value'   => $country->ID(),
1887
-                            'QSO_desc'    => $country->name(),
1888
-                            'QST_ID'      => $QST->get('QST_ID'),
1889
-                            'QSO_deleted' => false,
1890
-                        ]
1891
-                    );
1892
-                    $QST->add_temp_option($QSO);
1893
-                }
1894
-            }
1895
-        }
1896
-        return $QST;
1897
-    }
1898
-
1899
-
1900
-    /**
1901
-     *  generates options for a month dropdown selector with numbers from 01 to 12
1902
-     *
1903
-     * @return array()
1904
-     */
1905
-    public static function two_digit_months_dropdown_options()
1906
-    {
1907
-        $options = [];
1908
-        for ($x = 1; $x <= 12; $x++) {
1909
-            $mm             = str_pad($x, 2, '0', STR_PAD_LEFT);
1910
-            $options[ $mm ] = $mm;
1911
-        }
1912
-        return EEH_Form_Fields::prep_answer_options($options);
1913
-    }
1914
-
1915
-
1916
-    /**
1917
-     *  generates a year dropdown selector with numbers for the next ten years
1918
-     *
1919
-     * @return array
1920
-     */
1921
-    public static function next_decade_two_digit_year_dropdown_options()
1922
-    {
1923
-        $options      = [];
1924
-        $current_year = date('y');
1925
-        $next_decade  = $current_year + 10;
1926
-        for ($x = $current_year; $x <= $next_decade; $x++) {
1927
-            $yy             = str_pad($x, 2, '0', STR_PAD_LEFT);
1928
-            $options[ $yy ] = $yy;
1929
-        }
1930
-        return EEH_Form_Fields::prep_answer_options($options);
1931
-    }
1932
-
1933
-
1934
-    /**
1935
-     * generates a month/year dropdown selector for all registrations matching the given criteria.  Typically used for
1936
-     * list table filter.
1937
-     *
1938
-     * @param string  $cur_date     any currently selected date can be entered here.
1939
-     * @param string  $status       Registration status
1940
-     * @param integer $evt_category Event Category ID if the Event Category filter is selected
1941
-     * @return string                html
1942
-     * @throws EE_Error
1943
-     */
1944
-    public static function generate_registration_months_dropdown($cur_date = '', $status = '', $evt_category = 0)
1945
-    {
1946
-        $_where = [];
1947
-        if (! empty($status)) {
1948
-            $_where['STS_ID'] = $status;
1949
-        }
1950
-
1951
-        if ($evt_category > 0) {
1952
-            $_where['Event.Term_Taxonomy.term_id'] = $evt_category;
1953
-        }
1954
-
1955
-        $regdtts = EEM_Registration::instance()->get_reg_months_and_years($_where);
1956
-
1957
-        // setup vals for select input helper
1958
-        $options = [
1959
-            0 => [
1960
-                'text' => esc_html__('Select a Month/Year', 'event_espresso'),
1961
-                'id'   => '',
1962
-            ],
1963
-        ];
1964
-
1965
-        foreach ($regdtts as $regdtt) {
1966
-            $date      = $regdtt->reg_month . ' ' . $regdtt->reg_year;
1967
-            $options[] = [
1968
-                'text' => $date,
1969
-                'id'   => $date,
1970
-            ];
1971
-        }
1972
-
1973
-        return self::select_input('month_range', $options, $cur_date);
1974
-    }
1975
-
1976
-
1977
-    /**
1978
-     * generates a month/year dropdown selector for all events matching the given criteria
1979
-     * Typically used for list table filter
1980
-     *
1981
-     * @param string $cur_date          any currently selected date can be entered here.
1982
-     * @param string $status            "view" (i.e. all, today, month, draft)
1983
-     * @param int    $evt_category      category event belongs to
1984
-     * @param string $evt_active_status "upcoming", "expired", "active", or "inactive"
1985
-     * @return string                    html
1986
-     * @throws EE_Error
1987
-     */
1988
-    public static function generate_event_months_dropdown(
1989
-        $cur_date = '',
1990
-        $status = null,
1991
-        $evt_category = null,
1992
-        $evt_active_status = null
1993
-    ) {
1994
-        // determine what post_status our condition will have for the query.
1995
-        // phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
1996
-        switch ($status) {
1997
-            case 'month':
1998
-            case 'today':
1999
-            case null:
2000
-            case 'all':
2001
-                $where['Event.status'] = ['NOT IN', ['trash']];
2002
-                break;
2003
-            case 'draft':
2004
-                $where['Event.status'] = ['IN', ['draft', 'auto-draft']];
2005
-                break;
2006
-            default:
2007
-                $where['Event.status'] = $status;
2008
-        }
2009
-
2010
-        // phpcs:enable
2011
-
2012
-        // categories?
2013
-
2014
-
2015
-        if (! empty($evt_category) and $evt_category > 0) {
2016
-            $where['Event.Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
2017
-            $where['Event.Term_Taxonomy.term_id']  = $evt_category;
2018
-        }
2019
-
2020
-
2021
-        //      $where['DTT_is_primary'] = 1;
2022
-
2023
-        $DTTS = EEM_Datetime::instance()->get_dtt_months_and_years($where, $evt_active_status);
2024
-
2025
-        // let's setup vals for select input helper
2026
-        $options = [
2027
-            0 => [
2028
-                'text' => esc_html__('Select a Month/Year', 'event_espresso'),
2029
-                'id'   => "",
2030
-            ],
2031
-        ];
2032
-
2033
-
2034
-        // translate month and date
2035
-        global $wp_locale;
2036
-
2037
-        foreach ($DTTS as $DTT) {
2038
-            $localized_date = $wp_locale->get_month($DTT->dtt_month_num) . ' ' . $DTT->dtt_year;
2039
-            $id             = $DTT->dtt_month . ' ' . $DTT->dtt_year;
2040
-            $options[]      = [
2041
-                'text' => $localized_date,
2042
-                'id'   => $id,
2043
-            ];
2044
-        }
2045
-
2046
-
2047
-        return self::select_input('month_range', $options, $cur_date);
2048
-    }
2049
-
2050
-
2051
-    /**
2052
-     * generates the dropdown selector for event categories
2053
-     * typically used as a filter on list tables.
2054
-     *
2055
-     * @param integer $current_cat currently selected category
2056
-     * @return string               html for dropdown
2057
-     * @throws EE_Error
2058
-     * @throws ReflectionException
2059
-     */
2060
-    public static function generate_event_category_dropdown($current_cat = -1)
2061
-    {
2062
-        $categories = EEM_Term::instance()->get_all_ee_categories(true);
2063
-        $options    = [
2064
-            '0' => [
2065
-                'text' => esc_html__('All Categories', 'event_espresso'),
2066
-                'id'   => -1,
2067
-            ],
2068
-        ];
2069
-
2070
-        // setup categories for dropdown
2071
-        foreach ($categories as $category) {
2072
-            $options[] = [
2073
-                'text' => $category->get('name'),
2074
-                'id'   => $category->ID(),
2075
-            ];
2076
-        }
2077
-
2078
-        return self::select_input('EVT_CAT', $options, $current_cat);
2079
-    }
2080
-
2081
-
2082
-    /**
2083
-     *    generate a submit button with or without it's own microform
2084
-     *    this is the only way to create buttons that are compatible across all themes
2085
-     *
2086
-     * @access    public
2087
-     * @param string      $url              - the form action
2088
-     * @param string      $ID               - some kind of unique ID, appended with "-sbmt" for the input and "-frm"
2089
-     *                                      for the form
2090
-     * @param string      $class            - css classes (separated by spaces if more than one)
2091
-     * @param string      $text             - what appears on the button
2092
-     * @param string      $nonce_action     - if using nonces
2093
-     * @param bool|string $input_only       - whether to print form header and footer. TRUE returns the input without
2094
-     *                                      the form
2095
-     * @param string      $extra_attributes - any extra attributes that need to be attached to the form input
2096
-     * @return    string
2097
-     */
2098
-    public static function submit_button(
2099
-        $url = '',
2100
-        $ID = '',
2101
-        $class = '',
2102
-        $text = '',
2103
-        $nonce_action = '',
2104
-        $input_only = false,
2105
-        $extra_attributes = ''
2106
-    ) {
2107
-        $btn = '';
2108
-        if (empty($url) || empty($ID)) {
2109
-            return $btn;
2110
-        }
2111
-        $text = ! empty($text) ? $text : esc_html__('Submit', 'event_espresso');
2112
-        $btn  .= '<input id="' . $ID . '-btn" class="' . $class . '" '
2113
-                 . 'type="submit" value="' . $text . '" ' . $extra_attributes . '/>';
2114
-        if (! $input_only) {
2115
-            $btn_frm = '<form id="' . $ID . '-frm" method="POST" action="' . $url . '">';
2116
-            $btn_frm .= ! empty($nonce_action)
2117
-                ? wp_nonce_field($nonce_action, $nonce_action . '_nonce', true, false)
2118
-                : '';
2119
-            $btn_frm .= $btn;
2120
-            $btn_frm .= '</form>';
2121
-            $btn     = $btn_frm;
2122
-            unset($btn_frm);
2123
-        }
2124
-        return $btn;
2125
-    }
1091
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1092
+		return $label_html . $input_html;
1093
+	}
1094
+
1095
+
1096
+	/**
1097
+	 * generates HTML for a form textarea
1098
+	 *
1099
+	 * @param string $question    label content
1100
+	 * @param string $answer      form input value attribute
1101
+	 * @param string $name        form input name attribute
1102
+	 * @param string $id          form input css id attribute
1103
+	 * @param string $class       form input css class attribute
1104
+	 * @param array  $dimensions  array of form input rows and cols attributes : array( 'rows' => 3, 'cols' => 40 )
1105
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1106
+	 *                            required 'class', and required 'msg' attribute
1107
+	 * @param string $label_class css class attribute for the label
1108
+	 * @param string $disabled    disabled="disabled" or null
1109
+	 * @return string HTML
1110
+	 */
1111
+	public static function textarea(
1112
+		$question = false,
1113
+		$answer = null,
1114
+		$name = false,
1115
+		$id = '',
1116
+		$class = '',
1117
+		$dimensions = false,
1118
+		$required = false,
1119
+		$required_text = '',
1120
+		$label_class = '',
1121
+		$disabled = false,
1122
+		$system_ID = false,
1123
+		$use_html_entities = true,
1124
+		$add_mobile_label = false
1125
+	) {
1126
+		// need these
1127
+		if (! $question || ! $name) {
1128
+			return null;
1129
+		}
1130
+		// prep the answer
1131
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1132
+		// prep the required array
1133
+		$required = self::prep_required($required);
1134
+		// make sure $dimensions is an array
1135
+		$dimensions = is_array($dimensions) ? $dimensions : [];
1136
+		// and set some defaults
1137
+		$dimensions = array_merge(['rows' => 3, 'cols' => 40], $dimensions);
1138
+		// set disabled tag
1139
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1140
+		// ya gots ta have style man!!!
1141
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1142
+		$class     .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1143
+		$extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1144
+
1145
+		$label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1146
+		$mobile_label = self::mobileLabel(
1147
+			$add_mobile_label,
1148
+			$question,
1149
+			$required_text,
1150
+			$required['label'],
1151
+			$label_class,
1152
+			$name
1153
+		);
1154
+
1155
+		$input_html = $mobile_label
1156
+			. '<textarea name="' . $name . '" id="' . $id . '" class="' . trim($class) . '" '
1157
+			. 'rows="' . $dimensions['rows'] . '" cols="' . $dimensions['cols'] . '"  '
1158
+			. 'aria-label="' . $required['msg'] . '" ' . $disabled . ' ' . $extra . '>'
1159
+			 . esc_textarea($answer)
1160
+			  . '</textarea>';
1161
+
1162
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1163
+		return $label_html . $input_html;
1164
+	}
1165
+
1166
+
1167
+	/**
1168
+	 * generates HTML for a form select input
1169
+	 *
1170
+	 * @param string $question    label content
1171
+	 * @param string $answer      form input value attribute
1172
+	 * @param array  $options     array of answer options where array key = option value and array value = option
1173
+	 *                            display text
1174
+	 * @param string $name        form input name attribute
1175
+	 * @param string $id          form input css id attribute
1176
+	 * @param string $class       form input css class attribute
1177
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1178
+	 *                            required 'class', and required 'msg' attribute
1179
+	 * @param string $label_class css class attribute for the label
1180
+	 * @param string $disabled    disabled="disabled" or null
1181
+	 * @return string HTML
1182
+	 */
1183
+	public static function select(
1184
+		$question = false,
1185
+		$answer = null,
1186
+		$options = false,
1187
+		$name = false,
1188
+		$id = '',
1189
+		$class = '',
1190
+		$required = false,
1191
+		$required_text = '',
1192
+		$label_class = '',
1193
+		$disabled = false,
1194
+		$system_ID = false,
1195
+		$use_html_entities = true,
1196
+		$add_please_select_option = false,
1197
+		$add_mobile_label = false
1198
+	) {
1199
+
1200
+		// need these
1201
+		if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1202
+			return null;
1203
+		}
1204
+		// prep the answer
1205
+		$answer = is_array($answer)
1206
+			? self::prep_answer(array_shift($answer), $use_html_entities)
1207
+			: self::prep_answer($answer, $use_html_entities);
1208
+		// prep the required array
1209
+		$required = self::prep_required($required);
1210
+		// set disabled tag
1211
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1212
+		// ya gots ta have style man!!!
1213
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1214
+		$class = self::appendInputSizeClass($class, $options);
1215
+		$extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1216
+
1217
+		$label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1218
+		$mobile_label = self::mobileLabel(
1219
+			$add_mobile_label,
1220
+			$question,
1221
+			$required_text,
1222
+			$required['label'],
1223
+			$label_class,
1224
+			$name
1225
+		);
1226
+
1227
+		$input_html = $mobile_label
1228
+			. '<select name="' . $name . '" id="' . $id . '" class="' . trim($class) . ' ' . $required['class'] . '" '
1229
+			. 'aria-label="' . esc_attr($required['msg']) . '"' . $disabled . ' ' . $extra . '>';
1230
+		// recursively count array elements, to determine total number of options
1231
+		$only_option = count($options, 1) == 1;
1232
+		if (! $only_option) {
1233
+			// if there is NO answer set and there are multiple options to choose from, then set the "please select" message as selected
1234
+			$selected   = $answer === null ? ' selected' : '';
1235
+			$input_html .= $add_please_select_option
1236
+				? "\n\t\t\t\t"
1237
+				  . '<option value=""' . $selected . '>'
1238
+				  . esc_html__(' - please select - ', 'event_espresso')
1239
+				  . '</option>'
1240
+				: '';
1241
+		}
1242
+		foreach ($options as $key => $value) {
1243
+			// if value is an array, then create option groups, else create regular ol' options
1244
+			$input_html .= is_array($value)
1245
+				? self::_generate_select_option_group(
1246
+					$key,
1247
+					$value,
1248
+					$answer,
1249
+					$use_html_entities
1250
+				)
1251
+				: self::_generate_select_option(
1252
+					$value->value(),
1253
+					$value->desc(),
1254
+					$answer,
1255
+					$only_option,
1256
+					$use_html_entities
1257
+				);
1258
+		}
1259
+
1260
+		$input_html .= "\n\t\t\t" . '</select>';
1261
+
1262
+		$input_html =
1263
+			apply_filters(
1264
+				'FHEE__EEH_Form_Fields__select__before_end_wrapper',
1265
+				$input_html,
1266
+				$question,
1267
+				$answer,
1268
+				$name,
1269
+				$id,
1270
+				$class,
1271
+				$system_ID
1272
+			);
1273
+
1274
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1275
+		return $label_html . $input_html;
1276
+	}
1277
+
1278
+
1279
+	/**
1280
+	 *  _generate_select_option_group
1281
+	 *
1282
+	 *  if  $value for a select box is an array, then the key will be used as the optgroup label
1283
+	 *  and the value array will be looped thru and the elements sent to _generate_select_option
1284
+	 *
1285
+	 * @param mixed   $opt_group
1286
+	 * @param mixed   $QSOs
1287
+	 * @param mixed   $answer
1288
+	 * @param boolean $use_html_entities
1289
+	 * @return string
1290
+	 */
1291
+	private static function _generate_select_option_group($opt_group, $QSOs, $answer, $use_html_entities = true)
1292
+	{
1293
+		$html = "\n\t\t\t\t" . '<optgroup label="' . self::prep_option_value($opt_group) . '">';
1294
+		foreach ($QSOs as $QSO) {
1295
+			$html .= self::_generate_select_option($QSO->value(), $QSO->desc(), $answer, false, $use_html_entities);
1296
+		}
1297
+		$html .= "\n\t\t\t\t" . '</optgroup>';
1298
+		return $html;
1299
+	}
1300
+
1301
+
1302
+	/**
1303
+	 *  _generate_select_option
1304
+	 *
1305
+	 * @param mixed   $key
1306
+	 * @param mixed   $value
1307
+	 * @param mixed   $answer
1308
+	 * @param int     $only_option
1309
+	 * @param boolean $use_html_entities
1310
+	 * @return string
1311
+	 */
1312
+	private static function _generate_select_option(
1313
+		$key,
1314
+		$value,
1315
+		$answer,
1316
+		$only_option = false,
1317
+		$use_html_entities = true
1318
+	) {
1319
+		$key      = self::prep_answer($key, $use_html_entities);
1320
+		$value    = self::prep_answer($value, $use_html_entities);
1321
+		$value    = ! empty($value) ? $value : $key;
1322
+		$selected = ($answer == $key || $only_option) ? 'selected' : '';
1323
+		return "\n\t\t\t\t"
1324
+			   . '<option value="' . self::prep_option_value($key) . '" ' . $selected . '> '
1325
+			   . $value
1326
+			   . '&nbsp;&nbsp;&nbsp;</option>';
1327
+	}
1328
+
1329
+
1330
+	/**
1331
+	 * generates HTML for form radio button inputs
1332
+	 *
1333
+	 * @param bool|string $question    label content
1334
+	 * @param string      $answer      form input value attribute
1335
+	 * @param array|bool  $options     array of answer options where array key = option value and array value = option
1336
+	 *                                 display text
1337
+	 * @param bool|string $name        form input name attribute
1338
+	 * @param string      $id          form input css id attribute
1339
+	 * @param string      $class       form input css class attribute
1340
+	 * @param array|bool  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1341
+	 *                                 required 'class', and required 'msg' attribute
1342
+	 * @param string      $required_text
1343
+	 * @param string      $label_class css class attribute for the label
1344
+	 * @param bool|string $disabled    disabled="disabled" or null
1345
+	 * @param bool        $system_ID
1346
+	 * @param bool        $use_html_entities
1347
+	 * @param bool        $label_b4
1348
+	 * @param bool        $use_desc_4_label
1349
+	 * @return string HTML
1350
+	 */
1351
+	public static function radio(
1352
+		$question = false,
1353
+		$answer = null,
1354
+		$options = false,
1355
+		$name = false,
1356
+		$id = '',
1357
+		$class = '',
1358
+		$required = false,
1359
+		$required_text = '',
1360
+		$label_class = '',
1361
+		$disabled = false,
1362
+		$system_ID = false,
1363
+		$use_html_entities = true,
1364
+		$label_b4 = false,
1365
+		$use_desc_4_label = false,
1366
+		$add_mobile_label = false
1367
+	) {
1368
+		// need these
1369
+		if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1370
+			return null;
1371
+		}
1372
+		// prep the answer
1373
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1374
+		// prep the required array
1375
+		$required = self::prep_required($required);
1376
+		// set disabled tag
1377
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1378
+		// ya gots ta have style man!!!
1379
+		$radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1380
+		$class       = ! empty($class) ? $class : 'espresso-radio-btn-inp';
1381
+		$extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1382
+
1383
+		$label_html = self::label($question, $required_text, $required['label'], '', $label_class);
1384
+		$mobile_label = self::mobileLabel(
1385
+			$add_mobile_label,
1386
+			$question,
1387
+			$required_text,
1388
+			$required['label'],
1389
+			$label_class
1390
+		);
1391
+
1392
+		$input_html = $mobile_label
1393
+			. '<ul id="' . $id . '-ul" class="espresso-radio-btn-options-ul ' . $class . '-ul">';
1394
+
1395
+		$class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1396
+		$class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1397
+
1398
+		foreach ($options as $OPT) {
1399
+			if ($OPT instanceof EE_Question_Option) {
1400
+				$value   = self::prep_option_value($OPT->value());
1401
+				$label   = $use_desc_4_label ? $OPT->desc() : $OPT->value();
1402
+				$size    = $use_desc_4_label
1403
+					? self::get_label_size_class($OPT->value() . ' ' . $OPT->desc())
1404
+					: self::get_label_size_class($OPT->value());
1405
+				$desc    = $OPT->desc();// no self::prep_answer
1406
+				$answer  = is_numeric($value) && empty($answer) ? 0 : $answer;
1407
+				$checked = (string) $value == (string) $answer ? ' checked' : '';
1408
+				$opt     = '-' . sanitize_key($value);
1409
+
1410
+				$input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1411
+				$input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-radio-btn-lbl">';
1412
+				$input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $label . '</span>&nbsp;' : '';
1413
+				$input_html .= "\n\t\t\t\t\t\t"
1414
+							   . '<input type="radio" name="' . $name . '" id="' . $id . $opt . '" '
1415
+							   . 'class="' . $class . '" value="' . $value . '" '
1416
+							   . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled
1417
+							   . $checked . ' ' . $extra . '/>';
1418
+				$input_html .= ! $label_b4
1419
+					? "\n\t\t\t\t\t\t"
1420
+					  . '&nbsp;<span class="espresso-radio-btn-desc">'
1421
+					  . $label
1422
+					  . '</span>'
1423
+					: '';
1424
+				$input_html .= "\n\t\t\t\t\t" . '</label>';
1425
+				$input_html .= $use_desc_4_label
1426
+					? ''
1427
+					: '<span class="espresso-radio-btn-option-desc small-text grey-text">' . $desc . '</span>';
1428
+				$input_html .= "\n\t\t\t\t" . '</li>';
1429
+			}
1430
+		}
1431
+
1432
+		$input_html .= "\n\t\t\t" . '</ul>';
1433
+
1434
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1435
+		return $label_html . $input_html;
1436
+	}
1437
+
1438
+
1439
+	/**
1440
+	 * generates HTML for form checkbox inputs
1441
+	 *
1442
+	 * @param string $question    label content
1443
+	 * @param string $answer      form input value attribute
1444
+	 * @param array  $options     array of options where array key = option value and array value = option display text
1445
+	 * @param string $name        form input name attribute
1446
+	 * @param string $id          form input css id attribute
1447
+	 * @param string $class       form input css class attribute
1448
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1449
+	 *                            required 'class', and required 'msg' attribute
1450
+	 * @param string $label_class css class attribute for the label
1451
+	 * @param string $disabled    disabled="disabled" or null
1452
+	 * @return string HTML
1453
+	 */
1454
+	public static function checkbox(
1455
+		$question = false,
1456
+		$answer = null,
1457
+		$options = false,
1458
+		$name = false,
1459
+		$id = '',
1460
+		$class = '',
1461
+		$required = false,
1462
+		$required_text = '',
1463
+		$label_class = '',
1464
+		$disabled = false,
1465
+		$label_b4 = false,
1466
+		$system_ID = false,
1467
+		$use_html_entities = true,
1468
+		$add_mobile_label = false
1469
+	) {
1470
+		// need these
1471
+		if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1472
+			return null;
1473
+		}
1474
+		$answer = maybe_unserialize($answer);
1475
+
1476
+		// prep the answer(s)
1477
+		$answer = is_array($answer) ? $answer : [sanitize_key($answer) => $answer];
1478
+
1479
+		foreach ($answer as $key => $value) {
1480
+			$key            = self::prep_option_value($key);
1481
+			$answer[ $key ] = self::prep_answer($value, $use_html_entities);
1482
+		}
1483
+
1484
+		// prep the required array
1485
+		$required = self::prep_required($required);
1486
+		// set disabled tag
1487
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1488
+		// ya gots ta have style man!!!
1489
+		$radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1490
+		$class       = empty($class) ? 'espresso-radio-btn-inp' : $class;
1491
+		$extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1492
+
1493
+		$label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1494
+		$mobile_label = self::mobileLabel(
1495
+			$add_mobile_label,
1496
+			$question,
1497
+			$required_text,
1498
+			$required['label'],
1499
+			$label_class
1500
+		);
1501
+
1502
+		$input_html = $mobile_label
1503
+			. '<ul id="' . $id . '-ul" class="espresso-checkbox-options-ul ' . $class . '-ul">';
1504
+
1505
+		$class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1506
+		$class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1507
+
1508
+		foreach ($options as $OPT) {
1509
+			$value = $OPT->value();// self::prep_option_value( $OPT->value() );
1510
+			$size  = self::get_label_size_class($OPT->value() . ' ' . $OPT->desc());
1511
+			$text  = self::prep_answer($OPT->value());
1512
+			$desc  = $OPT->desc();
1513
+			$opt   = '-' . sanitize_key($value);
1514
+
1515
+			$checked = is_array($answer) && in_array($text, $answer) ? ' checked' : '';
1516
+
1517
+			$input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1518
+			$input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-checkbox-lbl">';
1519
+			$input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $text . '</span>&nbsp;' : '';
1520
+			$input_html .= "\n\t\t\t\t\t\t"
1521
+						   . '<input type="checkbox" name="' . $name . '[' . $OPT->ID() . ']" '
1522
+						   . 'id="' . $id . $opt . '" class="' . $class . '" value="' . $value . '" '
1523
+						   . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . $checked . ' ' . $extra . '/>';
1524
+			$input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t" . '&nbsp;<span>' . $text . '</span>' : '';
1525
+			$input_html .= "\n\t\t\t\t\t" . '</label>';
1526
+			if (! empty($desc) && $desc != $text) {
1527
+				$input_html .= "\n\t\t\t\t\t"
1528
+							   . ' &nbsp; <br/><div class="espresso-checkbox-option-desc small-text grey-text">'
1529
+							   . $desc
1530
+							   . '</div>';
1531
+			}
1532
+			$input_html .= "\n\t\t\t\t" . '</li>';
1533
+		}
1534
+
1535
+		$input_html .= "\n\t\t\t" . '</ul>';
1536
+
1537
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1538
+		return $label_html . $input_html;
1539
+	}
1540
+
1541
+
1542
+	/**
1543
+	 * generates HTML for a form datepicker input
1544
+	 *
1545
+	 * @param string $question    label content
1546
+	 * @param string $answer      form input value attribute
1547
+	 * @param string $name        form input name attribute
1548
+	 * @param string $id          form input css id attribute
1549
+	 * @param string $class       form input css class attribute
1550
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1551
+	 *                            required 'class', and required 'msg' attribute
1552
+	 * @param string $label_class css class attribute for the label
1553
+	 * @param string $disabled    disabled="disabled" or null
1554
+	 * @return string HTML
1555
+	 */
1556
+	public static function datepicker(
1557
+		$question = false,
1558
+		$answer = null,
1559
+		$name = false,
1560
+		$id = '',
1561
+		$class = '',
1562
+		$required = false,
1563
+		$required_text = '',
1564
+		$label_class = '',
1565
+		$disabled = false,
1566
+		$system_ID = false,
1567
+		$use_html_entities = true,
1568
+		$add_mobile_label = false
1569
+	) {
1570
+		// need these
1571
+		if (! $question || ! $name) {
1572
+			return null;
1573
+		}
1574
+		// prep the answer
1575
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1576
+		// prep the required array
1577
+		$required = self::prep_required($required);
1578
+		// set disabled tag
1579
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1580
+		// ya gots ta have style man!!!
1581
+		$txt_class = is_admin() ? 'regular-text' : 'espresso-datepicker-inp';
1582
+		$class     = empty($class) ? $txt_class : $class;
1583
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1584
+		$class = self::appendInputSizeClass($class, $answer);
1585
+		$extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1586
+
1587
+		$label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1588
+		$mobile_label = self::mobileLabel(
1589
+			$add_mobile_label,
1590
+			$question,
1591
+			$required_text,
1592
+			$required['label'],
1593
+			$label_class,
1594
+			$name
1595
+		);
1596
+
1597
+		$input_html = $mobile_label
1598
+			. '<input type="text" name="' . $name . '" id="' . $id . '" '
1599
+			. 'class="' . $class . ' ' . $required['class'] . ' datepicker" value="' . $answer . '"  '
1600
+			. 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . ' ' . $extra . '/>';
1601
+
1602
+		// enqueue scripts
1603
+		wp_register_style(
1604
+			'espresso-ui-theme',
1605
+			EE_GLOBAL_ASSETS_URL . 'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1606
+			[],
1607
+			EVENT_ESPRESSO_VERSION
1608
+		);
1609
+		wp_enqueue_style('espresso-ui-theme');
1610
+		wp_enqueue_script('jquery-ui-datepicker');
1611
+
1612
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1613
+		return $label_html . $input_html;
1614
+	}
1615
+
1616
+
1617
+	/**
1618
+	 *  remove_label_keep_required_msg
1619
+	 *  this will strip out a form input's label HTML while keeping the required text HTML that MUST be before the label
1620
+	 *
1621
+	 * @access public
1622
+	 * @return     string
1623
+	 */
1624
+	public static function remove_label_keep_required_msg($label_html, $required_text)
1625
+	{
1626
+		return $required_text;
1627
+	}
1628
+
1629
+
1630
+	/**
1631
+	 * Simply returns the HTML for a hidden input of the given name and value.
1632
+	 *
1633
+	 * @param string $name
1634
+	 * @param string $value
1635
+	 * @return string HTML
1636
+	 */
1637
+	public static function hidden_input($name, $value, $id = '')
1638
+	{
1639
+		$id = ! empty($id) ? $id : $name;
1640
+		return '<input id="' . $id . '" type="hidden" name="' . $name . '" value="' . $value . '"/>';
1641
+	}
1642
+
1643
+
1644
+	/**
1645
+	 * prep_question
1646
+	 *
1647
+	 * @param string $question
1648
+	 * @return string
1649
+	 */
1650
+	public static function prep_question($question)
1651
+	{
1652
+		return $question;
1653
+	}
1654
+
1655
+
1656
+	/**
1657
+	 *  prep_answer
1658
+	 *
1659
+	 * @param mixed $answer
1660
+	 * @return string
1661
+	 */
1662
+	public static function prep_answer($answer, $use_html_entities = true)
1663
+	{
1664
+		// make sure we convert bools first.  Otherwise (bool) false becomes an empty string which is NOT desired,
1665
+		// we want "0".
1666
+		if (is_bool($answer)) {
1667
+			$answer = $answer ? 1 : 0;
1668
+		}
1669
+		$answer = trim(stripslashes(str_replace('&#039;', "'", $answer)));
1670
+		return $use_html_entities ? htmlentities($answer, ENT_QUOTES, 'UTF-8') : $answer;
1671
+	}
1672
+
1673
+
1674
+	/**
1675
+	 *  prep_answer_options
1676
+	 *
1677
+	 * @param array $QSOs array of EE_Question_Option objects
1678
+	 * @return array
1679
+	 */
1680
+	public static function prep_answer_options($QSOs = [])
1681
+	{
1682
+		$prepped_answer_options = [];
1683
+		if (is_array($QSOs) && ! empty($QSOs)) {
1684
+			foreach ($QSOs as $key => $QSO) {
1685
+				if (! $QSO instanceof EE_Question_Option) {
1686
+					$QSO = EE_Question_Option::new_instance(
1687
+						[
1688
+							'QSO_value' => is_array($QSO) && isset($QSO['id'])
1689
+								? (string) $QSO['id']
1690
+								: (string) $key,
1691
+							'QSO_desc'  => is_array($QSO) && isset($QSO['text'])
1692
+								? (string) $QSO['text']
1693
+								: (string) $QSO,
1694
+						]
1695
+					);
1696
+				}
1697
+				if ($QSO->opt_group()) {
1698
+					$prepped_answer_options[ $QSO->opt_group() ][] = $QSO;
1699
+				} else {
1700
+					$prepped_answer_options[] = $QSO;
1701
+				}
1702
+			}
1703
+		}
1704
+		//      d( $prepped_answer_options );
1705
+		return $prepped_answer_options;
1706
+	}
1707
+
1708
+
1709
+	/**
1710
+	 *  prep_option_value
1711
+	 *
1712
+	 * @param string $option_value
1713
+	 * @return string
1714
+	 */
1715
+	public static function prep_option_value($option_value)
1716
+	{
1717
+		return esc_attr(trim(stripslashes($option_value)));
1718
+	}
1719
+
1720
+
1721
+	/**
1722
+	 *  prep_required
1723
+	 *
1724
+	 * @param string|array $required
1725
+	 * @return array
1726
+	 */
1727
+	public static function prep_required($required = [])
1728
+	{
1729
+		// make sure required is an array
1730
+		$required = is_array($required) ? $required : [];
1731
+		// and set some defaults
1732
+		return array_merge(['label' => '', 'class' => '', 'msg' => ''], $required);
1733
+	}
1734
+
1735
+
1736
+	/**
1737
+	 *  get_label_size_class
1738
+	 *
1739
+	 * @param string $value
1740
+	 * @return string
1741
+	 */
1742
+	public static function get_label_size_class($value = false)
1743
+	{
1744
+		if ($value === false || $value === '') {
1745
+			return ' class="medium-lbl"';
1746
+		}
1747
+		// determine length of option value
1748
+		$val_size = strlen($value);
1749
+		switch ($val_size) {
1750
+			case $val_size < 3:
1751
+				$size = ' class="nano-lbl"';
1752
+				break;
1753
+			case $val_size < 6:
1754
+				$size = ' class="micro-lbl"';
1755
+				break;
1756
+			case $val_size < 12:
1757
+				$size = ' class="tiny-lbl"';
1758
+				break;
1759
+			case $val_size < 25:
1760
+				$size = ' class="small-lbl"';
1761
+				break;
1762
+			case $val_size > 100:
1763
+				$size = ' class="big-lbl"';
1764
+				break;
1765
+			default:
1766
+				$size = ' class="medium-lbl"';
1767
+				break;
1768
+		}
1769
+		return $size;
1770
+	}
1771
+
1772
+
1773
+	/**
1774
+	 *  _load_system_dropdowns
1775
+	 *
1776
+	 * @param EE_Question_Form_Input $QFI
1777
+	 * @return array
1778
+	 * @throws EE_Error
1779
+	 * @throws ReflectionException
1780
+	 */
1781
+	private static function _load_system_dropdowns($QFI)
1782
+	{
1783
+		$QST_system = $QFI->get('QST_system');
1784
+		switch ($QST_system) {
1785
+			case 'state':
1786
+				$QFI = self::generate_state_dropdown($QFI);
1787
+				break;
1788
+			case 'country':
1789
+				$QFI = self::generate_country_dropdown($QFI);
1790
+				break;
1791
+			case 'admin-state':
1792
+				$QFI = self::generate_state_dropdown($QFI, true);
1793
+				break;
1794
+			case 'admin-country':
1795
+				$QFI = self::generate_country_dropdown($QFI, true);
1796
+				break;
1797
+		}
1798
+		return $QFI;
1799
+	}
1800
+
1801
+
1802
+	/**
1803
+	 * This preps dropdowns that are specialized.
1804
+	 *
1805
+	 * @param EE_Question_Form_Input $QFI
1806
+	 *
1807
+	 * @return EE_Question_Form_Input
1808
+	 * @throws EE_Error
1809
+	 * @throws ReflectionException
1810
+	 * @since  4.6.0
1811
+	 */
1812
+	protected static function _load_specialized_dropdowns($QFI)
1813
+	{
1814
+		switch ($QFI->get('QST_type')) {
1815
+			case 'STATE':
1816
+				$QFI = self::generate_state_dropdown($QFI);
1817
+				break;
1818
+			case 'COUNTRY':
1819
+				$QFI = self::generate_country_dropdown($QFI);
1820
+				break;
1821
+		}
1822
+		return $QFI;
1823
+	}
1824
+
1825
+
1826
+	/**
1827
+	 *    generate_state_dropdown
1828
+	 *
1829
+	 * @param EE_Question_Form_Input $QST
1830
+	 * @param bool                   $get_all
1831
+	 * @return EE_Question_Form_Input
1832
+	 * @throws EE_Error
1833
+	 * @throws ReflectionException
1834
+	 */
1835
+	public static function generate_state_dropdown($QST, $get_all = false)
1836
+	{
1837
+		$states = $get_all
1838
+			? EEM_State::instance()->get_all_states()
1839
+			: EEM_State::instance()->get_all_states_of_active_countries();
1840
+		if ($states && count($states) != count($QST->options())) {
1841
+			$QST->set('QST_type', 'DROPDOWN');
1842
+			// if multiple countries, we'll create option groups within the dropdown
1843
+			foreach ($states as $state) {
1844
+				if ($state instanceof EE_State) {
1845
+					$QSO = EE_Question_Option::new_instance(
1846
+						[
1847
+							'QSO_value'   => $state->ID(),
1848
+							'QSO_desc'    => $state->name(),
1849
+							'QST_ID'      => $QST->get('QST_ID'),
1850
+							'QSO_deleted' => false,
1851
+						]
1852
+					);
1853
+					// set option group
1854
+					$QSO->set_opt_group($state->country()->name());
1855
+					// add option to question
1856
+					$QST->add_temp_option($QSO);
1857
+				}
1858
+			}
1859
+		}
1860
+		return $QST;
1861
+	}
1862
+
1863
+
1864
+	/**
1865
+	 *    generate_country_dropdown
1866
+	 *
1867
+	 * @param      $QST
1868
+	 * @param bool $get_all
1869
+	 * @return array
1870
+	 * @throws EE_Error
1871
+	 * @throws ReflectionException
1872
+	 * @internal param array $question
1873
+	 */
1874
+	public static function generate_country_dropdown($QST, $get_all = false)
1875
+	{
1876
+		$countries = $get_all
1877
+			? EEM_Country::instance()->get_all_countries()
1878
+			: EEM_Country::instance()->get_all_active_countries();
1879
+		if ($countries && count($countries) != count($QST->options())) {
1880
+			$QST->set('QST_type', 'DROPDOWN');
1881
+			// now add countries
1882
+			foreach ($countries as $country) {
1883
+				if ($country instanceof EE_Country) {
1884
+					$QSO = EE_Question_Option::new_instance(
1885
+						[
1886
+							'QSO_value'   => $country->ID(),
1887
+							'QSO_desc'    => $country->name(),
1888
+							'QST_ID'      => $QST->get('QST_ID'),
1889
+							'QSO_deleted' => false,
1890
+						]
1891
+					);
1892
+					$QST->add_temp_option($QSO);
1893
+				}
1894
+			}
1895
+		}
1896
+		return $QST;
1897
+	}
1898
+
1899
+
1900
+	/**
1901
+	 *  generates options for a month dropdown selector with numbers from 01 to 12
1902
+	 *
1903
+	 * @return array()
1904
+	 */
1905
+	public static function two_digit_months_dropdown_options()
1906
+	{
1907
+		$options = [];
1908
+		for ($x = 1; $x <= 12; $x++) {
1909
+			$mm             = str_pad($x, 2, '0', STR_PAD_LEFT);
1910
+			$options[ $mm ] = $mm;
1911
+		}
1912
+		return EEH_Form_Fields::prep_answer_options($options);
1913
+	}
1914
+
1915
+
1916
+	/**
1917
+	 *  generates a year dropdown selector with numbers for the next ten years
1918
+	 *
1919
+	 * @return array
1920
+	 */
1921
+	public static function next_decade_two_digit_year_dropdown_options()
1922
+	{
1923
+		$options      = [];
1924
+		$current_year = date('y');
1925
+		$next_decade  = $current_year + 10;
1926
+		for ($x = $current_year; $x <= $next_decade; $x++) {
1927
+			$yy             = str_pad($x, 2, '0', STR_PAD_LEFT);
1928
+			$options[ $yy ] = $yy;
1929
+		}
1930
+		return EEH_Form_Fields::prep_answer_options($options);
1931
+	}
1932
+
1933
+
1934
+	/**
1935
+	 * generates a month/year dropdown selector for all registrations matching the given criteria.  Typically used for
1936
+	 * list table filter.
1937
+	 *
1938
+	 * @param string  $cur_date     any currently selected date can be entered here.
1939
+	 * @param string  $status       Registration status
1940
+	 * @param integer $evt_category Event Category ID if the Event Category filter is selected
1941
+	 * @return string                html
1942
+	 * @throws EE_Error
1943
+	 */
1944
+	public static function generate_registration_months_dropdown($cur_date = '', $status = '', $evt_category = 0)
1945
+	{
1946
+		$_where = [];
1947
+		if (! empty($status)) {
1948
+			$_where['STS_ID'] = $status;
1949
+		}
1950
+
1951
+		if ($evt_category > 0) {
1952
+			$_where['Event.Term_Taxonomy.term_id'] = $evt_category;
1953
+		}
1954
+
1955
+		$regdtts = EEM_Registration::instance()->get_reg_months_and_years($_where);
1956
+
1957
+		// setup vals for select input helper
1958
+		$options = [
1959
+			0 => [
1960
+				'text' => esc_html__('Select a Month/Year', 'event_espresso'),
1961
+				'id'   => '',
1962
+			],
1963
+		];
1964
+
1965
+		foreach ($regdtts as $regdtt) {
1966
+			$date      = $regdtt->reg_month . ' ' . $regdtt->reg_year;
1967
+			$options[] = [
1968
+				'text' => $date,
1969
+				'id'   => $date,
1970
+			];
1971
+		}
1972
+
1973
+		return self::select_input('month_range', $options, $cur_date);
1974
+	}
1975
+
1976
+
1977
+	/**
1978
+	 * generates a month/year dropdown selector for all events matching the given criteria
1979
+	 * Typically used for list table filter
1980
+	 *
1981
+	 * @param string $cur_date          any currently selected date can be entered here.
1982
+	 * @param string $status            "view" (i.e. all, today, month, draft)
1983
+	 * @param int    $evt_category      category event belongs to
1984
+	 * @param string $evt_active_status "upcoming", "expired", "active", or "inactive"
1985
+	 * @return string                    html
1986
+	 * @throws EE_Error
1987
+	 */
1988
+	public static function generate_event_months_dropdown(
1989
+		$cur_date = '',
1990
+		$status = null,
1991
+		$evt_category = null,
1992
+		$evt_active_status = null
1993
+	) {
1994
+		// determine what post_status our condition will have for the query.
1995
+		// phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
1996
+		switch ($status) {
1997
+			case 'month':
1998
+			case 'today':
1999
+			case null:
2000
+			case 'all':
2001
+				$where['Event.status'] = ['NOT IN', ['trash']];
2002
+				break;
2003
+			case 'draft':
2004
+				$where['Event.status'] = ['IN', ['draft', 'auto-draft']];
2005
+				break;
2006
+			default:
2007
+				$where['Event.status'] = $status;
2008
+		}
2009
+
2010
+		// phpcs:enable
2011
+
2012
+		// categories?
2013
+
2014
+
2015
+		if (! empty($evt_category) and $evt_category > 0) {
2016
+			$where['Event.Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
2017
+			$where['Event.Term_Taxonomy.term_id']  = $evt_category;
2018
+		}
2019
+
2020
+
2021
+		//      $where['DTT_is_primary'] = 1;
2022
+
2023
+		$DTTS = EEM_Datetime::instance()->get_dtt_months_and_years($where, $evt_active_status);
2024
+
2025
+		// let's setup vals for select input helper
2026
+		$options = [
2027
+			0 => [
2028
+				'text' => esc_html__('Select a Month/Year', 'event_espresso'),
2029
+				'id'   => "",
2030
+			],
2031
+		];
2032
+
2033
+
2034
+		// translate month and date
2035
+		global $wp_locale;
2036
+
2037
+		foreach ($DTTS as $DTT) {
2038
+			$localized_date = $wp_locale->get_month($DTT->dtt_month_num) . ' ' . $DTT->dtt_year;
2039
+			$id             = $DTT->dtt_month . ' ' . $DTT->dtt_year;
2040
+			$options[]      = [
2041
+				'text' => $localized_date,
2042
+				'id'   => $id,
2043
+			];
2044
+		}
2045
+
2046
+
2047
+		return self::select_input('month_range', $options, $cur_date);
2048
+	}
2049
+
2050
+
2051
+	/**
2052
+	 * generates the dropdown selector for event categories
2053
+	 * typically used as a filter on list tables.
2054
+	 *
2055
+	 * @param integer $current_cat currently selected category
2056
+	 * @return string               html for dropdown
2057
+	 * @throws EE_Error
2058
+	 * @throws ReflectionException
2059
+	 */
2060
+	public static function generate_event_category_dropdown($current_cat = -1)
2061
+	{
2062
+		$categories = EEM_Term::instance()->get_all_ee_categories(true);
2063
+		$options    = [
2064
+			'0' => [
2065
+				'text' => esc_html__('All Categories', 'event_espresso'),
2066
+				'id'   => -1,
2067
+			],
2068
+		];
2069
+
2070
+		// setup categories for dropdown
2071
+		foreach ($categories as $category) {
2072
+			$options[] = [
2073
+				'text' => $category->get('name'),
2074
+				'id'   => $category->ID(),
2075
+			];
2076
+		}
2077
+
2078
+		return self::select_input('EVT_CAT', $options, $current_cat);
2079
+	}
2080
+
2081
+
2082
+	/**
2083
+	 *    generate a submit button with or without it's own microform
2084
+	 *    this is the only way to create buttons that are compatible across all themes
2085
+	 *
2086
+	 * @access    public
2087
+	 * @param string      $url              - the form action
2088
+	 * @param string      $ID               - some kind of unique ID, appended with "-sbmt" for the input and "-frm"
2089
+	 *                                      for the form
2090
+	 * @param string      $class            - css classes (separated by spaces if more than one)
2091
+	 * @param string      $text             - what appears on the button
2092
+	 * @param string      $nonce_action     - if using nonces
2093
+	 * @param bool|string $input_only       - whether to print form header and footer. TRUE returns the input without
2094
+	 *                                      the form
2095
+	 * @param string      $extra_attributes - any extra attributes that need to be attached to the form input
2096
+	 * @return    string
2097
+	 */
2098
+	public static function submit_button(
2099
+		$url = '',
2100
+		$ID = '',
2101
+		$class = '',
2102
+		$text = '',
2103
+		$nonce_action = '',
2104
+		$input_only = false,
2105
+		$extra_attributes = ''
2106
+	) {
2107
+		$btn = '';
2108
+		if (empty($url) || empty($ID)) {
2109
+			return $btn;
2110
+		}
2111
+		$text = ! empty($text) ? $text : esc_html__('Submit', 'event_espresso');
2112
+		$btn  .= '<input id="' . $ID . '-btn" class="' . $class . '" '
2113
+				 . 'type="submit" value="' . $text . '" ' . $extra_attributes . '/>';
2114
+		if (! $input_only) {
2115
+			$btn_frm = '<form id="' . $ID . '-frm" method="POST" action="' . $url . '">';
2116
+			$btn_frm .= ! empty($nonce_action)
2117
+				? wp_nonce_field($nonce_action, $nonce_action . '_nonce', true, false)
2118
+				: '';
2119
+			$btn_frm .= $btn;
2120
+			$btn_frm .= '</form>';
2121
+			$btn     = $btn_frm;
2122
+			unset($btn_frm);
2123
+		}
2124
+		return $btn;
2125
+	}
2126 2126
 }
Please login to merge, or discard this patch.
caffeinated/admin/new/pricing/Prices_List_Table.class.php 1 patch
Indentation   +270 added lines, -270 removed lines patch added patch discarded remove patch
@@ -13,274 +13,274 @@
 block discarded – undo
13 13
  */
14 14
 class Prices_List_Table extends EE_Admin_List_Table
15 15
 {
16
-    private $_PRT;
17
-
18
-    /**
19
-     * Array of price types.
20
-     *
21
-     * @var EE_Price_Type[]
22
-     */
23
-    protected $_price_types = [];
24
-
25
-
26
-    public function __construct(EE_Admin_Page $admin_page)
27
-    {
28
-        parent::__construct($admin_page);
29
-        require_once(EE_MODELS . 'EEM_Price_Type.model.php');
30
-        $this->_PRT         = EEM_Price_Type::instance();
31
-        $this->_price_types = $this->_PRT->get_all_deleted_and_undeleted();
32
-    }
33
-
34
-
35
-    protected function _setup_data()
36
-    {
37
-        $trashed               = $this->_admin_page->get_view() == 'trashed' ? true : false;
38
-        $this->_data           = $this->_admin_page->get_prices_overview_data($this->_per_page, false, $trashed);
39
-        $this->_all_data_count = $this->_admin_page->get_prices_overview_data($this->_per_page, true, false);
40
-        $this->_trashed_count  = $this->_admin_page->get_prices_overview_data($this->_per_page, true, true);
41
-    }
42
-
43
-
44
-    protected function _set_properties()
45
-    {
46
-        $this->_wp_list_args = [
47
-            'singular' => esc_html__('price', 'event_espresso'),
48
-            'plural'   => esc_html__('prices', 'event_espresso'),
49
-            'ajax'     => true,
50
-            'screen'   => $this->_admin_page->get_current_screen()->id,
51
-        ];
52
-
53
-        $this->_columns = [
54
-            'cb'          => '<input type="checkbox" />', // Render a checkbox instead of text
55
-            'id'          => esc_html__('ID', 'event_espresso'),
56
-            'name'        => esc_html__('Name', 'event_espresso'),
57
-            'type'        => esc_html__('Price Type', 'event_espresso'),
58
-            'description' => esc_html__('Description', 'event_espresso'),
59
-            'amount'      => esc_html__('Amount', 'event_espresso'),
60
-        ];
61
-        $this->_primary_column = 'id';
62
-
63
-        $this->_sortable_columns = [
64
-            // true means its already sorted
65
-            'name'   => ['name' => false],
66
-            'type'   => ['type' => false],
67
-            'amount' => ['amount' => false],
68
-        ];
69
-
70
-        $this->_hidden_columns = [];
71
-
72
-        $this->_ajax_sorting_callback = 'update_prices_order';
73
-    }
74
-
75
-
76
-    protected function _get_table_filters()
77
-    {
78
-        return [];
79
-    }
80
-
81
-
82
-    protected function _add_view_counts()
83
-    {
84
-        $this->_views['all']['count'] = $this->_all_data_count;
85
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_default_prices', 'pricing_trash_price')) {
86
-            $this->_views['trashed']['count'] = $this->_trashed_count;
87
-        }
88
-    }
89
-
90
-
91
-    /**
92
-     * overriding parent method so that we can make sure the row isn't sortable for certain items
93
-     *
94
-     * @param object $item the current item
95
-     * @return string
96
-     */
97
-    protected function _get_row_class($item)
98
-    {
99
-        return $item->type_obj() instanceof EE_Price_Type
100
-                     && $item->type_obj()->base_type() !== 1
101
-                     && $item->type_obj()->base_type() !== 4
102
-            ? ' class="rowsortable"'
103
-            : '';
104
-    }
105
-
106
-
107
-    /**
108
-     * @param EE_Price $price
109
-     * @param string   $action
110
-     * @return string
111
-     * @throws EE_Error
112
-     * @throws ReflectionException
113
-     * @since $VID:$
114
-     */
115
-    protected function getActionUrl(EE_Price $price, string $action): string
116
-    {
117
-        if (! in_array($action, self::$actions)) {
118
-            throw new DomainException(esc_html__('Invalid Action', 'event_espresso'));
119
-        }
120
-        return EE_Admin_Page::add_query_args_and_nonce(
121
-            [
122
-                'action'   => "{$action}_price",
123
-                'id'       => $price->ID(),
124
-                'noheader' => $action !== self::ACTION_EDIT,
125
-            ],
126
-            PRICING_ADMIN_URL
127
-        );
128
-    }
129
-
130
-
131
-    public function column_cb($item)
132
-    {
133
-        return $item->type_obj() instanceof EE_Price_Type && $item->type_obj()->base_type() !== 1
134
-            ? sprintf(
135
-                '<input type="checkbox" name="checkbox[%1$s]" value="%1$s" />',
136
-                $item->ID()
137
-            )
138
-            : '';
139
-    }
140
-
141
-
142
-    /**
143
-     * @param EE_Price $item
144
-     * @return string
145
-     * @throws EE_Error
146
-     * @throws ReflectionException
147
-     */
148
-    public function column_id($item)
149
-    {
150
-        $content = '<span class="ee-entity-id">' . $item->ID() . '</span>';
151
-        $content .= '<span class="show-on-mobile-view-only">' . $this->column_name($item, false) . '</span>';
152
-        return $this->columnContent('id', $content, 'end');
153
-    }
154
-
155
-
156
-    /**
157
-     * @param EE_Price $price
158
-     * @param bool     $prep_content
159
-     * @return string
160
-     * @throws EE_Error
161
-     * @throws ReflectionException
162
-     */
163
-    public function column_name(EE_Price $price, bool $prep_content = true): string
164
-    {
165
-
166
-        // Build row actions
167
-        $actions = [];
168
-        // edit price link
169
-        if (
170
-            EE_Registry::instance()->CAP->current_user_can(
171
-                'ee_edit_default_price',
172
-                'pricing_edit_price',
173
-                $price->ID()
174
-            )
175
-        ) {
176
-            $actions['edit'] = $this->getActionLink(
177
-                $this->getActionUrl($price, self::ACTION_EDIT),
178
-                esc_html__('Edit', 'event_espresso'),
179
-                esc_attr__('Edit Price', 'event_espresso')
180
-            );
181
-        }
182
-
183
-        $name_link = EE_Registry::instance()->CAP->current_user_can(
184
-            'ee_edit_default_price',
185
-            'edit_price',
186
-            $price->ID()
187
-        )
188
-            ? $this->getActionLink(
189
-                $this->getActionUrl($price, self::ACTION_EDIT),
190
-                stripslashes($price->name()),
191
-                esc_attr__('Edit Price', 'event_espresso')
192
-            )
193
-            : $price->name();
194
-
195
-        if ($price->type_obj() instanceof EE_Price_Type && $price->type_obj()->base_type() !== 1) {
196
-            if ($this->_view == 'all') {
197
-                // trash price link
198
-                if (
199
-                    EE_Registry::instance()->CAP->current_user_can(
200
-                        'ee_delete_default_price',
201
-                        'pricing_trash_price',
202
-                        $price->ID()
203
-                    )
204
-                ) {
205
-                    $actions['trash'] = $this->getActionLink(
206
-                        $this->getActionUrl($price, self::ACTION_TRASH),
207
-                        esc_html__('Trash', 'event_espresso'),
208
-                        esc_attr__('Move Price to Trash', 'event_espresso')
209
-                    );
210
-                }
211
-            } else {
212
-                if (
213
-                    EE_Registry::instance()->CAP->current_user_can(
214
-                        'ee_delete_default_price',
215
-                        'pricing_restore_price',
216
-                        $price->ID()
217
-                    )
218
-                ) {
219
-                    $actions['restore'] = $this->getActionLink(
220
-                        $this->getActionUrl($price, self::ACTION_RESTORE),
221
-                        esc_html__('Restore', 'event_espresso'),
222
-                        esc_attr__('Restore Price', 'event_espresso')
223
-                    );
224
-                }
225
-
226
-                // delete price link
227
-                if (
228
-                    EE_Registry::instance()->CAP->current_user_can(
229
-                        'ee_delete_default_price',
230
-                        'pricing_delete_price',
231
-                        $price->ID()
232
-                    )
233
-                ) {
234
-                    $actions['delete'] = $this->getActionLink(
235
-                        $this->getActionUrl($price, self::ACTION_DELETE),
236
-                        esc_html__('Delete Permanently', 'event_espresso'),
237
-                        esc_attr__('Delete Price Permanently', 'event_espresso')
238
-                    );
239
-                }
240
-            }
241
-        }
242
-
243
-        $content = $prep_content ? $name_link . $this->row_actions($actions) : $name_link;
244
-        return $prep_content ? $this->columnContent('name', $content) : $content;
245
-    }
246
-
247
-
248
-    /**
249
-     * @throws EE_Error
250
-     * @throws ReflectionException
251
-     */
252
-    public function column_type(EE_Price $price): string
253
-    {
254
-        $content = isset($this->_price_types[ $price->type() ])
255
-            ? $this->_price_types[ $price->type() ]->name()
256
-            : '';
257
-        return $this->columnContent('type', $content);
258
-    }
259
-
260
-
261
-    /**
262
-     * @throws EE_Error
263
-     * @throws ReflectionException
264
-     */
265
-    public function column_description(EE_Price $price): string
266
-    {
267
-        $content = stripslashes($price->desc());
268
-        return $this->columnContent('description', $content);
269
-    }
270
-
271
-
272
-    /**
273
-     * @throws EE_Error
274
-     * @throws ReflectionException
275
-     */
276
-    public function column_amount(EE_Price $price): string
277
-    {
278
-        $price_type = isset($this->_price_types[ $price->type() ])
279
-            ? $this->_price_types[ $price->type() ]
280
-            : null;
281
-        $content = $price_type instanceof EE_Price_Type && $price_type->is_percent() ?
282
-            '<div class="pad-amnt-rght">' . number_format($price->amount(), 1) . '%</div>'
283
-            : '<div class="pad-amnt-rght">' . EEH_Template::format_currency($price->amount()) . '</div>';
284
-        return $this->columnContent('amount', $content, 'end');
285
-    }
16
+	private $_PRT;
17
+
18
+	/**
19
+	 * Array of price types.
20
+	 *
21
+	 * @var EE_Price_Type[]
22
+	 */
23
+	protected $_price_types = [];
24
+
25
+
26
+	public function __construct(EE_Admin_Page $admin_page)
27
+	{
28
+		parent::__construct($admin_page);
29
+		require_once(EE_MODELS . 'EEM_Price_Type.model.php');
30
+		$this->_PRT         = EEM_Price_Type::instance();
31
+		$this->_price_types = $this->_PRT->get_all_deleted_and_undeleted();
32
+	}
33
+
34
+
35
+	protected function _setup_data()
36
+	{
37
+		$trashed               = $this->_admin_page->get_view() == 'trashed' ? true : false;
38
+		$this->_data           = $this->_admin_page->get_prices_overview_data($this->_per_page, false, $trashed);
39
+		$this->_all_data_count = $this->_admin_page->get_prices_overview_data($this->_per_page, true, false);
40
+		$this->_trashed_count  = $this->_admin_page->get_prices_overview_data($this->_per_page, true, true);
41
+	}
42
+
43
+
44
+	protected function _set_properties()
45
+	{
46
+		$this->_wp_list_args = [
47
+			'singular' => esc_html__('price', 'event_espresso'),
48
+			'plural'   => esc_html__('prices', 'event_espresso'),
49
+			'ajax'     => true,
50
+			'screen'   => $this->_admin_page->get_current_screen()->id,
51
+		];
52
+
53
+		$this->_columns = [
54
+			'cb'          => '<input type="checkbox" />', // Render a checkbox instead of text
55
+			'id'          => esc_html__('ID', 'event_espresso'),
56
+			'name'        => esc_html__('Name', 'event_espresso'),
57
+			'type'        => esc_html__('Price Type', 'event_espresso'),
58
+			'description' => esc_html__('Description', 'event_espresso'),
59
+			'amount'      => esc_html__('Amount', 'event_espresso'),
60
+		];
61
+		$this->_primary_column = 'id';
62
+
63
+		$this->_sortable_columns = [
64
+			// true means its already sorted
65
+			'name'   => ['name' => false],
66
+			'type'   => ['type' => false],
67
+			'amount' => ['amount' => false],
68
+		];
69
+
70
+		$this->_hidden_columns = [];
71
+
72
+		$this->_ajax_sorting_callback = 'update_prices_order';
73
+	}
74
+
75
+
76
+	protected function _get_table_filters()
77
+	{
78
+		return [];
79
+	}
80
+
81
+
82
+	protected function _add_view_counts()
83
+	{
84
+		$this->_views['all']['count'] = $this->_all_data_count;
85
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_default_prices', 'pricing_trash_price')) {
86
+			$this->_views['trashed']['count'] = $this->_trashed_count;
87
+		}
88
+	}
89
+
90
+
91
+	/**
92
+	 * overriding parent method so that we can make sure the row isn't sortable for certain items
93
+	 *
94
+	 * @param object $item the current item
95
+	 * @return string
96
+	 */
97
+	protected function _get_row_class($item)
98
+	{
99
+		return $item->type_obj() instanceof EE_Price_Type
100
+					 && $item->type_obj()->base_type() !== 1
101
+					 && $item->type_obj()->base_type() !== 4
102
+			? ' class="rowsortable"'
103
+			: '';
104
+	}
105
+
106
+
107
+	/**
108
+	 * @param EE_Price $price
109
+	 * @param string   $action
110
+	 * @return string
111
+	 * @throws EE_Error
112
+	 * @throws ReflectionException
113
+	 * @since $VID:$
114
+	 */
115
+	protected function getActionUrl(EE_Price $price, string $action): string
116
+	{
117
+		if (! in_array($action, self::$actions)) {
118
+			throw new DomainException(esc_html__('Invalid Action', 'event_espresso'));
119
+		}
120
+		return EE_Admin_Page::add_query_args_and_nonce(
121
+			[
122
+				'action'   => "{$action}_price",
123
+				'id'       => $price->ID(),
124
+				'noheader' => $action !== self::ACTION_EDIT,
125
+			],
126
+			PRICING_ADMIN_URL
127
+		);
128
+	}
129
+
130
+
131
+	public function column_cb($item)
132
+	{
133
+		return $item->type_obj() instanceof EE_Price_Type && $item->type_obj()->base_type() !== 1
134
+			? sprintf(
135
+				'<input type="checkbox" name="checkbox[%1$s]" value="%1$s" />',
136
+				$item->ID()
137
+			)
138
+			: '';
139
+	}
140
+
141
+
142
+	/**
143
+	 * @param EE_Price $item
144
+	 * @return string
145
+	 * @throws EE_Error
146
+	 * @throws ReflectionException
147
+	 */
148
+	public function column_id($item)
149
+	{
150
+		$content = '<span class="ee-entity-id">' . $item->ID() . '</span>';
151
+		$content .= '<span class="show-on-mobile-view-only">' . $this->column_name($item, false) . '</span>';
152
+		return $this->columnContent('id', $content, 'end');
153
+	}
154
+
155
+
156
+	/**
157
+	 * @param EE_Price $price
158
+	 * @param bool     $prep_content
159
+	 * @return string
160
+	 * @throws EE_Error
161
+	 * @throws ReflectionException
162
+	 */
163
+	public function column_name(EE_Price $price, bool $prep_content = true): string
164
+	{
165
+
166
+		// Build row actions
167
+		$actions = [];
168
+		// edit price link
169
+		if (
170
+			EE_Registry::instance()->CAP->current_user_can(
171
+				'ee_edit_default_price',
172
+				'pricing_edit_price',
173
+				$price->ID()
174
+			)
175
+		) {
176
+			$actions['edit'] = $this->getActionLink(
177
+				$this->getActionUrl($price, self::ACTION_EDIT),
178
+				esc_html__('Edit', 'event_espresso'),
179
+				esc_attr__('Edit Price', 'event_espresso')
180
+			);
181
+		}
182
+
183
+		$name_link = EE_Registry::instance()->CAP->current_user_can(
184
+			'ee_edit_default_price',
185
+			'edit_price',
186
+			$price->ID()
187
+		)
188
+			? $this->getActionLink(
189
+				$this->getActionUrl($price, self::ACTION_EDIT),
190
+				stripslashes($price->name()),
191
+				esc_attr__('Edit Price', 'event_espresso')
192
+			)
193
+			: $price->name();
194
+
195
+		if ($price->type_obj() instanceof EE_Price_Type && $price->type_obj()->base_type() !== 1) {
196
+			if ($this->_view == 'all') {
197
+				// trash price link
198
+				if (
199
+					EE_Registry::instance()->CAP->current_user_can(
200
+						'ee_delete_default_price',
201
+						'pricing_trash_price',
202
+						$price->ID()
203
+					)
204
+				) {
205
+					$actions['trash'] = $this->getActionLink(
206
+						$this->getActionUrl($price, self::ACTION_TRASH),
207
+						esc_html__('Trash', 'event_espresso'),
208
+						esc_attr__('Move Price to Trash', 'event_espresso')
209
+					);
210
+				}
211
+			} else {
212
+				if (
213
+					EE_Registry::instance()->CAP->current_user_can(
214
+						'ee_delete_default_price',
215
+						'pricing_restore_price',
216
+						$price->ID()
217
+					)
218
+				) {
219
+					$actions['restore'] = $this->getActionLink(
220
+						$this->getActionUrl($price, self::ACTION_RESTORE),
221
+						esc_html__('Restore', 'event_espresso'),
222
+						esc_attr__('Restore Price', 'event_espresso')
223
+					);
224
+				}
225
+
226
+				// delete price link
227
+				if (
228
+					EE_Registry::instance()->CAP->current_user_can(
229
+						'ee_delete_default_price',
230
+						'pricing_delete_price',
231
+						$price->ID()
232
+					)
233
+				) {
234
+					$actions['delete'] = $this->getActionLink(
235
+						$this->getActionUrl($price, self::ACTION_DELETE),
236
+						esc_html__('Delete Permanently', 'event_espresso'),
237
+						esc_attr__('Delete Price Permanently', 'event_espresso')
238
+					);
239
+				}
240
+			}
241
+		}
242
+
243
+		$content = $prep_content ? $name_link . $this->row_actions($actions) : $name_link;
244
+		return $prep_content ? $this->columnContent('name', $content) : $content;
245
+	}
246
+
247
+
248
+	/**
249
+	 * @throws EE_Error
250
+	 * @throws ReflectionException
251
+	 */
252
+	public function column_type(EE_Price $price): string
253
+	{
254
+		$content = isset($this->_price_types[ $price->type() ])
255
+			? $this->_price_types[ $price->type() ]->name()
256
+			: '';
257
+		return $this->columnContent('type', $content);
258
+	}
259
+
260
+
261
+	/**
262
+	 * @throws EE_Error
263
+	 * @throws ReflectionException
264
+	 */
265
+	public function column_description(EE_Price $price): string
266
+	{
267
+		$content = stripslashes($price->desc());
268
+		return $this->columnContent('description', $content);
269
+	}
270
+
271
+
272
+	/**
273
+	 * @throws EE_Error
274
+	 * @throws ReflectionException
275
+	 */
276
+	public function column_amount(EE_Price $price): string
277
+	{
278
+		$price_type = isset($this->_price_types[ $price->type() ])
279
+			? $this->_price_types[ $price->type() ]
280
+			: null;
281
+		$content = $price_type instanceof EE_Price_Type && $price_type->is_percent() ?
282
+			'<div class="pad-amnt-rght">' . number_format($price->amount(), 1) . '%</div>'
283
+			: '<div class="pad-amnt-rght">' . EEH_Template::format_currency($price->amount()) . '</div>';
284
+		return $this->columnContent('amount', $content, 'end');
285
+	}
286 286
 }
Please login to merge, or discard this patch.
caffeinated/admin/new/pricing/Price_Types_List_Table.class.php 1 patch
Indentation   +250 added lines, -250 removed lines patch added patch discarded remove patch
@@ -13,254 +13,254 @@
 block discarded – undo
13 13
  */
14 14
 class Price_Types_List_Table extends EE_Admin_List_Table
15 15
 {
16
-    /**
17
-     * @var Pricing_Admin_Page
18
-     */
19
-    protected $_admin_page;
20
-
21
-
22
-    public function __construct($admin_page)
23
-    {
24
-        parent::__construct($admin_page);
25
-        require_once(EE_MODELS . 'EEM_Price_Type.model.php');
26
-        $this->_PRT = EEM_Price_Type::instance();
27
-    }
28
-
29
-
30
-    protected function _setup_data()
31
-    {
32
-        $trashed               = $this->_admin_page->get_view() == 'trashed';
33
-        $this->_data           = $this->_admin_page->get_price_types_overview_data($this->_per_page, false, $trashed);
34
-        $this->_all_data_count = $this->_admin_page->get_price_types_overview_data($this->_per_page, true);
35
-        $this->_trashed_count  = $this->_admin_page->get_price_types_overview_data($this->_per_page, true, true);
36
-    }
37
-
38
-
39
-    protected function _set_properties()
40
-    {
41
-        $this->_wp_list_args = [
42
-            'singular' => esc_html__('price type', 'event_espresso'),
43
-            'plural'   => esc_html__('price types', 'event_espresso'),
44
-            'ajax'     => true,
45
-            'screen'   => $this->_admin_page->get_current_screen()->id,
46
-        ];
47
-
48
-        $this->_columns = [
49
-            'cb'        => '<input type="checkbox" />', // Render a checkbox instead of text
50
-            'id'        => esc_html__('ID', 'event_espresso'),
51
-            'name'      => esc_html__('Name', 'event_espresso'),
52
-            'base_type' => esc_html__('Base Type', 'event_espresso'),
53
-            'percent'   => sprintf(
54
-                               /* translators: 1: HTML new line, 2: open span tag, 3: close span tag */
55
-                esc_html__('Applied %1$s as %2$s%%%3$s or %2$s$%3$s', 'event_espresso'),
56
-                '',
57
-                '<span class="big-text">',
58
-                '</span>'
59
-            ),
60
-            'order'     => esc_html__('Order of Application', 'event_espresso'),
61
-        ];
62
-
63
-        $this->_sortable_columns = [
64
-            // TRUE means its already sorted
65
-            'name' => ['name' => false],
66
-        ];
67
-
68
-        $this->_hidden_columns = [];
69
-    }
70
-
71
-
72
-    protected function _get_table_filters()
73
-    {
74
-        return [];
75
-    }
76
-
77
-
78
-    protected function _add_view_counts()
79
-    {
80
-        $this->_views['all']['count'] = $this->_all_data_count;
81
-        if (
82
-            EE_Registry::instance()->CAP->current_user_can(
83
-                'ee_delete_default_price_types',
84
-                'pricing_trash_price_type'
85
-            )
86
-        ) {
87
-            $this->_views['trashed']['count'] = $this->_trashed_count;
88
-        }
89
-    }
90
-
91
-
92
-    /**
93
-     * @param EE_Price_Type $price_type
94
-     * @param string   $action
95
-     * @return string
96
-     * @throws EE_Error
97
-     * @throws ReflectionException
98
-     * @since $VID:$
99
-     */
100
-    protected function getActionUrl(EE_Price_Type $price_type, string $action): string
101
-    {
102
-        if (! in_array($action, self::$actions)) {
103
-            throw new DomainException(esc_html__('Invalid Action', 'event_espresso'));
104
-        }
105
-        return EE_Admin_Page::add_query_args_and_nonce(
106
-            [
107
-                'action'   => "{$action}_price_type",
108
-                'id'       => $price_type->ID(),
109
-                'noheader' => $action !== self::ACTION_EDIT,
110
-            ],
111
-            PRICING_ADMIN_URL
112
-        );
113
-    }
114
-
115
-
116
-    public function column_cb($item): string
117
-    {
118
-        if ($item->base_type() !== 1) {
119
-            return sprintf(
120
-                '<input type="checkbox" name="checkbox[%1$s]" />',
121
-                $item->ID()
122
-            );
123
-        }
124
-        return '';
125
-    }
126
-
127
-
128
-    /**
129
-     * @param EE_Price_Type $item
130
-     * @return string
131
-     * @throws EE_Error
132
-     * @throws ReflectionException
133
-     */
134
-    public function column_id($item): string
135
-    {
136
-        $content = '<span class="ee-entity-id">' . $item->ID() . '</span>';
137
-        $content .= '<span class="show-on-mobile-view-only">' . $this->column_name($item, false) . '</span>';
138
-        return $this->columnContent('id', $content, 'end');
139
-    }
140
-
141
-
142
-    /**
143
-     * @param EE_Price_Type $price_type
144
-     * @param bool          $prep_content
145
-     * @return string
146
-     * @throws EE_Error
147
-     * @throws ReflectionException
148
-     */
149
-    public function column_name(EE_Price_Type $price_type, bool $prep_content = true): string
150
-    {
151
-
152
-        // Build row actions
153
-        $actions   = [];
154
-        $name_link = $price_type->name();
155
-        // edit price link
156
-        if (
157
-            EE_Registry::instance()->CAP->current_user_can(
158
-                'ee_edit_default_price_type',
159
-                'pricing_edit_price_type',
160
-                $price_type->ID()
161
-            )
162
-        ) {
163
-            $name_link = $this->getActionLink(
164
-                $this->getActionUrl($price_type, self::ACTION_EDIT),
165
-                stripslashes($price_type->name()),
166
-                sprintf(
167
-                    /* translators: The name of the price type */
168
-                    esc_attr__('Edit Price Type (%s)', 'event_espresso'),
169
-                    $price_type->name()
170
-                )
171
-            );
172
-
173
-            $actions['edit'] = $this->getActionLink(
174
-                $this->getActionUrl($price_type, self::ACTION_EDIT),
175
-                esc_html__('Edit', 'event_espresso'),
176
-                sprintf(
177
-                    /* translators: The name of the price type */
178
-                    esc_attr__('Edit Price Type (%s)', 'event_espresso'),
179
-                    $price_type->name()
180
-                )
181
-            );
182
-        }
183
-
184
-        if ($price_type->base_type() !== 1) {
185
-            if ($this->_view == 'all') {
186
-                // trash price link
187
-                if (
188
-                    EE_Registry::instance()->CAP->current_user_can(
189
-                        'ee_delete_default_price_type',
190
-                        'pricing_trash_price_type',
191
-                        $price_type->ID()
192
-                    )
193
-                ) {
194
-                    $actions['trash'] = $this->getActionLink(
195
-                        $this->getActionUrl($price_type, self::ACTION_TRASH),
196
-                        esc_html__('Trash', 'event_espresso'),
197
-                        sprintf(
198
-                            /* translators: The name of the price type */
199
-                            esc_attr__('Move Price Type %s to Trash', 'event_espresso'),
200
-                            $price_type->name()
201
-                        )
202
-                    );
203
-                }
204
-            } else {
205
-                // restore price link
206
-                if (
207
-                    EE_Registry::instance()->CAP->current_user_can(
208
-                        'ee_delete_default_price_type',
209
-                        'pricing_restore_price_type',
210
-                        $price_type->ID()
211
-                    )
212
-                ) {
213
-                    $actions['restore'] = $this->getActionLink(
214
-                        $this->getActionUrl($price_type, self::ACTION_RESTORE),
215
-                        esc_html__('Restore', 'event_espresso'),
216
-                        sprintf(
217
-                            /* translators: The name of the price type */
218
-                            esc_attr__('Restore Price Type (%s)', 'event_espresso'),
219
-                            $price_type->name()
220
-                        )
221
-                    );
222
-                }
223
-                // delete price link
224
-                if (
225
-                    EE_Registry::instance()->CAP->current_user_can(
226
-                        'ee_delete_default_price_type',
227
-                        'pricing_delete_price_type',
228
-                        $price_type->ID()
229
-                    )
230
-                ) {
231
-                    $actions['delete'] = $this->getActionLink(
232
-                        $this->getActionUrl($price_type, self::ACTION_DELETE),
233
-                        esc_html__('Delete Permanently', 'event_espresso'),
234
-                        sprintf(
235
-                            /* translators: The name of the price type */
236
-                            esc_attr__('Delete Price Type %s Permanently', 'event_espresso'),
237
-                            $price_type->name()
238
-                        )
239
-                    );
240
-                }
241
-            }
242
-        }
243
-
244
-        $content = $prep_content ? $name_link . $this->row_actions($actions) : $name_link;
245
-        return $prep_content ? $this->columnContent('name', $content) : $content;
246
-    }
247
-
248
-
249
-    public function column_base_type($price_type): string
250
-    {
251
-        return $this->columnContent('base_type', $price_type->base_type_name());
252
-    }
253
-
254
-
255
-    public function column_percent($price_type): string
256
-    {
257
-        $content = $price_type->is_percent() ? '%' : EE_Registry::instance()->CFG->currency->sign;
258
-        return $this->columnContent('percent', $content, 'center');
259
-    }
260
-
261
-
262
-    public function column_order($price_type): string
263
-    {
264
-        return $this->columnContent('order', $price_type->order(), 'end');
265
-    }
16
+	/**
17
+	 * @var Pricing_Admin_Page
18
+	 */
19
+	protected $_admin_page;
20
+
21
+
22
+	public function __construct($admin_page)
23
+	{
24
+		parent::__construct($admin_page);
25
+		require_once(EE_MODELS . 'EEM_Price_Type.model.php');
26
+		$this->_PRT = EEM_Price_Type::instance();
27
+	}
28
+
29
+
30
+	protected function _setup_data()
31
+	{
32
+		$trashed               = $this->_admin_page->get_view() == 'trashed';
33
+		$this->_data           = $this->_admin_page->get_price_types_overview_data($this->_per_page, false, $trashed);
34
+		$this->_all_data_count = $this->_admin_page->get_price_types_overview_data($this->_per_page, true);
35
+		$this->_trashed_count  = $this->_admin_page->get_price_types_overview_data($this->_per_page, true, true);
36
+	}
37
+
38
+
39
+	protected function _set_properties()
40
+	{
41
+		$this->_wp_list_args = [
42
+			'singular' => esc_html__('price type', 'event_espresso'),
43
+			'plural'   => esc_html__('price types', 'event_espresso'),
44
+			'ajax'     => true,
45
+			'screen'   => $this->_admin_page->get_current_screen()->id,
46
+		];
47
+
48
+		$this->_columns = [
49
+			'cb'        => '<input type="checkbox" />', // Render a checkbox instead of text
50
+			'id'        => esc_html__('ID', 'event_espresso'),
51
+			'name'      => esc_html__('Name', 'event_espresso'),
52
+			'base_type' => esc_html__('Base Type', 'event_espresso'),
53
+			'percent'   => sprintf(
54
+							   /* translators: 1: HTML new line, 2: open span tag, 3: close span tag */
55
+				esc_html__('Applied %1$s as %2$s%%%3$s or %2$s$%3$s', 'event_espresso'),
56
+				'',
57
+				'<span class="big-text">',
58
+				'</span>'
59
+			),
60
+			'order'     => esc_html__('Order of Application', 'event_espresso'),
61
+		];
62
+
63
+		$this->_sortable_columns = [
64
+			// TRUE means its already sorted
65
+			'name' => ['name' => false],
66
+		];
67
+
68
+		$this->_hidden_columns = [];
69
+	}
70
+
71
+
72
+	protected function _get_table_filters()
73
+	{
74
+		return [];
75
+	}
76
+
77
+
78
+	protected function _add_view_counts()
79
+	{
80
+		$this->_views['all']['count'] = $this->_all_data_count;
81
+		if (
82
+			EE_Registry::instance()->CAP->current_user_can(
83
+				'ee_delete_default_price_types',
84
+				'pricing_trash_price_type'
85
+			)
86
+		) {
87
+			$this->_views['trashed']['count'] = $this->_trashed_count;
88
+		}
89
+	}
90
+
91
+
92
+	/**
93
+	 * @param EE_Price_Type $price_type
94
+	 * @param string   $action
95
+	 * @return string
96
+	 * @throws EE_Error
97
+	 * @throws ReflectionException
98
+	 * @since $VID:$
99
+	 */
100
+	protected function getActionUrl(EE_Price_Type $price_type, string $action): string
101
+	{
102
+		if (! in_array($action, self::$actions)) {
103
+			throw new DomainException(esc_html__('Invalid Action', 'event_espresso'));
104
+		}
105
+		return EE_Admin_Page::add_query_args_and_nonce(
106
+			[
107
+				'action'   => "{$action}_price_type",
108
+				'id'       => $price_type->ID(),
109
+				'noheader' => $action !== self::ACTION_EDIT,
110
+			],
111
+			PRICING_ADMIN_URL
112
+		);
113
+	}
114
+
115
+
116
+	public function column_cb($item): string
117
+	{
118
+		if ($item->base_type() !== 1) {
119
+			return sprintf(
120
+				'<input type="checkbox" name="checkbox[%1$s]" />',
121
+				$item->ID()
122
+			);
123
+		}
124
+		return '';
125
+	}
126
+
127
+
128
+	/**
129
+	 * @param EE_Price_Type $item
130
+	 * @return string
131
+	 * @throws EE_Error
132
+	 * @throws ReflectionException
133
+	 */
134
+	public function column_id($item): string
135
+	{
136
+		$content = '<span class="ee-entity-id">' . $item->ID() . '</span>';
137
+		$content .= '<span class="show-on-mobile-view-only">' . $this->column_name($item, false) . '</span>';
138
+		return $this->columnContent('id', $content, 'end');
139
+	}
140
+
141
+
142
+	/**
143
+	 * @param EE_Price_Type $price_type
144
+	 * @param bool          $prep_content
145
+	 * @return string
146
+	 * @throws EE_Error
147
+	 * @throws ReflectionException
148
+	 */
149
+	public function column_name(EE_Price_Type $price_type, bool $prep_content = true): string
150
+	{
151
+
152
+		// Build row actions
153
+		$actions   = [];
154
+		$name_link = $price_type->name();
155
+		// edit price link
156
+		if (
157
+			EE_Registry::instance()->CAP->current_user_can(
158
+				'ee_edit_default_price_type',
159
+				'pricing_edit_price_type',
160
+				$price_type->ID()
161
+			)
162
+		) {
163
+			$name_link = $this->getActionLink(
164
+				$this->getActionUrl($price_type, self::ACTION_EDIT),
165
+				stripslashes($price_type->name()),
166
+				sprintf(
167
+					/* translators: The name of the price type */
168
+					esc_attr__('Edit Price Type (%s)', 'event_espresso'),
169
+					$price_type->name()
170
+				)
171
+			);
172
+
173
+			$actions['edit'] = $this->getActionLink(
174
+				$this->getActionUrl($price_type, self::ACTION_EDIT),
175
+				esc_html__('Edit', 'event_espresso'),
176
+				sprintf(
177
+					/* translators: The name of the price type */
178
+					esc_attr__('Edit Price Type (%s)', 'event_espresso'),
179
+					$price_type->name()
180
+				)
181
+			);
182
+		}
183
+
184
+		if ($price_type->base_type() !== 1) {
185
+			if ($this->_view == 'all') {
186
+				// trash price link
187
+				if (
188
+					EE_Registry::instance()->CAP->current_user_can(
189
+						'ee_delete_default_price_type',
190
+						'pricing_trash_price_type',
191
+						$price_type->ID()
192
+					)
193
+				) {
194
+					$actions['trash'] = $this->getActionLink(
195
+						$this->getActionUrl($price_type, self::ACTION_TRASH),
196
+						esc_html__('Trash', 'event_espresso'),
197
+						sprintf(
198
+							/* translators: The name of the price type */
199
+							esc_attr__('Move Price Type %s to Trash', 'event_espresso'),
200
+							$price_type->name()
201
+						)
202
+					);
203
+				}
204
+			} else {
205
+				// restore price link
206
+				if (
207
+					EE_Registry::instance()->CAP->current_user_can(
208
+						'ee_delete_default_price_type',
209
+						'pricing_restore_price_type',
210
+						$price_type->ID()
211
+					)
212
+				) {
213
+					$actions['restore'] = $this->getActionLink(
214
+						$this->getActionUrl($price_type, self::ACTION_RESTORE),
215
+						esc_html__('Restore', 'event_espresso'),
216
+						sprintf(
217
+							/* translators: The name of the price type */
218
+							esc_attr__('Restore Price Type (%s)', 'event_espresso'),
219
+							$price_type->name()
220
+						)
221
+					);
222
+				}
223
+				// delete price link
224
+				if (
225
+					EE_Registry::instance()->CAP->current_user_can(
226
+						'ee_delete_default_price_type',
227
+						'pricing_delete_price_type',
228
+						$price_type->ID()
229
+					)
230
+				) {
231
+					$actions['delete'] = $this->getActionLink(
232
+						$this->getActionUrl($price_type, self::ACTION_DELETE),
233
+						esc_html__('Delete Permanently', 'event_espresso'),
234
+						sprintf(
235
+							/* translators: The name of the price type */
236
+							esc_attr__('Delete Price Type %s Permanently', 'event_espresso'),
237
+							$price_type->name()
238
+						)
239
+					);
240
+				}
241
+			}
242
+		}
243
+
244
+		$content = $prep_content ? $name_link . $this->row_actions($actions) : $name_link;
245
+		return $prep_content ? $this->columnContent('name', $content) : $content;
246
+	}
247
+
248
+
249
+	public function column_base_type($price_type): string
250
+	{
251
+		return $this->columnContent('base_type', $price_type->base_type_name());
252
+	}
253
+
254
+
255
+	public function column_percent($price_type): string
256
+	{
257
+		$content = $price_type->is_percent() ? '%' : EE_Registry::instance()->CFG->currency->sign;
258
+		return $this->columnContent('percent', $content, 'center');
259
+	}
260
+
261
+
262
+	public function column_order($price_type): string
263
+	{
264
+		return $this->columnContent('order', $price_type->order(), 'end');
265
+	}
266 266
 }
Please login to merge, or discard this patch.
caffeinated/admin/extend/events/Extend_Events_Admin_Page.core.php 1 patch
Indentation   +1279 added lines, -1279 removed lines patch added patch discarded remove patch
@@ -16,1289 +16,1289 @@
 block discarded – undo
16 16
  */
17 17
 class Extend_Events_Admin_Page extends Events_Admin_Page
18 18
 {
19
-    /**
20
-     * @var EE_Admin_Config
21
-     */
22
-    protected $admin_config;
23
-
24
-
25
-    /**
26
-     * Extend_Events_Admin_Page constructor.
27
-     *
28
-     * @param bool $routing
29
-     * @throws ReflectionException
30
-     */
31
-    public function __construct($routing = true)
32
-    {
33
-        if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
34
-            define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
35
-            define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
36
-            define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
37
-        }
38
-        parent::__construct($routing);
39
-        $this->admin_config = $this->loader->getShared('EE_Admin_Config');
40
-    }
41
-
42
-
43
-    protected function _set_page_config()
44
-    {
45
-        parent::_set_page_config();
46
-
47
-        $this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
48
-        // is there a evt_id in the request?
49
-        $EVT_ID                                          = $this->request->getRequestParam('EVT_ID', 0, 'int');
50
-        $EVT_ID                                          = $this->request->getRequestParam('post', $EVT_ID, 'int');
51
-        $TKT_ID                                          = $this->request->getRequestParam('TKT_ID', 0, 'int');
52
-        $new_page_routes                                 = [
53
-            'duplicate_event'          => [
54
-                'func'       => '_duplicate_event',
55
-                'capability' => 'ee_edit_event',
56
-                'obj_id'     => $EVT_ID,
57
-                'noheader'   => true,
58
-            ],
59
-            'import_page'              => [
60
-                'func'       => '_import_page',
61
-                'capability' => 'import',
62
-            ],
63
-            'import'                   => [
64
-                'func'       => '_import_events',
65
-                'capability' => 'import',
66
-                'noheader'   => true,
67
-            ],
68
-            'import_events'            => [
69
-                'func'       => '_import_events',
70
-                'capability' => 'import',
71
-                'noheader'   => true,
72
-            ],
73
-            'export_events'            => [
74
-                'func'       => '_events_export',
75
-                'capability' => 'export',
76
-                'noheader'   => true,
77
-            ],
78
-            'export_categories'        => [
79
-                'func'       => '_categories_export',
80
-                'capability' => 'export',
81
-                'noheader'   => true,
82
-            ],
83
-            'sample_export_file'       => [
84
-                'func'       => '_sample_export_file',
85
-                'capability' => 'export',
86
-                'noheader'   => true,
87
-            ],
88
-            'update_template_settings' => [
89
-                'func'       => '_update_template_settings',
90
-                'capability' => 'manage_options',
91
-                'noheader'   => true,
92
-            ],
93
-            'ticket_list_table'        => [
94
-                'func'       => '_tickets_overview_list_table',
95
-                'capability' => 'ee_read_default_tickets',
96
-            ],
97
-        ];
98
-        $this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
99
-        $this->_page_config['edit']['metaboxes'][]       = '_premium_event_editor_meta_boxes';
100
-        // don't load these meta boxes if using the advanced editor
101
-        if (
102
-            ! $this->admin_config->useAdvancedEditor()
103
-            || ! $this->feature->allowed('use_default_ticket_manager')
104
-        ) {
105
-            $this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
106
-            $this->_page_config['edit']['qtips'][]       = 'EE_Event_Editor_Tips';
107
-
108
-            $legacy_editor_page_routes = [
109
-                'trash_ticket'    => [
110
-                    'func'       => '_trash_or_restore_ticket',
111
-                    'capability' => 'ee_delete_default_ticket',
112
-                    'obj_id'     => $TKT_ID,
113
-                    'noheader'   => true,
114
-                    'args'       => ['trash' => true],
115
-                ],
116
-                'trash_tickets'   => [
117
-                    'func'       => '_trash_or_restore_ticket',
118
-                    'capability' => 'ee_delete_default_tickets',
119
-                    'noheader'   => true,
120
-                    'args'       => ['trash' => true],
121
-                ],
122
-                'restore_ticket'  => [
123
-                    'func'       => '_trash_or_restore_ticket',
124
-                    'capability' => 'ee_delete_default_ticket',
125
-                    'obj_id'     => $TKT_ID,
126
-                    'noheader'   => true,
127
-                ],
128
-                'restore_tickets' => [
129
-                    'func'       => '_trash_or_restore_ticket',
130
-                    'capability' => 'ee_delete_default_tickets',
131
-                    'noheader'   => true,
132
-                ],
133
-                'delete_ticket'   => [
134
-                    'func'       => '_delete_ticket',
135
-                    'capability' => 'ee_delete_default_ticket',
136
-                    'obj_id'     => $TKT_ID,
137
-                    'noheader'   => true,
138
-                ],
139
-                'delete_tickets'  => [
140
-                    'func'       => '_delete_ticket',
141
-                    'capability' => 'ee_delete_default_tickets',
142
-                    'noheader'   => true,
143
-                ],
144
-            ];
145
-            $new_page_routes           = array_merge($new_page_routes, $legacy_editor_page_routes);
146
-        }
147
-
148
-        $this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
149
-        // partial route/config override
150
-        $this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
151
-        $this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
152
-
153
-        // add default tickets tab and template settings nav tabs (note union at end)
154
-        $this->_page_config = [
155
-                                  'ticket_list_table' => [
156
-                                      'nav'           => [
157
-                                          'label' => esc_html__('Default Tickets', 'event_espresso'),
158
-                                          'icon'  => 'dashicons-tickets-alt',
159
-                                          'order' => 60,
160
-                                      ],
161
-                                      'list_table'    => 'Tickets_List_Table',
162
-                                      'require_nonce' => false,
163
-                                  ],
164
-                                  'template_settings' => [
165
-                                      'nav'           => [
166
-                                          'label' => esc_html__('Templates', 'event_espresso'),
167
-                                          'icon'  => 'dashicons-layout',
168
-                                          'order' => 30,
169
-                                      ],
170
-                                      'metaboxes'     => array_merge(
171
-                                          ['_publish_post_box'],
172
-                                          $this->_default_espresso_metaboxes
173
-                                      ),
174
-                                      'help_tabs'     => [
175
-                                          'general_settings_templates_help_tab' => [
176
-                                              'title'    => esc_html__('Templates', 'event_espresso'),
177
-                                              'filename' => 'general_settings_templates',
178
-                                          ],
179
-                                      ],
180
-                                      'require_nonce' => false,
181
-                                  ],
182
-                              ] + $this->_page_config;
183
-
184
-        // add filters and actions
185
-        // modifying _views
186
-        add_filter(
187
-            'FHEE_event_datetime_metabox_add_additional_date_time_template',
188
-            [$this, 'add_additional_datetime_button'],
189
-            10,
190
-            2
191
-        );
192
-        add_filter(
193
-            'FHEE_event_datetime_metabox_clone_button_template',
194
-            [$this, 'add_datetime_clone_button'],
195
-            10,
196
-            2
197
-        );
198
-        add_filter(
199
-            'FHEE_event_datetime_metabox_timezones_template',
200
-            [$this, 'datetime_timezones_template'],
201
-            10,
202
-            2
203
-        );
204
-        // filters for event list table
205
-        add_filter(
206
-            'FHEE__Events_Admin_List_Table__column_actions__action_links',
207
-            [$this, 'extra_list_table_actions'],
208
-            10,
209
-            2
210
-        );
211
-        // legend item
212
-        add_filter('FHEE__Events_Admin_Page___event_legend_items__items', [$this, 'additional_legend_items']);
213
-        add_action('admin_init', [$this, 'admin_init']);
214
-        // this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
215
-        add_filter('get_sample_permalink_html', [DuplicateEventButton::class, 'addButton'], 8, 4);
216
-    }
217
-
218
-
219
-    /**
220
-     * admin_init
221
-     */
222
-    public function admin_init()
223
-    {
224
-        EE_Registry::$i18n_js_strings = array_merge(
225
-            EE_Registry::$i18n_js_strings,
226
-            [
227
-                'image_confirm'          => esc_html__(
228
-                    'Do you really want to delete this image? Please remember to update your event to complete the removal.',
229
-                    'event_espresso'
230
-                ),
231
-                'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
232
-                'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
233
-                'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
234
-                'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
235
-                'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
236
-            ]
237
-        );
238
-    }
239
-
240
-
241
-    /**
242
-     * Add per page screen options to the default ticket list table view.
243
-     *
244
-     * @throws InvalidArgumentException
245
-     * @throws InvalidDataTypeException
246
-     * @throws InvalidInterfaceException
247
-     */
248
-    protected function _add_screen_options_ticket_list_table()
249
-    {
250
-        $this->_per_page_screen_option();
251
-    }
252
-
253
-
254
-    /**
255
-     * @param string      $return    the current html
256
-     * @param int         $id        the post id for the page
257
-     * @param string|null $new_title What the title is
258
-     * @param string|null $new_slug  what the slug is
259
-     * @return string
260
-     * @deprecated $VID:$
261
-     */
262
-    public function extra_permalink_field_buttons(
263
-        string $return,
264
-        int $id,
265
-        ?string $new_title,
266
-        ?string $new_slug
267
-    ): string {
268
-        $return = DuplicateEventButton::addButton($return, $id, $new_title, $new_slug);
269
-        return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
270
-    }
271
-
272
-
273
-    /**
274
-     * Set the list table views for the default ticket list table view.
275
-     */
276
-    public function _set_list_table_views_ticket_list_table()
277
-    {
278
-        $this->_views = [
279
-            'all'     => [
280
-                'slug'        => 'all',
281
-                'label'       => esc_html__('All', 'event_espresso'),
282
-                'count'       => 0,
283
-                'bulk_action' => [
284
-                    'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
285
-                ],
286
-            ],
287
-            'trashed' => [
288
-                'slug'        => 'trashed',
289
-                'label'       => esc_html__('Trash', 'event_espresso'),
290
-                'count'       => 0,
291
-                'bulk_action' => [
292
-                    'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
293
-                    'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
294
-                ],
295
-            ],
296
-        ];
297
-    }
298
-
299
-
300
-    /**
301
-     * Enqueue scripts and styles for the event editor.
302
-     */
303
-    public function load_scripts_styles_edit()
304
-    {
305
-        if (! $this->admin_config->useAdvancedEditor()) {
306
-            wp_register_script(
307
-                'ee-event-editor-heartbeat',
308
-                EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
309
-                ['ee_admin_js', 'heartbeat'],
310
-                EVENT_ESPRESSO_VERSION,
311
-                true
312
-            );
313
-            wp_enqueue_script('ee-accounting');
314
-            wp_enqueue_script('ee-event-editor-heartbeat');
315
-        }
316
-        wp_enqueue_script('event_editor_js');
317
-        wp_register_style(
318
-            'event-editor-css',
319
-            EVENTS_ASSETS_URL . 'event-editor.css',
320
-            ['ee-admin-css'],
321
-            EVENT_ESPRESSO_VERSION
322
-        );
323
-        wp_enqueue_style('event-editor-css');
324
-        // styles
325
-        wp_enqueue_style('espresso-ui-theme');
326
-    }
327
-
328
-
329
-    /**
330
-     * Sets the views for the default list table view.
331
-     *
332
-     * @throws EE_Error
333
-     * @throws ReflectionException
334
-     */
335
-    protected function _set_list_table_views_default()
336
-    {
337
-        parent::_set_list_table_views_default();
338
-        $new_views    = [
339
-            'today' => [
340
-                'slug'        => 'today',
341
-                'label'       => esc_html__('Today', 'event_espresso'),
342
-                'count'       => $this->total_events_today(),
343
-                'bulk_action' => [
344
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
345
-                ],
346
-            ],
347
-            'month' => [
348
-                'slug'        => 'month',
349
-                'label'       => esc_html__('This Month', 'event_espresso'),
350
-                'count'       => $this->total_events_this_month(),
351
-                'bulk_action' => [
352
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
353
-                ],
354
-            ],
355
-        ];
356
-        $this->_views = array_merge($this->_views, $new_views);
357
-    }
358
-
359
-
360
-    /**
361
-     * Returns the extra action links for the default list table view.
362
-     *
363
-     * @param array    $action_links
364
-     * @param EE_Event $event
365
-     * @return array
366
-     * @throws EE_Error
367
-     * @throws ReflectionException
368
-     */
369
-    public function extra_list_table_actions(array $action_links, EE_Event $event): array
370
-    {
371
-        if (
372
-        EE_Registry::instance()->CAP->current_user_can(
373
-            'ee_read_registrations',
374
-            'espresso_registrations_reports',
375
-            $event->ID()
376
-        )
377
-        ) {
378
-            $reports_link = EE_Admin_Page::add_query_args_and_nonce(
379
-                [
380
-                    'action' => 'reports',
381
-                    'EVT_ID' => $event->ID(),
382
-                ],
383
-                REG_ADMIN_URL
384
-            );
385
-
386
-            $action_links[] = '
19
+	/**
20
+	 * @var EE_Admin_Config
21
+	 */
22
+	protected $admin_config;
23
+
24
+
25
+	/**
26
+	 * Extend_Events_Admin_Page constructor.
27
+	 *
28
+	 * @param bool $routing
29
+	 * @throws ReflectionException
30
+	 */
31
+	public function __construct($routing = true)
32
+	{
33
+		if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
34
+			define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
35
+			define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
36
+			define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
37
+		}
38
+		parent::__construct($routing);
39
+		$this->admin_config = $this->loader->getShared('EE_Admin_Config');
40
+	}
41
+
42
+
43
+	protected function _set_page_config()
44
+	{
45
+		parent::_set_page_config();
46
+
47
+		$this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
48
+		// is there a evt_id in the request?
49
+		$EVT_ID                                          = $this->request->getRequestParam('EVT_ID', 0, 'int');
50
+		$EVT_ID                                          = $this->request->getRequestParam('post', $EVT_ID, 'int');
51
+		$TKT_ID                                          = $this->request->getRequestParam('TKT_ID', 0, 'int');
52
+		$new_page_routes                                 = [
53
+			'duplicate_event'          => [
54
+				'func'       => '_duplicate_event',
55
+				'capability' => 'ee_edit_event',
56
+				'obj_id'     => $EVT_ID,
57
+				'noheader'   => true,
58
+			],
59
+			'import_page'              => [
60
+				'func'       => '_import_page',
61
+				'capability' => 'import',
62
+			],
63
+			'import'                   => [
64
+				'func'       => '_import_events',
65
+				'capability' => 'import',
66
+				'noheader'   => true,
67
+			],
68
+			'import_events'            => [
69
+				'func'       => '_import_events',
70
+				'capability' => 'import',
71
+				'noheader'   => true,
72
+			],
73
+			'export_events'            => [
74
+				'func'       => '_events_export',
75
+				'capability' => 'export',
76
+				'noheader'   => true,
77
+			],
78
+			'export_categories'        => [
79
+				'func'       => '_categories_export',
80
+				'capability' => 'export',
81
+				'noheader'   => true,
82
+			],
83
+			'sample_export_file'       => [
84
+				'func'       => '_sample_export_file',
85
+				'capability' => 'export',
86
+				'noheader'   => true,
87
+			],
88
+			'update_template_settings' => [
89
+				'func'       => '_update_template_settings',
90
+				'capability' => 'manage_options',
91
+				'noheader'   => true,
92
+			],
93
+			'ticket_list_table'        => [
94
+				'func'       => '_tickets_overview_list_table',
95
+				'capability' => 'ee_read_default_tickets',
96
+			],
97
+		];
98
+		$this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
99
+		$this->_page_config['edit']['metaboxes'][]       = '_premium_event_editor_meta_boxes';
100
+		// don't load these meta boxes if using the advanced editor
101
+		if (
102
+			! $this->admin_config->useAdvancedEditor()
103
+			|| ! $this->feature->allowed('use_default_ticket_manager')
104
+		) {
105
+			$this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
106
+			$this->_page_config['edit']['qtips'][]       = 'EE_Event_Editor_Tips';
107
+
108
+			$legacy_editor_page_routes = [
109
+				'trash_ticket'    => [
110
+					'func'       => '_trash_or_restore_ticket',
111
+					'capability' => 'ee_delete_default_ticket',
112
+					'obj_id'     => $TKT_ID,
113
+					'noheader'   => true,
114
+					'args'       => ['trash' => true],
115
+				],
116
+				'trash_tickets'   => [
117
+					'func'       => '_trash_or_restore_ticket',
118
+					'capability' => 'ee_delete_default_tickets',
119
+					'noheader'   => true,
120
+					'args'       => ['trash' => true],
121
+				],
122
+				'restore_ticket'  => [
123
+					'func'       => '_trash_or_restore_ticket',
124
+					'capability' => 'ee_delete_default_ticket',
125
+					'obj_id'     => $TKT_ID,
126
+					'noheader'   => true,
127
+				],
128
+				'restore_tickets' => [
129
+					'func'       => '_trash_or_restore_ticket',
130
+					'capability' => 'ee_delete_default_tickets',
131
+					'noheader'   => true,
132
+				],
133
+				'delete_ticket'   => [
134
+					'func'       => '_delete_ticket',
135
+					'capability' => 'ee_delete_default_ticket',
136
+					'obj_id'     => $TKT_ID,
137
+					'noheader'   => true,
138
+				],
139
+				'delete_tickets'  => [
140
+					'func'       => '_delete_ticket',
141
+					'capability' => 'ee_delete_default_tickets',
142
+					'noheader'   => true,
143
+				],
144
+			];
145
+			$new_page_routes           = array_merge($new_page_routes, $legacy_editor_page_routes);
146
+		}
147
+
148
+		$this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
149
+		// partial route/config override
150
+		$this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
151
+		$this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
152
+
153
+		// add default tickets tab and template settings nav tabs (note union at end)
154
+		$this->_page_config = [
155
+								  'ticket_list_table' => [
156
+									  'nav'           => [
157
+										  'label' => esc_html__('Default Tickets', 'event_espresso'),
158
+										  'icon'  => 'dashicons-tickets-alt',
159
+										  'order' => 60,
160
+									  ],
161
+									  'list_table'    => 'Tickets_List_Table',
162
+									  'require_nonce' => false,
163
+								  ],
164
+								  'template_settings' => [
165
+									  'nav'           => [
166
+										  'label' => esc_html__('Templates', 'event_espresso'),
167
+										  'icon'  => 'dashicons-layout',
168
+										  'order' => 30,
169
+									  ],
170
+									  'metaboxes'     => array_merge(
171
+										  ['_publish_post_box'],
172
+										  $this->_default_espresso_metaboxes
173
+									  ),
174
+									  'help_tabs'     => [
175
+										  'general_settings_templates_help_tab' => [
176
+											  'title'    => esc_html__('Templates', 'event_espresso'),
177
+											  'filename' => 'general_settings_templates',
178
+										  ],
179
+									  ],
180
+									  'require_nonce' => false,
181
+								  ],
182
+							  ] + $this->_page_config;
183
+
184
+		// add filters and actions
185
+		// modifying _views
186
+		add_filter(
187
+			'FHEE_event_datetime_metabox_add_additional_date_time_template',
188
+			[$this, 'add_additional_datetime_button'],
189
+			10,
190
+			2
191
+		);
192
+		add_filter(
193
+			'FHEE_event_datetime_metabox_clone_button_template',
194
+			[$this, 'add_datetime_clone_button'],
195
+			10,
196
+			2
197
+		);
198
+		add_filter(
199
+			'FHEE_event_datetime_metabox_timezones_template',
200
+			[$this, 'datetime_timezones_template'],
201
+			10,
202
+			2
203
+		);
204
+		// filters for event list table
205
+		add_filter(
206
+			'FHEE__Events_Admin_List_Table__column_actions__action_links',
207
+			[$this, 'extra_list_table_actions'],
208
+			10,
209
+			2
210
+		);
211
+		// legend item
212
+		add_filter('FHEE__Events_Admin_Page___event_legend_items__items', [$this, 'additional_legend_items']);
213
+		add_action('admin_init', [$this, 'admin_init']);
214
+		// this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
215
+		add_filter('get_sample_permalink_html', [DuplicateEventButton::class, 'addButton'], 8, 4);
216
+	}
217
+
218
+
219
+	/**
220
+	 * admin_init
221
+	 */
222
+	public function admin_init()
223
+	{
224
+		EE_Registry::$i18n_js_strings = array_merge(
225
+			EE_Registry::$i18n_js_strings,
226
+			[
227
+				'image_confirm'          => esc_html__(
228
+					'Do you really want to delete this image? Please remember to update your event to complete the removal.',
229
+					'event_espresso'
230
+				),
231
+				'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
232
+				'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
233
+				'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
234
+				'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
235
+				'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
236
+			]
237
+		);
238
+	}
239
+
240
+
241
+	/**
242
+	 * Add per page screen options to the default ticket list table view.
243
+	 *
244
+	 * @throws InvalidArgumentException
245
+	 * @throws InvalidDataTypeException
246
+	 * @throws InvalidInterfaceException
247
+	 */
248
+	protected function _add_screen_options_ticket_list_table()
249
+	{
250
+		$this->_per_page_screen_option();
251
+	}
252
+
253
+
254
+	/**
255
+	 * @param string      $return    the current html
256
+	 * @param int         $id        the post id for the page
257
+	 * @param string|null $new_title What the title is
258
+	 * @param string|null $new_slug  what the slug is
259
+	 * @return string
260
+	 * @deprecated $VID:$
261
+	 */
262
+	public function extra_permalink_field_buttons(
263
+		string $return,
264
+		int $id,
265
+		?string $new_title,
266
+		?string $new_slug
267
+	): string {
268
+		$return = DuplicateEventButton::addButton($return, $id, $new_title, $new_slug);
269
+		return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
270
+	}
271
+
272
+
273
+	/**
274
+	 * Set the list table views for the default ticket list table view.
275
+	 */
276
+	public function _set_list_table_views_ticket_list_table()
277
+	{
278
+		$this->_views = [
279
+			'all'     => [
280
+				'slug'        => 'all',
281
+				'label'       => esc_html__('All', 'event_espresso'),
282
+				'count'       => 0,
283
+				'bulk_action' => [
284
+					'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
285
+				],
286
+			],
287
+			'trashed' => [
288
+				'slug'        => 'trashed',
289
+				'label'       => esc_html__('Trash', 'event_espresso'),
290
+				'count'       => 0,
291
+				'bulk_action' => [
292
+					'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
293
+					'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
294
+				],
295
+			],
296
+		];
297
+	}
298
+
299
+
300
+	/**
301
+	 * Enqueue scripts and styles for the event editor.
302
+	 */
303
+	public function load_scripts_styles_edit()
304
+	{
305
+		if (! $this->admin_config->useAdvancedEditor()) {
306
+			wp_register_script(
307
+				'ee-event-editor-heartbeat',
308
+				EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
309
+				['ee_admin_js', 'heartbeat'],
310
+				EVENT_ESPRESSO_VERSION,
311
+				true
312
+			);
313
+			wp_enqueue_script('ee-accounting');
314
+			wp_enqueue_script('ee-event-editor-heartbeat');
315
+		}
316
+		wp_enqueue_script('event_editor_js');
317
+		wp_register_style(
318
+			'event-editor-css',
319
+			EVENTS_ASSETS_URL . 'event-editor.css',
320
+			['ee-admin-css'],
321
+			EVENT_ESPRESSO_VERSION
322
+		);
323
+		wp_enqueue_style('event-editor-css');
324
+		// styles
325
+		wp_enqueue_style('espresso-ui-theme');
326
+	}
327
+
328
+
329
+	/**
330
+	 * Sets the views for the default list table view.
331
+	 *
332
+	 * @throws EE_Error
333
+	 * @throws ReflectionException
334
+	 */
335
+	protected function _set_list_table_views_default()
336
+	{
337
+		parent::_set_list_table_views_default();
338
+		$new_views    = [
339
+			'today' => [
340
+				'slug'        => 'today',
341
+				'label'       => esc_html__('Today', 'event_espresso'),
342
+				'count'       => $this->total_events_today(),
343
+				'bulk_action' => [
344
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
345
+				],
346
+			],
347
+			'month' => [
348
+				'slug'        => 'month',
349
+				'label'       => esc_html__('This Month', 'event_espresso'),
350
+				'count'       => $this->total_events_this_month(),
351
+				'bulk_action' => [
352
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
353
+				],
354
+			],
355
+		];
356
+		$this->_views = array_merge($this->_views, $new_views);
357
+	}
358
+
359
+
360
+	/**
361
+	 * Returns the extra action links for the default list table view.
362
+	 *
363
+	 * @param array    $action_links
364
+	 * @param EE_Event $event
365
+	 * @return array
366
+	 * @throws EE_Error
367
+	 * @throws ReflectionException
368
+	 */
369
+	public function extra_list_table_actions(array $action_links, EE_Event $event): array
370
+	{
371
+		if (
372
+		EE_Registry::instance()->CAP->current_user_can(
373
+			'ee_read_registrations',
374
+			'espresso_registrations_reports',
375
+			$event->ID()
376
+		)
377
+		) {
378
+			$reports_link = EE_Admin_Page::add_query_args_and_nonce(
379
+				[
380
+					'action' => 'reports',
381
+					'EVT_ID' => $event->ID(),
382
+				],
383
+				REG_ADMIN_URL
384
+			);
385
+
386
+			$action_links[] = '
387 387
                 <a href="' . $reports_link . '"
388 388
                     aria-label="' . esc_attr__('View Report', 'event_espresso') . '"
389 389
                     class="ee-aria-tooltip button button--icon-only"
390 390
                 >
391 391
                     <span class="dashicons dashicons-chart-bar"></span>
392 392
                 </a>';
393
-        }
394
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
395
-            EE_Registry::instance()->load_helper('MSG_Template');
396
-            $action_links[] = EEH_MSG_Template::get_message_action_link(
397
-                'see_notifications_for',
398
-                null,
399
-                ['EVT_ID' => $event->ID()]
400
-            );
401
-        }
402
-        return $action_links;
403
-    }
404
-
405
-
406
-    /**
407
-     * @param $items
408
-     * @return mixed
409
-     */
410
-    public function additional_legend_items($items)
411
-    {
412
-        if (
413
-        EE_Registry::instance()->CAP->current_user_can(
414
-            'ee_read_registrations',
415
-            'espresso_registrations_reports'
416
-        )
417
-        ) {
418
-            $items['reports'] = [
419
-                'class' => 'dashicons dashicons-chart-bar',
420
-                'desc'  => esc_html__('Event Reports', 'event_espresso'),
421
-            ];
422
-        }
423
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
424
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
425
-            // $related_for_icon can sometimes be a string so 'css_class' would be an illegal offset
426
-            // (can only use numeric offsets when treating strings as arrays)
427
-            if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
428
-                $items['view_related_messages'] = [
429
-                    'class' => $related_for_icon['css_class'],
430
-                    'desc'  => $related_for_icon['label'],
431
-                ];
432
-            }
433
-        }
434
-        return $items;
435
-    }
436
-
437
-
438
-    /**
439
-     * This is the callback method for the duplicate event route
440
-     * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
441
-     * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
442
-     * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
443
-     * After duplication the redirect is to the new event edit page.
444
-     *
445
-     * @return void
446
-     * @throws EE_Error If EE_Event is not available with given ID
447
-     * @throws ReflectionException
448
-     * @access protected
449
-     */
450
-    protected function _duplicate_event()
451
-    {
452
-        // first make sure the ID for the event is in the request.
453
-        //  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
454
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
455
-        if (! $EVT_ID) {
456
-            EE_Error::add_error(
457
-                esc_html__(
458
-                    'In order to duplicate an event an Event ID is required.  None was given.',
459
-                    'event_espresso'
460
-                ),
461
-                __FILE__,
462
-                __FUNCTION__,
463
-                __LINE__
464
-            );
465
-            $this->_redirect_after_action(false, '', '', [], true);
466
-            return;
467
-        }
468
-        // k we've got EVT_ID so let's use that to get the event we'll duplicate
469
-        $orig_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
470
-        if (! $orig_event instanceof EE_Event) {
471
-            throw new EE_Error(
472
-                sprintf(
473
-                    esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
474
-                    $EVT_ID
475
-                )
476
-            );
477
-        }
478
-        // k now let's clone the $orig_event before getting relations
479
-        $new_event = clone $orig_event;
480
-        // original datetimes
481
-        $orig_datetimes = $orig_event->get_many_related('Datetime');
482
-        // other original relations
483
-        $orig_ven = $orig_event->get_many_related('Venue');
484
-        // reset the ID and modify other details to make it clear this is a dupe
485
-        $new_event->set('EVT_ID', 0);
486
-        $new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
487
-        $new_event->set('EVT_name', $new_name);
488
-        $new_event->set(
489
-            'EVT_slug',
490
-            wp_unique_post_slug(
491
-                sanitize_title($orig_event->name()),
492
-                0,
493
-                'publish',
494
-                'espresso_events',
495
-                0
496
-            )
497
-        );
498
-        $new_event->set('status', 'draft');
499
-        // duplicate discussion settings
500
-        $new_event->set('comment_status', $orig_event->get('comment_status'));
501
-        $new_event->set('ping_status', $orig_event->get('ping_status'));
502
-        // save the new event
503
-        $new_event->save();
504
-        // venues
505
-        foreach ($orig_ven as $ven) {
506
-            $new_event->_add_relation_to($ven, 'Venue');
507
-        }
508
-        $new_event->save();
509
-        // now we need to get the question group relations and handle that
510
-        // first primary question groups
511
-        $orig_primary_qgs = $orig_event->get_many_related(
512
-            'Question_Group',
513
-            [['Event_Question_Group.EQG_primary' => true]]
514
-        );
515
-        if (! empty($orig_primary_qgs)) {
516
-            foreach ($orig_primary_qgs as $obj) {
517
-                if ($obj instanceof EE_Question_Group) {
518
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
519
-                }
520
-            }
521
-        }
522
-        // next additional attendee question groups
523
-        $orig_additional_qgs = $orig_event->get_many_related(
524
-            'Question_Group',
525
-            [['Event_Question_Group.EQG_additional' => true]]
526
-        );
527
-        if (! empty($orig_additional_qgs)) {
528
-            foreach ($orig_additional_qgs as $obj) {
529
-                if ($obj instanceof EE_Question_Group) {
530
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
531
-                }
532
-            }
533
-        }
534
-
535
-        $new_event->save();
536
-
537
-        // k now that we have the new event saved we can loop through the datetimes and start adding relations.
538
-        $cloned_tickets = [];
539
-        foreach ($orig_datetimes as $orig_dtt) {
540
-            if (! $orig_dtt instanceof EE_Datetime) {
541
-                continue;
542
-            }
543
-            $new_dtt      = clone $orig_dtt;
544
-            $orig_tickets = $orig_dtt->tickets();
545
-            // save new dtt then add to event
546
-            $new_dtt->set('DTT_ID', 0);
547
-            $new_dtt->set('DTT_sold', 0);
548
-            $new_dtt->set_reserved(0);
549
-            $new_dtt->save();
550
-            $new_event->_add_relation_to($new_dtt, 'Datetime');
551
-            $new_event->save();
552
-            // now let's get the ticket relations setup.
553
-            foreach ((array) $orig_tickets as $orig_ticket) {
554
-                // it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
555
-                if (! $orig_ticket instanceof EE_Ticket) {
556
-                    continue;
557
-                }
558
-                // is this ticket archived?  If it is then let's skip
559
-                if ($orig_ticket->get('TKT_deleted')) {
560
-                    continue;
561
-                }
562
-                // does this original ticket already exist in the clone_tickets cache?
563
-                //  If so we'll just use the new ticket from it.
564
-                if (isset($cloned_tickets[ $orig_ticket->ID() ])) {
565
-                    $new_ticket = $cloned_tickets[ $orig_ticket->ID() ];
566
-                } else {
567
-                    $new_ticket = clone $orig_ticket;
568
-                    // get relations on the $orig_ticket that we need to setup.
569
-                    $orig_prices = $orig_ticket->prices();
570
-                    $new_ticket->set('TKT_ID', 0);
571
-                    $new_ticket->set('TKT_sold', 0);
572
-                    $new_ticket->set('TKT_reserved', 0);
573
-                    $new_ticket->save(); // make sure new ticket has ID.
574
-                    // price relations on new ticket need to be setup.
575
-                    foreach ($orig_prices as $orig_price) {
576
-                        $new_price = clone $orig_price;
577
-                        $new_price->set('PRC_ID', 0);
578
-                        $new_price->save();
579
-                        $new_ticket->_add_relation_to($new_price, 'Price');
580
-                        $new_ticket->save();
581
-                    }
582
-
583
-                    do_action(
584
-                        'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
585
-                        $orig_ticket,
586
-                        $new_ticket,
587
-                        $orig_prices,
588
-                        $orig_event,
589
-                        $orig_dtt,
590
-                        $new_dtt
591
-                    );
592
-                }
593
-                // k now we can add the new ticket as a relation to the new datetime
594
-                // and make sure its added to our cached $cloned_tickets array
595
-                // for use with later datetimes that have the same ticket.
596
-                $new_dtt->_add_relation_to($new_ticket, 'Ticket');
597
-                $new_dtt->save();
598
-                $cloned_tickets[ $orig_ticket->ID() ] = $new_ticket;
599
-            }
600
-        }
601
-        // clone taxonomy information
602
-        $taxonomies_to_clone_with = apply_filters(
603
-            'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
604
-            ['espresso_event_categories', 'espresso_event_type', 'post_tag']
605
-        );
606
-        // get terms for original event (notice)
607
-        $orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
608
-        // loop through terms and add them to new event.
609
-        foreach ($orig_terms as $term) {
610
-            wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
611
-        }
612
-
613
-        // duplicate other core WP_Post items for this event.
614
-        // post thumbnail (feature image).
615
-        $feature_image_id = get_post_thumbnail_id($orig_event->ID());
616
-        if ($feature_image_id) {
617
-            update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
618
-        }
619
-
620
-        // duplicate page_template setting
621
-        $page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
622
-        if ($page_template) {
623
-            update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
624
-        }
625
-
626
-        do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
627
-        // now let's redirect to the edit page for this duplicated event if we have a new event id.
628
-        if ($new_event->ID()) {
629
-            $redirect_args = [
630
-                'post'   => $new_event->ID(),
631
-                'action' => 'edit',
632
-            ];
633
-            EE_Error::add_success(
634
-                esc_html__(
635
-                    'Event successfully duplicated.  Please review the details below and make any necessary edits',
636
-                    'event_espresso'
637
-                )
638
-            );
639
-        } else {
640
-            $redirect_args = [
641
-                'action' => 'default',
642
-            ];
643
-            EE_Error::add_error(
644
-                esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
645
-                __FILE__,
646
-                __FUNCTION__,
647
-                __LINE__
648
-            );
649
-        }
650
-        $this->_redirect_after_action(false, '', '', $redirect_args, true);
651
-    }
652
-
653
-
654
-    /**
655
-     * Generates output for the import page.
656
-     *
657
-     * @throws EE_Error
658
-     */
659
-    protected function _import_page()
660
-    {
661
-        $title = esc_html__('Import', 'event_espresso');
662
-        $intro = esc_html__(
663
-            'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
664
-            'event_espresso'
665
-        );
666
-
667
-        $form_url = EVENTS_ADMIN_URL;
668
-        $action   = 'import_events';
669
-        $type     = 'csv';
670
-
671
-        $this->_template_args['form'] = EE_Import::instance()->upload_form(
672
-            $title,
673
-            $intro,
674
-            $form_url,
675
-            $action,
676
-            $type
677
-        );
678
-
679
-        $this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
680
-            ['action' => 'sample_export_file'],
681
-            $this->_admin_base_url
682
-        );
683
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
684
-            EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
685
-            $this->_template_args,
686
-            true
687
-        );
688
-        $this->display_admin_page_with_sidebar();
689
-    }
690
-
691
-
692
-    /**
693
-     * _import_events
694
-     * This handles displaying the screen and running imports for importing events.
695
-     *
696
-     * @return void
697
-     * @throws EE_Error
698
-     */
699
-    protected function _import_events()
700
-    {
701
-        require_once(EE_CLASSES . 'EE_Import.class.php');
702
-        $success = EE_Import::instance()->import();
703
-        $this->_redirect_after_action(
704
-            $success,
705
-            esc_html__('Import File', 'event_espresso'),
706
-            'ran',
707
-            ['action' => 'import_page'],
708
-            true
709
-        );
710
-    }
711
-
712
-
713
-    /**
714
-     * _events_export
715
-     * Will export all (or just the given event) to a Excel compatible file.
716
-     *
717
-     * @access protected
718
-     * @return void
719
-     */
720
-    protected function _events_export()
721
-    {
722
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
723
-        $EVT_ID = $this->request->getRequestParam('EVT_IDs', $EVT_ID, 'int');
724
-        $this->request->mergeRequestParams(
725
-            [
726
-                'export' => 'report',
727
-                'action' => 'all_event_data',
728
-                'EVT_ID' => $EVT_ID,
729
-            ]
730
-        );
731
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
732
-            require_once(EE_CLASSES . 'EE_Export.class.php');
733
-            $EE_Export = EE_Export::instance($this->request->requestParams());
734
-            $EE_Export->export();
735
-        }
736
-    }
737
-
738
-
739
-    /**
740
-     * handle category exports()
741
-     *
742
-     * @return void
743
-     */
744
-    protected function _categories_export()
745
-    {
746
-        $EVT_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
747
-        $this->request->mergeRequestParams(
748
-            [
749
-                'export' => 'report',
750
-                'action' => 'categories',
751
-                'EVT_ID' => $EVT_ID,
752
-            ]
753
-        );
754
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
755
-            require_once(EE_CLASSES . 'EE_Export.class.php');
756
-            $EE_Export = EE_Export::instance($this->request->requestParams());
757
-            $EE_Export->export();
758
-        }
759
-    }
760
-
761
-
762
-    /**
763
-     * Creates a sample CSV file for importing
764
-     */
765
-    protected function _sample_export_file()
766
-    {
767
-        $EE_Export = EE_Export::instance();
768
-        if ($EE_Export instanceof EE_Export) {
769
-            $EE_Export->export();
770
-        }
771
-    }
772
-
773
-
774
-    /*************        Template Settings        *************/
775
-    /**
776
-     * Generates template settings page output
777
-     *
778
-     * @throws DomainException
779
-     * @throws EE_Error
780
-     * @throws InvalidArgumentException
781
-     * @throws InvalidDataTypeException
782
-     * @throws InvalidInterfaceException
783
-     */
784
-    protected function _template_settings()
785
-    {
786
-        $this->_template_args['values'] = $this->_yes_no_values;
787
-        /**
788
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
789
-         * from General_Settings_Admin_Page to here.
790
-         */
791
-        $this->_template_args = apply_filters(
792
-            'FHEE__General_Settings_Admin_Page__template_settings__template_args',
793
-            $this->_template_args
794
-        );
795
-        $this->_set_add_edit_form_tags('update_template_settings');
796
-        $this->_set_publish_post_box_vars();
797
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
798
-            EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
799
-            $this->_template_args,
800
-            true
801
-        );
802
-        $this->display_admin_page_with_sidebar();
803
-    }
804
-
805
-
806
-    /**
807
-     * Handler for updating template settings.
808
-     *
809
-     * @throws EE_Error
810
-     */
811
-    protected function _update_template_settings()
812
-    {
813
-        /**
814
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
815
-         * from General_Settings_Admin_Page to here.
816
-         */
817
-        EE_Registry::instance()->CFG->template_settings = apply_filters(
818
-            'FHEE__General_Settings_Admin_Page__update_template_settings__data',
819
-            EE_Registry::instance()->CFG->template_settings,
820
-            $this->request->requestParams()
821
-        );
822
-        // update custom post type slugs and detect if we need to flush rewrite rules
823
-        $old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
824
-
825
-        $event_cpt_slug = $this->request->getRequestParam('event_cpt_slug');
826
-
827
-        EE_Registry::instance()->CFG->core->event_cpt_slug = $event_cpt_slug
828
-            ? EEH_URL::slugify($event_cpt_slug, 'events')
829
-            : EE_Registry::instance()->CFG->core->event_cpt_slug;
830
-
831
-        $what    = esc_html__('Template Settings', 'event_espresso');
832
-        $success = $this->_update_espresso_configuration(
833
-            $what,
834
-            EE_Registry::instance()->CFG->template_settings,
835
-            __FILE__,
836
-            __FUNCTION__,
837
-            __LINE__
838
-        );
839
-        if (EE_Registry::instance()->CFG->core->event_cpt_slug !== $old_slug) {
840
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
841
-            $rewrite_rules = LoaderFactory::getLoader()->getShared(
842
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
843
-            );
844
-            $rewrite_rules->flush();
845
-        }
846
-        $this->_redirect_after_action($success, $what, 'updated', ['action' => 'template_settings']);
847
-    }
848
-
849
-
850
-    /**
851
-     * _premium_event_editor_meta_boxes
852
-     * add all metaboxes related to the event_editor
853
-     *
854
-     * @access protected
855
-     * @return void
856
-     * @throws EE_Error
857
-     * @throws ReflectionException
858
-     */
859
-    protected function _premium_event_editor_meta_boxes()
860
-    {
861
-        $this->verify_cpt_object();
862
-        // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
863
-        if (
864
-            ! $this->admin_config->useAdvancedEditor()
865
-            || ! $this->feature->allowed('use_reg_options_meta_box')
866
-        ) {
867
-            $this->addMetaBox(
868
-                'espresso_event_editor_event_options',
869
-                esc_html__('Event Registration Options', 'event_espresso'),
870
-                [$this, 'registration_options_meta_box'],
871
-                $this->page_slug,
872
-                'side',
873
-                'core'
874
-            );
875
-        }
876
-    }
877
-
878
-
879
-    /**
880
-     * override caf metabox
881
-     *
882
-     * @return void
883
-     * @throws EE_Error
884
-     * @throws ReflectionException
885
-     */
886
-    public function registration_options_meta_box()
887
-    {
888
-        $yes_no_values = [
889
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
890
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
891
-        ];
892
-
893
-        $default_reg_status_values = EEM_Registration::reg_status_array(
894
-            [
895
-                EEM_Registration::status_id_cancelled,
896
-                EEM_Registration::status_id_declined,
897
-                EEM_Registration::status_id_incomplete,
898
-                EEM_Registration::status_id_wait_list,
899
-            ],
900
-            true
901
-        );
902
-
903
-        $template_args['active_status']    = $this->_cpt_model_obj->pretty_active_status(false);
904
-        $template_args['_event']           = $this->_cpt_model_obj;
905
-        $template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
906
-
907
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
908
-            'default_reg_status',
909
-            $default_reg_status_values,
910
-            $this->_cpt_model_obj->default_registration_status()
911
-        );
912
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
913
-            'display_desc',
914
-            $yes_no_values,
915
-            $this->_cpt_model_obj->display_description()
916
-        );
917
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
918
-            'display_ticket_selector',
919
-            $yes_no_values,
920
-            $this->_cpt_model_obj->display_ticket_selector(),
921
-            '',
922
-            '',
923
-            false
924
-        );
925
-        $template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
926
-            'EVT_default_registration_status',
927
-            $default_reg_status_values,
928
-            $this->_cpt_model_obj->default_registration_status()
929
-        );
930
-        $template_args['additional_registration_options'] = apply_filters(
931
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
932
-            '',
933
-            $template_args,
934
-            $yes_no_values,
935
-            $default_reg_status_values
936
-        );
937
-        EEH_Template::display_template(
938
-            EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
939
-            $template_args
940
-        );
941
-    }
942
-
943
-
944
-
945
-    /**
946
-     * wp_list_table_mods for caf
947
-     * ============================
948
-     */
949
-
950
-
951
-    /**
952
-     * espresso_event_months_dropdown
953
-     *
954
-     * @deprecatd $VID:$
955
-     * @access public
956
-     * @return string                dropdown listing month/year selections for events.
957
-     * @throws EE_Error
958
-     */
959
-    public function espresso_event_months_dropdown(): string
960
-    {
961
-        // what we need to do is get all PRIMARY datetimes for all events to filter on.
962
-        // Note we need to include any other filters that are set!
963
-        return EEH_Form_Fields::generate_event_months_dropdown(
964
-            $this->request->getRequestParam('month_range'),
965
-            $this->request->getRequestParam('status'),
966
-            $this->request->getRequestParam('EVT_CAT', 0, 'int'),
967
-            $this->request->getRequestParam('active_status')
968
-        );
969
-    }
970
-
971
-
972
-    /**
973
-     * returns a list of "active" statuses on the event
974
-     *
975
-     * @deprecatd $VID:$
976
-     * @param string $current_value whatever the current active status is
977
-     * @return string
978
-     */
979
-    public function active_status_dropdown(string $current_value = ''): string
980
-    {
981
-        $select_name = 'active_status';
982
-        $values      = [
983
-            'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
984
-            'active'   => esc_html__('Active', 'event_espresso'),
985
-            'upcoming' => esc_html__('Upcoming', 'event_espresso'),
986
-            'expired'  => esc_html__('Expired', 'event_espresso'),
987
-            'inactive' => esc_html__('Inactive', 'event_espresso'),
988
-        ];
989
-
990
-        return EEH_Form_Fields::select_input($select_name, $values, $current_value);
991
-    }
992
-
993
-
994
-    /**
995
-     * returns a list of "venues"
996
-     *
997
-     * @deprecatd $VID:$
998
-     * @param string $current_value whatever the current active status is
999
-     * @return string
1000
-     * @throws EE_Error
1001
-     * @throws ReflectionException
1002
-     */
1003
-    protected function venuesDropdown(string $current_value = ''): string
1004
-    {
1005
-        $values = ['' => esc_html__('All Venues', 'event_espresso')];
1006
-        // populate the list of venues.
1007
-        $venues = EEM_Venue::instance()->get_all(['order_by' => ['VNU_name' => 'ASC']]);
1008
-
1009
-        foreach ($venues as $venue) {
1010
-            $values[ $venue->ID() ] = $venue->name();
1011
-        }
1012
-
1013
-        return EEH_Form_Fields::select_input('venue', $values, $current_value);
1014
-    }
1015
-
1016
-
1017
-    /**
1018
-     * output a dropdown of the categories for the category filter on the event admin list table
1019
-     *
1020
-     * @deprecatd $VID:$
1021
-     * @access  public
1022
-     * @return string html
1023
-     * @throws EE_Error
1024
-     * @throws ReflectionException
1025
-     */
1026
-    public function category_dropdown(): string
1027
-    {
1028
-        return EEH_Form_Fields::generate_event_category_dropdown(
1029
-            $this->request->getRequestParam('EVT_CAT', -1, 'int')
1030
-        );
1031
-    }
1032
-
1033
-
1034
-    /**
1035
-     * get total number of events today
1036
-     *
1037
-     * @access public
1038
-     * @return int
1039
-     * @throws EE_Error
1040
-     * @throws InvalidArgumentException
1041
-     * @throws InvalidDataTypeException
1042
-     * @throws InvalidInterfaceException
1043
-     * @throws ReflectionException
1044
-     */
1045
-    public function total_events_today(): int
1046
-    {
1047
-        $start = EEM_Datetime::instance()->convert_datetime_for_query(
1048
-            'DTT_EVT_start',
1049
-            date('Y-m-d') . ' 00:00:00',
1050
-            'Y-m-d H:i:s',
1051
-            'UTC'
1052
-        );
1053
-        $end   = EEM_Datetime::instance()->convert_datetime_for_query(
1054
-            'DTT_EVT_start',
1055
-            date('Y-m-d') . ' 23:59:59',
1056
-            'Y-m-d H:i:s',
1057
-            'UTC'
1058
-        );
1059
-        $where = [
1060
-            'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1061
-        ];
1062
-        return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1063
-    }
1064
-
1065
-
1066
-    /**
1067
-     * get total number of events this month
1068
-     *
1069
-     * @access public
1070
-     * @return int
1071
-     * @throws EE_Error
1072
-     * @throws InvalidArgumentException
1073
-     * @throws InvalidDataTypeException
1074
-     * @throws InvalidInterfaceException
1075
-     * @throws ReflectionException
1076
-     */
1077
-    public function total_events_this_month(): int
1078
-    {
1079
-        // Dates
1080
-        $this_year_r     = date('Y');
1081
-        $this_month_r    = date('m');
1082
-        $days_this_month = date('t');
1083
-        $start           = EEM_Datetime::instance()->convert_datetime_for_query(
1084
-            'DTT_EVT_start',
1085
-            $this_year_r . '-' . $this_month_r . '-01 00:00:00',
1086
-            'Y-m-d H:i:s',
1087
-            'UTC'
1088
-        );
1089
-        $end             = EEM_Datetime::instance()->convert_datetime_for_query(
1090
-            'DTT_EVT_start',
1091
-            $this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1092
-            'Y-m-d H:i:s',
1093
-            'UTC'
1094
-        );
1095
-        $where           = [
1096
-            'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1097
-        ];
1098
-        return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1099
-    }
1100
-
1101
-
1102
-    /** DEFAULT TICKETS STUFF **/
1103
-
1104
-    /**
1105
-     * Output default tickets list table view.
1106
-     *
1107
-     * @throws EE_Error
1108
-     */
1109
-    public function _tickets_overview_list_table()
1110
-    {
1111
-        if (
1112
-            $this->admin_config->useAdvancedEditor()
1113
-            && $this->feature->allowed('use_default_ticket_manager')
1114
-        ) {
1115
-            // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1116
-            $this->_template_args['admin_page_content'] = EEH_Template::display_template(
1117
-                EVENTS_CAF_TEMPLATE_PATH . 'default_tickets_moved_notice.template.php',
1118
-                [],
1119
-                true
1120
-            );
1121
-            $this->display_admin_page_with_no_sidebar();
1122
-        } else {
1123
-            $this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1124
-            $this->display_admin_list_table_page_with_no_sidebar();
1125
-        }
1126
-    }
1127
-
1128
-
1129
-    /**
1130
-     * @param int  $per_page
1131
-     * @param bool $count
1132
-     * @param bool $trashed
1133
-     * @return EE_Soft_Delete_Base_Class[]|int
1134
-     * @throws EE_Error
1135
-     * @throws ReflectionException
1136
-     */
1137
-    public function get_default_tickets(int $per_page = 10, bool $count = false, bool $trashed = false)
1138
-    {
1139
-        $orderby = $this->request->getRequestParam('orderby', 'TKT_name');
1140
-        $order   = $this->request->getRequestParam('order', 'ASC');
1141
-        switch ($orderby) {
1142
-            case 'TKT_name':
1143
-                $orderby = ['TKT_name' => $order];
1144
-                break;
1145
-            case 'TKT_price':
1146
-                $orderby = ['TKT_price' => $order];
1147
-                break;
1148
-            case 'TKT_uses':
1149
-                $orderby = ['TKT_uses' => $order];
1150
-                break;
1151
-            case 'TKT_min':
1152
-                $orderby = ['TKT_min' => $order];
1153
-                break;
1154
-            case 'TKT_max':
1155
-                $orderby = ['TKT_max' => $order];
1156
-                break;
1157
-            case 'TKT_qty':
1158
-                $orderby = ['TKT_qty' => $order];
1159
-                break;
1160
-        }
1161
-
1162
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
1163
-        $per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1164
-        $offset       = ($current_page - 1) * $per_page;
1165
-
1166
-        $where = [
1167
-            'TKT_is_default' => 1,
1168
-            'TKT_deleted'    => $trashed,
1169
-        ];
1170
-
1171
-        $search_term = $this->request->getRequestParam('s');
1172
-        if ($search_term) {
1173
-            $search_term = '%' . $search_term . '%';
1174
-            $where['OR'] = [
1175
-                'TKT_name'        => ['LIKE', $search_term],
1176
-                'TKT_description' => ['LIKE', $search_term],
1177
-            ];
1178
-        }
1179
-
1180
-        return $count
1181
-            ? EEM_Ticket::instance()->count_deleted_and_undeleted([$where])
1182
-            : EEM_Ticket::instance()->get_all_deleted_and_undeleted(
1183
-                [
1184
-                    $where,
1185
-                    'order_by' => $orderby,
1186
-                    'limit'    => [$offset, $per_page],
1187
-                    'group_by' => 'TKT_ID',
1188
-                ]
1189
-            );
1190
-    }
1191
-
1192
-
1193
-    /**
1194
-     * @param bool $trash
1195
-     * @throws EE_Error
1196
-     * @throws InvalidArgumentException
1197
-     * @throws InvalidDataTypeException
1198
-     * @throws InvalidInterfaceException
1199
-     * @throws ReflectionException
1200
-     */
1201
-    protected function _trash_or_restore_ticket(bool $trash = false)
1202
-    {
1203
-        $success = 1;
1204
-        $TKT     = EEM_Ticket::instance();
1205
-        // checkboxes?
1206
-        $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1207
-        if (! empty($checkboxes)) {
1208
-            // if array has more than one element then success message should be plural
1209
-            $success = count($checkboxes) > 1 ? 2 : 1;
1210
-            // cycle thru the boxes
1211
-            foreach ($checkboxes as $TKT_ID => $value) {
1212
-                if ($trash) {
1213
-                    if (! $TKT->delete_by_ID($TKT_ID)) {
1214
-                        $success = 0;
1215
-                    }
1216
-                } elseif (! $TKT->restore_by_ID($TKT_ID)) {
1217
-                    $success = 0;
1218
-                }
1219
-            }
1220
-        } else {
1221
-            // grab single id and trash
1222
-            $TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1223
-            if ($trash) {
1224
-                if (! $TKT->delete_by_ID($TKT_ID)) {
1225
-                    $success = 0;
1226
-                }
1227
-            } elseif (! $TKT->restore_by_ID($TKT_ID)) {
1228
-                $success = 0;
1229
-            }
1230
-        }
1231
-        $action_desc = $trash ? 'moved to the trash' : 'restored';
1232
-        $query_args  = [
1233
-            'action' => 'ticket_list_table',
1234
-            'status' => $trash ? '' : 'trashed',
1235
-        ];
1236
-        $this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1237
-    }
1238
-
1239
-
1240
-    /**
1241
-     * Handles trashing default ticket.
1242
-     *
1243
-     * @throws EE_Error
1244
-     * @throws ReflectionException
1245
-     */
1246
-    protected function _delete_ticket()
1247
-    {
1248
-        $success = 1;
1249
-        // checkboxes?
1250
-        $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1251
-        if (! empty($checkboxes)) {
1252
-            // if array has more than one element then success message should be plural
1253
-            $success = count($checkboxes) > 1 ? 2 : 1;
1254
-            // cycle thru the boxes
1255
-            foreach ($checkboxes as $TKT_ID => $value) {
1256
-                // delete
1257
-                if (! $this->_delete_the_ticket($TKT_ID)) {
1258
-                    $success = 0;
1259
-                }
1260
-            }
1261
-        } else {
1262
-            // grab single id and trash
1263
-            $TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1264
-            if (! $this->_delete_the_ticket($TKT_ID)) {
1265
-                $success = 0;
1266
-            }
1267
-        }
1268
-        $action_desc = 'deleted';
1269
-        $query_args  = [
1270
-            'action' => 'ticket_list_table',
1271
-            'status' => 'trashed',
1272
-        ];
1273
-        // fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1274
-        if (
1275
-        EEM_Ticket::instance()->count_deleted_and_undeleted(
1276
-            [['TKT_is_default' => 1]],
1277
-            'TKT_ID',
1278
-            true
1279
-        )
1280
-        ) {
1281
-            $query_args = [];
1282
-        }
1283
-        $this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1284
-    }
1285
-
1286
-
1287
-    /**
1288
-     * @param int $TKT_ID
1289
-     * @return bool|int
1290
-     * @throws EE_Error
1291
-     * @throws ReflectionException
1292
-     */
1293
-    protected function _delete_the_ticket(int $TKT_ID)
1294
-    {
1295
-        $ticket = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1296
-        if (! $ticket instanceof EE_Ticket) {
1297
-            return false;
1298
-        }
1299
-        $ticket->_remove_relations('Datetime');
1300
-        // delete all related prices first
1301
-        $ticket->delete_related_permanently('Price');
1302
-        return $ticket->delete_permanently();
1303
-    }
393
+		}
394
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
395
+			EE_Registry::instance()->load_helper('MSG_Template');
396
+			$action_links[] = EEH_MSG_Template::get_message_action_link(
397
+				'see_notifications_for',
398
+				null,
399
+				['EVT_ID' => $event->ID()]
400
+			);
401
+		}
402
+		return $action_links;
403
+	}
404
+
405
+
406
+	/**
407
+	 * @param $items
408
+	 * @return mixed
409
+	 */
410
+	public function additional_legend_items($items)
411
+	{
412
+		if (
413
+		EE_Registry::instance()->CAP->current_user_can(
414
+			'ee_read_registrations',
415
+			'espresso_registrations_reports'
416
+		)
417
+		) {
418
+			$items['reports'] = [
419
+				'class' => 'dashicons dashicons-chart-bar',
420
+				'desc'  => esc_html__('Event Reports', 'event_espresso'),
421
+			];
422
+		}
423
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
424
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
425
+			// $related_for_icon can sometimes be a string so 'css_class' would be an illegal offset
426
+			// (can only use numeric offsets when treating strings as arrays)
427
+			if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
428
+				$items['view_related_messages'] = [
429
+					'class' => $related_for_icon['css_class'],
430
+					'desc'  => $related_for_icon['label'],
431
+				];
432
+			}
433
+		}
434
+		return $items;
435
+	}
436
+
437
+
438
+	/**
439
+	 * This is the callback method for the duplicate event route
440
+	 * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
441
+	 * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
442
+	 * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
443
+	 * After duplication the redirect is to the new event edit page.
444
+	 *
445
+	 * @return void
446
+	 * @throws EE_Error If EE_Event is not available with given ID
447
+	 * @throws ReflectionException
448
+	 * @access protected
449
+	 */
450
+	protected function _duplicate_event()
451
+	{
452
+		// first make sure the ID for the event is in the request.
453
+		//  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
454
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
455
+		if (! $EVT_ID) {
456
+			EE_Error::add_error(
457
+				esc_html__(
458
+					'In order to duplicate an event an Event ID is required.  None was given.',
459
+					'event_espresso'
460
+				),
461
+				__FILE__,
462
+				__FUNCTION__,
463
+				__LINE__
464
+			);
465
+			$this->_redirect_after_action(false, '', '', [], true);
466
+			return;
467
+		}
468
+		// k we've got EVT_ID so let's use that to get the event we'll duplicate
469
+		$orig_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
470
+		if (! $orig_event instanceof EE_Event) {
471
+			throw new EE_Error(
472
+				sprintf(
473
+					esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
474
+					$EVT_ID
475
+				)
476
+			);
477
+		}
478
+		// k now let's clone the $orig_event before getting relations
479
+		$new_event = clone $orig_event;
480
+		// original datetimes
481
+		$orig_datetimes = $orig_event->get_many_related('Datetime');
482
+		// other original relations
483
+		$orig_ven = $orig_event->get_many_related('Venue');
484
+		// reset the ID and modify other details to make it clear this is a dupe
485
+		$new_event->set('EVT_ID', 0);
486
+		$new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
487
+		$new_event->set('EVT_name', $new_name);
488
+		$new_event->set(
489
+			'EVT_slug',
490
+			wp_unique_post_slug(
491
+				sanitize_title($orig_event->name()),
492
+				0,
493
+				'publish',
494
+				'espresso_events',
495
+				0
496
+			)
497
+		);
498
+		$new_event->set('status', 'draft');
499
+		// duplicate discussion settings
500
+		$new_event->set('comment_status', $orig_event->get('comment_status'));
501
+		$new_event->set('ping_status', $orig_event->get('ping_status'));
502
+		// save the new event
503
+		$new_event->save();
504
+		// venues
505
+		foreach ($orig_ven as $ven) {
506
+			$new_event->_add_relation_to($ven, 'Venue');
507
+		}
508
+		$new_event->save();
509
+		// now we need to get the question group relations and handle that
510
+		// first primary question groups
511
+		$orig_primary_qgs = $orig_event->get_many_related(
512
+			'Question_Group',
513
+			[['Event_Question_Group.EQG_primary' => true]]
514
+		);
515
+		if (! empty($orig_primary_qgs)) {
516
+			foreach ($orig_primary_qgs as $obj) {
517
+				if ($obj instanceof EE_Question_Group) {
518
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
519
+				}
520
+			}
521
+		}
522
+		// next additional attendee question groups
523
+		$orig_additional_qgs = $orig_event->get_many_related(
524
+			'Question_Group',
525
+			[['Event_Question_Group.EQG_additional' => true]]
526
+		);
527
+		if (! empty($orig_additional_qgs)) {
528
+			foreach ($orig_additional_qgs as $obj) {
529
+				if ($obj instanceof EE_Question_Group) {
530
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
531
+				}
532
+			}
533
+		}
534
+
535
+		$new_event->save();
536
+
537
+		// k now that we have the new event saved we can loop through the datetimes and start adding relations.
538
+		$cloned_tickets = [];
539
+		foreach ($orig_datetimes as $orig_dtt) {
540
+			if (! $orig_dtt instanceof EE_Datetime) {
541
+				continue;
542
+			}
543
+			$new_dtt      = clone $orig_dtt;
544
+			$orig_tickets = $orig_dtt->tickets();
545
+			// save new dtt then add to event
546
+			$new_dtt->set('DTT_ID', 0);
547
+			$new_dtt->set('DTT_sold', 0);
548
+			$new_dtt->set_reserved(0);
549
+			$new_dtt->save();
550
+			$new_event->_add_relation_to($new_dtt, 'Datetime');
551
+			$new_event->save();
552
+			// now let's get the ticket relations setup.
553
+			foreach ((array) $orig_tickets as $orig_ticket) {
554
+				// it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
555
+				if (! $orig_ticket instanceof EE_Ticket) {
556
+					continue;
557
+				}
558
+				// is this ticket archived?  If it is then let's skip
559
+				if ($orig_ticket->get('TKT_deleted')) {
560
+					continue;
561
+				}
562
+				// does this original ticket already exist in the clone_tickets cache?
563
+				//  If so we'll just use the new ticket from it.
564
+				if (isset($cloned_tickets[ $orig_ticket->ID() ])) {
565
+					$new_ticket = $cloned_tickets[ $orig_ticket->ID() ];
566
+				} else {
567
+					$new_ticket = clone $orig_ticket;
568
+					// get relations on the $orig_ticket that we need to setup.
569
+					$orig_prices = $orig_ticket->prices();
570
+					$new_ticket->set('TKT_ID', 0);
571
+					$new_ticket->set('TKT_sold', 0);
572
+					$new_ticket->set('TKT_reserved', 0);
573
+					$new_ticket->save(); // make sure new ticket has ID.
574
+					// price relations on new ticket need to be setup.
575
+					foreach ($orig_prices as $orig_price) {
576
+						$new_price = clone $orig_price;
577
+						$new_price->set('PRC_ID', 0);
578
+						$new_price->save();
579
+						$new_ticket->_add_relation_to($new_price, 'Price');
580
+						$new_ticket->save();
581
+					}
582
+
583
+					do_action(
584
+						'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
585
+						$orig_ticket,
586
+						$new_ticket,
587
+						$orig_prices,
588
+						$orig_event,
589
+						$orig_dtt,
590
+						$new_dtt
591
+					);
592
+				}
593
+				// k now we can add the new ticket as a relation to the new datetime
594
+				// and make sure its added to our cached $cloned_tickets array
595
+				// for use with later datetimes that have the same ticket.
596
+				$new_dtt->_add_relation_to($new_ticket, 'Ticket');
597
+				$new_dtt->save();
598
+				$cloned_tickets[ $orig_ticket->ID() ] = $new_ticket;
599
+			}
600
+		}
601
+		// clone taxonomy information
602
+		$taxonomies_to_clone_with = apply_filters(
603
+			'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
604
+			['espresso_event_categories', 'espresso_event_type', 'post_tag']
605
+		);
606
+		// get terms for original event (notice)
607
+		$orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
608
+		// loop through terms and add them to new event.
609
+		foreach ($orig_terms as $term) {
610
+			wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
611
+		}
612
+
613
+		// duplicate other core WP_Post items for this event.
614
+		// post thumbnail (feature image).
615
+		$feature_image_id = get_post_thumbnail_id($orig_event->ID());
616
+		if ($feature_image_id) {
617
+			update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
618
+		}
619
+
620
+		// duplicate page_template setting
621
+		$page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
622
+		if ($page_template) {
623
+			update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
624
+		}
625
+
626
+		do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
627
+		// now let's redirect to the edit page for this duplicated event if we have a new event id.
628
+		if ($new_event->ID()) {
629
+			$redirect_args = [
630
+				'post'   => $new_event->ID(),
631
+				'action' => 'edit',
632
+			];
633
+			EE_Error::add_success(
634
+				esc_html__(
635
+					'Event successfully duplicated.  Please review the details below and make any necessary edits',
636
+					'event_espresso'
637
+				)
638
+			);
639
+		} else {
640
+			$redirect_args = [
641
+				'action' => 'default',
642
+			];
643
+			EE_Error::add_error(
644
+				esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
645
+				__FILE__,
646
+				__FUNCTION__,
647
+				__LINE__
648
+			);
649
+		}
650
+		$this->_redirect_after_action(false, '', '', $redirect_args, true);
651
+	}
652
+
653
+
654
+	/**
655
+	 * Generates output for the import page.
656
+	 *
657
+	 * @throws EE_Error
658
+	 */
659
+	protected function _import_page()
660
+	{
661
+		$title = esc_html__('Import', 'event_espresso');
662
+		$intro = esc_html__(
663
+			'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
664
+			'event_espresso'
665
+		);
666
+
667
+		$form_url = EVENTS_ADMIN_URL;
668
+		$action   = 'import_events';
669
+		$type     = 'csv';
670
+
671
+		$this->_template_args['form'] = EE_Import::instance()->upload_form(
672
+			$title,
673
+			$intro,
674
+			$form_url,
675
+			$action,
676
+			$type
677
+		);
678
+
679
+		$this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
680
+			['action' => 'sample_export_file'],
681
+			$this->_admin_base_url
682
+		);
683
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
684
+			EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
685
+			$this->_template_args,
686
+			true
687
+		);
688
+		$this->display_admin_page_with_sidebar();
689
+	}
690
+
691
+
692
+	/**
693
+	 * _import_events
694
+	 * This handles displaying the screen and running imports for importing events.
695
+	 *
696
+	 * @return void
697
+	 * @throws EE_Error
698
+	 */
699
+	protected function _import_events()
700
+	{
701
+		require_once(EE_CLASSES . 'EE_Import.class.php');
702
+		$success = EE_Import::instance()->import();
703
+		$this->_redirect_after_action(
704
+			$success,
705
+			esc_html__('Import File', 'event_espresso'),
706
+			'ran',
707
+			['action' => 'import_page'],
708
+			true
709
+		);
710
+	}
711
+
712
+
713
+	/**
714
+	 * _events_export
715
+	 * Will export all (or just the given event) to a Excel compatible file.
716
+	 *
717
+	 * @access protected
718
+	 * @return void
719
+	 */
720
+	protected function _events_export()
721
+	{
722
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
723
+		$EVT_ID = $this->request->getRequestParam('EVT_IDs', $EVT_ID, 'int');
724
+		$this->request->mergeRequestParams(
725
+			[
726
+				'export' => 'report',
727
+				'action' => 'all_event_data',
728
+				'EVT_ID' => $EVT_ID,
729
+			]
730
+		);
731
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
732
+			require_once(EE_CLASSES . 'EE_Export.class.php');
733
+			$EE_Export = EE_Export::instance($this->request->requestParams());
734
+			$EE_Export->export();
735
+		}
736
+	}
737
+
738
+
739
+	/**
740
+	 * handle category exports()
741
+	 *
742
+	 * @return void
743
+	 */
744
+	protected function _categories_export()
745
+	{
746
+		$EVT_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
747
+		$this->request->mergeRequestParams(
748
+			[
749
+				'export' => 'report',
750
+				'action' => 'categories',
751
+				'EVT_ID' => $EVT_ID,
752
+			]
753
+		);
754
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
755
+			require_once(EE_CLASSES . 'EE_Export.class.php');
756
+			$EE_Export = EE_Export::instance($this->request->requestParams());
757
+			$EE_Export->export();
758
+		}
759
+	}
760
+
761
+
762
+	/**
763
+	 * Creates a sample CSV file for importing
764
+	 */
765
+	protected function _sample_export_file()
766
+	{
767
+		$EE_Export = EE_Export::instance();
768
+		if ($EE_Export instanceof EE_Export) {
769
+			$EE_Export->export();
770
+		}
771
+	}
772
+
773
+
774
+	/*************        Template Settings        *************/
775
+	/**
776
+	 * Generates template settings page output
777
+	 *
778
+	 * @throws DomainException
779
+	 * @throws EE_Error
780
+	 * @throws InvalidArgumentException
781
+	 * @throws InvalidDataTypeException
782
+	 * @throws InvalidInterfaceException
783
+	 */
784
+	protected function _template_settings()
785
+	{
786
+		$this->_template_args['values'] = $this->_yes_no_values;
787
+		/**
788
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
789
+		 * from General_Settings_Admin_Page to here.
790
+		 */
791
+		$this->_template_args = apply_filters(
792
+			'FHEE__General_Settings_Admin_Page__template_settings__template_args',
793
+			$this->_template_args
794
+		);
795
+		$this->_set_add_edit_form_tags('update_template_settings');
796
+		$this->_set_publish_post_box_vars();
797
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
798
+			EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
799
+			$this->_template_args,
800
+			true
801
+		);
802
+		$this->display_admin_page_with_sidebar();
803
+	}
804
+
805
+
806
+	/**
807
+	 * Handler for updating template settings.
808
+	 *
809
+	 * @throws EE_Error
810
+	 */
811
+	protected function _update_template_settings()
812
+	{
813
+		/**
814
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
815
+		 * from General_Settings_Admin_Page to here.
816
+		 */
817
+		EE_Registry::instance()->CFG->template_settings = apply_filters(
818
+			'FHEE__General_Settings_Admin_Page__update_template_settings__data',
819
+			EE_Registry::instance()->CFG->template_settings,
820
+			$this->request->requestParams()
821
+		);
822
+		// update custom post type slugs and detect if we need to flush rewrite rules
823
+		$old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
824
+
825
+		$event_cpt_slug = $this->request->getRequestParam('event_cpt_slug');
826
+
827
+		EE_Registry::instance()->CFG->core->event_cpt_slug = $event_cpt_slug
828
+			? EEH_URL::slugify($event_cpt_slug, 'events')
829
+			: EE_Registry::instance()->CFG->core->event_cpt_slug;
830
+
831
+		$what    = esc_html__('Template Settings', 'event_espresso');
832
+		$success = $this->_update_espresso_configuration(
833
+			$what,
834
+			EE_Registry::instance()->CFG->template_settings,
835
+			__FILE__,
836
+			__FUNCTION__,
837
+			__LINE__
838
+		);
839
+		if (EE_Registry::instance()->CFG->core->event_cpt_slug !== $old_slug) {
840
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
841
+			$rewrite_rules = LoaderFactory::getLoader()->getShared(
842
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
843
+			);
844
+			$rewrite_rules->flush();
845
+		}
846
+		$this->_redirect_after_action($success, $what, 'updated', ['action' => 'template_settings']);
847
+	}
848
+
849
+
850
+	/**
851
+	 * _premium_event_editor_meta_boxes
852
+	 * add all metaboxes related to the event_editor
853
+	 *
854
+	 * @access protected
855
+	 * @return void
856
+	 * @throws EE_Error
857
+	 * @throws ReflectionException
858
+	 */
859
+	protected function _premium_event_editor_meta_boxes()
860
+	{
861
+		$this->verify_cpt_object();
862
+		// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
863
+		if (
864
+			! $this->admin_config->useAdvancedEditor()
865
+			|| ! $this->feature->allowed('use_reg_options_meta_box')
866
+		) {
867
+			$this->addMetaBox(
868
+				'espresso_event_editor_event_options',
869
+				esc_html__('Event Registration Options', 'event_espresso'),
870
+				[$this, 'registration_options_meta_box'],
871
+				$this->page_slug,
872
+				'side',
873
+				'core'
874
+			);
875
+		}
876
+	}
877
+
878
+
879
+	/**
880
+	 * override caf metabox
881
+	 *
882
+	 * @return void
883
+	 * @throws EE_Error
884
+	 * @throws ReflectionException
885
+	 */
886
+	public function registration_options_meta_box()
887
+	{
888
+		$yes_no_values = [
889
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
890
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
891
+		];
892
+
893
+		$default_reg_status_values = EEM_Registration::reg_status_array(
894
+			[
895
+				EEM_Registration::status_id_cancelled,
896
+				EEM_Registration::status_id_declined,
897
+				EEM_Registration::status_id_incomplete,
898
+				EEM_Registration::status_id_wait_list,
899
+			],
900
+			true
901
+		);
902
+
903
+		$template_args['active_status']    = $this->_cpt_model_obj->pretty_active_status(false);
904
+		$template_args['_event']           = $this->_cpt_model_obj;
905
+		$template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
906
+
907
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
908
+			'default_reg_status',
909
+			$default_reg_status_values,
910
+			$this->_cpt_model_obj->default_registration_status()
911
+		);
912
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
913
+			'display_desc',
914
+			$yes_no_values,
915
+			$this->_cpt_model_obj->display_description()
916
+		);
917
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
918
+			'display_ticket_selector',
919
+			$yes_no_values,
920
+			$this->_cpt_model_obj->display_ticket_selector(),
921
+			'',
922
+			'',
923
+			false
924
+		);
925
+		$template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
926
+			'EVT_default_registration_status',
927
+			$default_reg_status_values,
928
+			$this->_cpt_model_obj->default_registration_status()
929
+		);
930
+		$template_args['additional_registration_options'] = apply_filters(
931
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
932
+			'',
933
+			$template_args,
934
+			$yes_no_values,
935
+			$default_reg_status_values
936
+		);
937
+		EEH_Template::display_template(
938
+			EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
939
+			$template_args
940
+		);
941
+	}
942
+
943
+
944
+
945
+	/**
946
+	 * wp_list_table_mods for caf
947
+	 * ============================
948
+	 */
949
+
950
+
951
+	/**
952
+	 * espresso_event_months_dropdown
953
+	 *
954
+	 * @deprecatd $VID:$
955
+	 * @access public
956
+	 * @return string                dropdown listing month/year selections for events.
957
+	 * @throws EE_Error
958
+	 */
959
+	public function espresso_event_months_dropdown(): string
960
+	{
961
+		// what we need to do is get all PRIMARY datetimes for all events to filter on.
962
+		// Note we need to include any other filters that are set!
963
+		return EEH_Form_Fields::generate_event_months_dropdown(
964
+			$this->request->getRequestParam('month_range'),
965
+			$this->request->getRequestParam('status'),
966
+			$this->request->getRequestParam('EVT_CAT', 0, 'int'),
967
+			$this->request->getRequestParam('active_status')
968
+		);
969
+	}
970
+
971
+
972
+	/**
973
+	 * returns a list of "active" statuses on the event
974
+	 *
975
+	 * @deprecatd $VID:$
976
+	 * @param string $current_value whatever the current active status is
977
+	 * @return string
978
+	 */
979
+	public function active_status_dropdown(string $current_value = ''): string
980
+	{
981
+		$select_name = 'active_status';
982
+		$values      = [
983
+			'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
984
+			'active'   => esc_html__('Active', 'event_espresso'),
985
+			'upcoming' => esc_html__('Upcoming', 'event_espresso'),
986
+			'expired'  => esc_html__('Expired', 'event_espresso'),
987
+			'inactive' => esc_html__('Inactive', 'event_espresso'),
988
+		];
989
+
990
+		return EEH_Form_Fields::select_input($select_name, $values, $current_value);
991
+	}
992
+
993
+
994
+	/**
995
+	 * returns a list of "venues"
996
+	 *
997
+	 * @deprecatd $VID:$
998
+	 * @param string $current_value whatever the current active status is
999
+	 * @return string
1000
+	 * @throws EE_Error
1001
+	 * @throws ReflectionException
1002
+	 */
1003
+	protected function venuesDropdown(string $current_value = ''): string
1004
+	{
1005
+		$values = ['' => esc_html__('All Venues', 'event_espresso')];
1006
+		// populate the list of venues.
1007
+		$venues = EEM_Venue::instance()->get_all(['order_by' => ['VNU_name' => 'ASC']]);
1008
+
1009
+		foreach ($venues as $venue) {
1010
+			$values[ $venue->ID() ] = $venue->name();
1011
+		}
1012
+
1013
+		return EEH_Form_Fields::select_input('venue', $values, $current_value);
1014
+	}
1015
+
1016
+
1017
+	/**
1018
+	 * output a dropdown of the categories for the category filter on the event admin list table
1019
+	 *
1020
+	 * @deprecatd $VID:$
1021
+	 * @access  public
1022
+	 * @return string html
1023
+	 * @throws EE_Error
1024
+	 * @throws ReflectionException
1025
+	 */
1026
+	public function category_dropdown(): string
1027
+	{
1028
+		return EEH_Form_Fields::generate_event_category_dropdown(
1029
+			$this->request->getRequestParam('EVT_CAT', -1, 'int')
1030
+		);
1031
+	}
1032
+
1033
+
1034
+	/**
1035
+	 * get total number of events today
1036
+	 *
1037
+	 * @access public
1038
+	 * @return int
1039
+	 * @throws EE_Error
1040
+	 * @throws InvalidArgumentException
1041
+	 * @throws InvalidDataTypeException
1042
+	 * @throws InvalidInterfaceException
1043
+	 * @throws ReflectionException
1044
+	 */
1045
+	public function total_events_today(): int
1046
+	{
1047
+		$start = EEM_Datetime::instance()->convert_datetime_for_query(
1048
+			'DTT_EVT_start',
1049
+			date('Y-m-d') . ' 00:00:00',
1050
+			'Y-m-d H:i:s',
1051
+			'UTC'
1052
+		);
1053
+		$end   = EEM_Datetime::instance()->convert_datetime_for_query(
1054
+			'DTT_EVT_start',
1055
+			date('Y-m-d') . ' 23:59:59',
1056
+			'Y-m-d H:i:s',
1057
+			'UTC'
1058
+		);
1059
+		$where = [
1060
+			'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1061
+		];
1062
+		return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1063
+	}
1064
+
1065
+
1066
+	/**
1067
+	 * get total number of events this month
1068
+	 *
1069
+	 * @access public
1070
+	 * @return int
1071
+	 * @throws EE_Error
1072
+	 * @throws InvalidArgumentException
1073
+	 * @throws InvalidDataTypeException
1074
+	 * @throws InvalidInterfaceException
1075
+	 * @throws ReflectionException
1076
+	 */
1077
+	public function total_events_this_month(): int
1078
+	{
1079
+		// Dates
1080
+		$this_year_r     = date('Y');
1081
+		$this_month_r    = date('m');
1082
+		$days_this_month = date('t');
1083
+		$start           = EEM_Datetime::instance()->convert_datetime_for_query(
1084
+			'DTT_EVT_start',
1085
+			$this_year_r . '-' . $this_month_r . '-01 00:00:00',
1086
+			'Y-m-d H:i:s',
1087
+			'UTC'
1088
+		);
1089
+		$end             = EEM_Datetime::instance()->convert_datetime_for_query(
1090
+			'DTT_EVT_start',
1091
+			$this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1092
+			'Y-m-d H:i:s',
1093
+			'UTC'
1094
+		);
1095
+		$where           = [
1096
+			'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1097
+		];
1098
+		return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1099
+	}
1100
+
1101
+
1102
+	/** DEFAULT TICKETS STUFF **/
1103
+
1104
+	/**
1105
+	 * Output default tickets list table view.
1106
+	 *
1107
+	 * @throws EE_Error
1108
+	 */
1109
+	public function _tickets_overview_list_table()
1110
+	{
1111
+		if (
1112
+			$this->admin_config->useAdvancedEditor()
1113
+			&& $this->feature->allowed('use_default_ticket_manager')
1114
+		) {
1115
+			// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1116
+			$this->_template_args['admin_page_content'] = EEH_Template::display_template(
1117
+				EVENTS_CAF_TEMPLATE_PATH . 'default_tickets_moved_notice.template.php',
1118
+				[],
1119
+				true
1120
+			);
1121
+			$this->display_admin_page_with_no_sidebar();
1122
+		} else {
1123
+			$this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1124
+			$this->display_admin_list_table_page_with_no_sidebar();
1125
+		}
1126
+	}
1127
+
1128
+
1129
+	/**
1130
+	 * @param int  $per_page
1131
+	 * @param bool $count
1132
+	 * @param bool $trashed
1133
+	 * @return EE_Soft_Delete_Base_Class[]|int
1134
+	 * @throws EE_Error
1135
+	 * @throws ReflectionException
1136
+	 */
1137
+	public function get_default_tickets(int $per_page = 10, bool $count = false, bool $trashed = false)
1138
+	{
1139
+		$orderby = $this->request->getRequestParam('orderby', 'TKT_name');
1140
+		$order   = $this->request->getRequestParam('order', 'ASC');
1141
+		switch ($orderby) {
1142
+			case 'TKT_name':
1143
+				$orderby = ['TKT_name' => $order];
1144
+				break;
1145
+			case 'TKT_price':
1146
+				$orderby = ['TKT_price' => $order];
1147
+				break;
1148
+			case 'TKT_uses':
1149
+				$orderby = ['TKT_uses' => $order];
1150
+				break;
1151
+			case 'TKT_min':
1152
+				$orderby = ['TKT_min' => $order];
1153
+				break;
1154
+			case 'TKT_max':
1155
+				$orderby = ['TKT_max' => $order];
1156
+				break;
1157
+			case 'TKT_qty':
1158
+				$orderby = ['TKT_qty' => $order];
1159
+				break;
1160
+		}
1161
+
1162
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
1163
+		$per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1164
+		$offset       = ($current_page - 1) * $per_page;
1165
+
1166
+		$where = [
1167
+			'TKT_is_default' => 1,
1168
+			'TKT_deleted'    => $trashed,
1169
+		];
1170
+
1171
+		$search_term = $this->request->getRequestParam('s');
1172
+		if ($search_term) {
1173
+			$search_term = '%' . $search_term . '%';
1174
+			$where['OR'] = [
1175
+				'TKT_name'        => ['LIKE', $search_term],
1176
+				'TKT_description' => ['LIKE', $search_term],
1177
+			];
1178
+		}
1179
+
1180
+		return $count
1181
+			? EEM_Ticket::instance()->count_deleted_and_undeleted([$where])
1182
+			: EEM_Ticket::instance()->get_all_deleted_and_undeleted(
1183
+				[
1184
+					$where,
1185
+					'order_by' => $orderby,
1186
+					'limit'    => [$offset, $per_page],
1187
+					'group_by' => 'TKT_ID',
1188
+				]
1189
+			);
1190
+	}
1191
+
1192
+
1193
+	/**
1194
+	 * @param bool $trash
1195
+	 * @throws EE_Error
1196
+	 * @throws InvalidArgumentException
1197
+	 * @throws InvalidDataTypeException
1198
+	 * @throws InvalidInterfaceException
1199
+	 * @throws ReflectionException
1200
+	 */
1201
+	protected function _trash_or_restore_ticket(bool $trash = false)
1202
+	{
1203
+		$success = 1;
1204
+		$TKT     = EEM_Ticket::instance();
1205
+		// checkboxes?
1206
+		$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1207
+		if (! empty($checkboxes)) {
1208
+			// if array has more than one element then success message should be plural
1209
+			$success = count($checkboxes) > 1 ? 2 : 1;
1210
+			// cycle thru the boxes
1211
+			foreach ($checkboxes as $TKT_ID => $value) {
1212
+				if ($trash) {
1213
+					if (! $TKT->delete_by_ID($TKT_ID)) {
1214
+						$success = 0;
1215
+					}
1216
+				} elseif (! $TKT->restore_by_ID($TKT_ID)) {
1217
+					$success = 0;
1218
+				}
1219
+			}
1220
+		} else {
1221
+			// grab single id and trash
1222
+			$TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1223
+			if ($trash) {
1224
+				if (! $TKT->delete_by_ID($TKT_ID)) {
1225
+					$success = 0;
1226
+				}
1227
+			} elseif (! $TKT->restore_by_ID($TKT_ID)) {
1228
+				$success = 0;
1229
+			}
1230
+		}
1231
+		$action_desc = $trash ? 'moved to the trash' : 'restored';
1232
+		$query_args  = [
1233
+			'action' => 'ticket_list_table',
1234
+			'status' => $trash ? '' : 'trashed',
1235
+		];
1236
+		$this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1237
+	}
1238
+
1239
+
1240
+	/**
1241
+	 * Handles trashing default ticket.
1242
+	 *
1243
+	 * @throws EE_Error
1244
+	 * @throws ReflectionException
1245
+	 */
1246
+	protected function _delete_ticket()
1247
+	{
1248
+		$success = 1;
1249
+		// checkboxes?
1250
+		$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1251
+		if (! empty($checkboxes)) {
1252
+			// if array has more than one element then success message should be plural
1253
+			$success = count($checkboxes) > 1 ? 2 : 1;
1254
+			// cycle thru the boxes
1255
+			foreach ($checkboxes as $TKT_ID => $value) {
1256
+				// delete
1257
+				if (! $this->_delete_the_ticket($TKT_ID)) {
1258
+					$success = 0;
1259
+				}
1260
+			}
1261
+		} else {
1262
+			// grab single id and trash
1263
+			$TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1264
+			if (! $this->_delete_the_ticket($TKT_ID)) {
1265
+				$success = 0;
1266
+			}
1267
+		}
1268
+		$action_desc = 'deleted';
1269
+		$query_args  = [
1270
+			'action' => 'ticket_list_table',
1271
+			'status' => 'trashed',
1272
+		];
1273
+		// fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1274
+		if (
1275
+		EEM_Ticket::instance()->count_deleted_and_undeleted(
1276
+			[['TKT_is_default' => 1]],
1277
+			'TKT_ID',
1278
+			true
1279
+		)
1280
+		) {
1281
+			$query_args = [];
1282
+		}
1283
+		$this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1284
+	}
1285
+
1286
+
1287
+	/**
1288
+	 * @param int $TKT_ID
1289
+	 * @return bool|int
1290
+	 * @throws EE_Error
1291
+	 * @throws ReflectionException
1292
+	 */
1293
+	protected function _delete_the_ticket(int $TKT_ID)
1294
+	{
1295
+		$ticket = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1296
+		if (! $ticket instanceof EE_Ticket) {
1297
+			return false;
1298
+		}
1299
+		$ticket->_remove_relations('Datetime');
1300
+		// delete all related prices first
1301
+		$ticket->delete_related_permanently('Price');
1302
+		return $ticket->delete_permanently();
1303
+	}
1304 1304
 }
Please login to merge, or discard this patch.