Completed
Branch BUG-10851-events-shortcode (1f397b)
by
unknown
11:46 queued 10s
created
core/libraries/form_sections/form_handlers/FormHandler.php 2 patches
Indentation   +637 added lines, -637 removed lines patch added patch discarded remove patch
@@ -15,7 +15,7 @@  discard block
 block discarded – undo
15 15
 use EventEspresso\core\exceptions\InvalidFormSubmissionException;
16 16
 
17 17
 if (! defined('EVENT_ESPRESSO_VERSION')) {
18
-    exit('No direct script access allowed');
18
+	exit('No direct script access allowed');
19 19
 }
20 20
 
21 21
 
@@ -34,642 +34,642 @@  discard block
 block discarded – undo
34 34
 abstract class FormHandler implements FormHandlerInterface
35 35
 {
36 36
 
37
-    /**
38
-     * will add opening and closing HTML form tags as well as a submit button
39
-     */
40
-    const ADD_FORM_TAGS_AND_SUBMIT = 'add_form_tags_and_submit';
41
-
42
-    /**
43
-     * will add opening and closing HTML form tags but NOT a submit button
44
-     */
45
-    const ADD_FORM_TAGS_ONLY = 'add_form_tags_only';
46
-
47
-    /**
48
-     * will NOT add opening and closing HTML form tags but will add a submit button
49
-     */
50
-    const ADD_FORM_SUBMIT_ONLY = 'add_form_submit_only';
51
-
52
-    /**
53
-     * will NOT add opening and closing HTML form tags NOR a submit button
54
-     */
55
-    const DO_NOT_SETUP_FORM = 'do_not_setup_form';
56
-
57
-    /**
58
-     * if set to false, then this form has no displayable content,
59
-     * and will only be used for processing data sent passed via GET or POST
60
-     * defaults to true ( ie: form has displayable content )
61
-     *
62
-     * @var boolean $displayable
63
-     */
64
-    private $displayable = true;
65
-
66
-    /**
67
-     * @var string $form_name
68
-     */
69
-    private $form_name;
70
-
71
-    /**
72
-     * @var string $admin_name
73
-     */
74
-    private $admin_name;
75
-
76
-    /**
77
-     * @var string $slug
78
-     */
79
-    private $slug;
80
-
81
-    /**
82
-     * @var string $submit_btn_text
83
-     */
84
-    private $submit_btn_text;
85
-
86
-    /**
87
-     * @var string $form_action
88
-     */
89
-    private $form_action;
90
-
91
-    /**
92
-     * form params in key value pairs
93
-     * can be added to form action URL or as hidden inputs
94
-     *
95
-     * @var array $form_args
96
-     */
97
-    private $form_args = array();
98
-
99
-    /**
100
-     * value of one of the string constant above
101
-     *
102
-     * @var string $form_config
103
-     */
104
-    private $form_config;
105
-
106
-    /**
107
-     * whether or not the form was determined to be invalid
108
-     *
109
-     * @var boolean $form_has_errors
110
-     */
111
-    private $form_has_errors;
112
-
113
-    /**
114
-     * the absolute top level form section being used on the page
115
-     *
116
-     * @var EE_Form_Section_Proper $form
117
-     */
118
-    private $form;
119
-
120
-    /**
121
-     * @var EE_Registry $registry
122
-     */
123
-    protected $registry;
124
-
125
-
126
-
127
-    /**
128
-     * Form constructor.
129
-     *
130
-     * @param string      $form_name
131
-     * @param string      $admin_name
132
-     * @param string      $slug
133
-     * @param string      $form_action
134
-     * @param string      $form_config
135
-     * @param EE_Registry $registry
136
-     * @throws InvalidDataTypeException
137
-     * @throws DomainException
138
-     * @throws InvalidArgumentException
139
-     */
140
-    public function __construct(
141
-        $form_name,
142
-        $admin_name,
143
-        $slug,
144
-        $form_action = '',
145
-        $form_config = FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
146
-        EE_Registry $registry
147
-    ) {
148
-        $this->setFormName($form_name);
149
-        $this->setAdminName($admin_name);
150
-        $this->setSlug($slug);
151
-        $this->setFormAction($form_action);
152
-        $this->setFormConfig($form_config);
153
-        $this->setSubmitBtnText(esc_html__('Submit', 'event_espresso'));
154
-        $this->registry = $registry;
155
-    }
156
-
157
-
158
-
159
-    /**
160
-     * @return array
161
-     */
162
-    public static function getFormConfigConstants()
163
-    {
164
-        return array(
165
-            FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
166
-            FormHandler::ADD_FORM_TAGS_ONLY,
167
-            FormHandler::ADD_FORM_SUBMIT_ONLY,
168
-            FormHandler::DO_NOT_SETUP_FORM,
169
-        );
170
-    }
171
-
172
-
173
-
174
-    /**
175
-     * @param bool $for_display
176
-     * @return EE_Form_Section_Proper
177
-     * @throws EE_Error
178
-     * @throws LogicException
179
-     */
180
-    public function form($for_display = false)
181
-    {
182
-        if (! $this->formIsValid()) {
183
-            return null;
184
-        }
185
-        if ($for_display) {
186
-            $form_config = $this->formConfig();
187
-            if (
188
-                $form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
189
-                || $form_config === FormHandler::ADD_FORM_SUBMIT_ONLY
190
-            ) {
191
-                $this->appendSubmitButton();
192
-                $this->clearFormButtonFloats();
193
-            }
194
-        }
195
-        return $this->form;
196
-    }
197
-
198
-
199
-
200
-    /**
201
-     * @return boolean
202
-     * @throws LogicException
203
-     */
204
-    public function formIsValid()
205
-    {
206
-        if (! $this->form instanceof EE_Form_Section_Proper) {
207
-            static $generated = false;
208
-            if (! $generated) {
209
-                $generated = true;
210
-                $form = apply_filters(
211
-                    'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__formIsValid__generated_form_object',
212
-                    $this->generate(),
213
-                    $this
214
-                );
215
-                if ($form instanceof EE_Form_Section_Proper) {
216
-                    $this->setForm($form);
217
-                }
218
-            }
219
-            return $this->verifyForm();
220
-        }
221
-        return true;
222
-    }
223
-
224
-
225
-
226
-    /**
227
-     * @return boolean
228
-     * @throws LogicException
229
-     */
230
-    public function verifyForm()
231
-    {
232
-        if ($this->form instanceof EE_Form_Section_Proper) {
233
-            return true;
234
-        }
235
-        throw new LogicException(
236
-            sprintf(
237
-                esc_html__('The "%1$s" form is invalid or missing', 'event_espresso'),
238
-                $this->form_name
239
-            )
240
-        );
241
-    }
242
-
243
-
244
-
245
-    /**
246
-     * @param EE_Form_Section_Proper $form
247
-     */
248
-    public function setForm(EE_Form_Section_Proper $form)
249
-    {
250
-        $this->form = $form;
251
-    }
252
-
253
-
254
-
255
-    /**
256
-     * @return boolean
257
-     */
258
-    public function displayable()
259
-    {
260
-        return $this->displayable;
261
-    }
262
-
263
-
264
-
265
-    /**
266
-     * @param boolean $displayable
267
-     */
268
-    public function setDisplayable($displayable = false)
269
-    {
270
-        $this->displayable = filter_var($displayable, FILTER_VALIDATE_BOOLEAN);
271
-    }
272
-
273
-
274
-
275
-    /**
276
-     * a public name for the form that can be displayed on the frontend of a site
277
-     *
278
-     * @return string
279
-     */
280
-    public function formName()
281
-    {
282
-        return $this->form_name;
283
-    }
284
-
285
-
286
-
287
-    /**
288
-     * @param string $form_name
289
-     * @throws InvalidDataTypeException
290
-     */
291
-    public function setFormName($form_name)
292
-    {
293
-        if (! is_string($form_name)) {
294
-            throw new InvalidDataTypeException('$form_name', $form_name, 'string');
295
-        }
296
-        $this->form_name = $form_name;
297
-    }
298
-
299
-
300
-
301
-    /**
302
-     * a public name for the form that can be displayed, but only in the admin
303
-     *
304
-     * @return string
305
-     */
306
-    public function adminName()
307
-    {
308
-        return $this->admin_name;
309
-    }
310
-
311
-
312
-
313
-    /**
314
-     * @param string $admin_name
315
-     * @throws InvalidDataTypeException
316
-     */
317
-    public function setAdminName($admin_name)
318
-    {
319
-        if (! is_string($admin_name)) {
320
-            throw new InvalidDataTypeException('$admin_name', $admin_name, 'string');
321
-        }
322
-        $this->admin_name = $admin_name;
323
-    }
324
-
325
-
326
-
327
-    /**
328
-     * a URL friendly string that can be used for identifying the form
329
-     *
330
-     * @return string
331
-     */
332
-    public function slug()
333
-    {
334
-        return $this->slug;
335
-    }
336
-
337
-
338
-
339
-    /**
340
-     * @param string $slug
341
-     * @throws InvalidDataTypeException
342
-     */
343
-    public function setSlug($slug)
344
-    {
345
-        if (! is_string($slug)) {
346
-            throw new InvalidDataTypeException('$slug', $slug, 'string');
347
-        }
348
-        $this->slug = $slug;
349
-    }
350
-
351
-
352
-
353
-    /**
354
-     * @return string
355
-     */
356
-    public function submitBtnText()
357
-    {
358
-        return $this->submit_btn_text;
359
-    }
360
-
361
-
362
-
363
-    /**
364
-     * @param string $submit_btn_text
365
-     * @throws InvalidDataTypeException
366
-     * @throws InvalidArgumentException
367
-     */
368
-    public function setSubmitBtnText($submit_btn_text)
369
-    {
370
-        if (! is_string($submit_btn_text)) {
371
-            throw new InvalidDataTypeException('$submit_btn_text', $submit_btn_text, 'string');
372
-        }
373
-        if (empty($submit_btn_text)) {
374
-            throw new InvalidArgumentException(
375
-                esc_html__('Can not set Submit button text because an empty string was provided.', 'event_espresso')
376
-            );
377
-        }
378
-        $this->submit_btn_text = $submit_btn_text;
379
-    }
380
-
381
-
382
-
383
-    /**
384
-     * @return string
385
-     */
386
-    public function formAction()
387
-    {
388
-        return ! empty($this->form_args)
389
-            ? add_query_arg($this->form_args, $this->form_action)
390
-            : $this->form_action;
391
-    }
392
-
393
-
394
-
395
-    /**
396
-     * @param string $form_action
397
-     * @throws InvalidDataTypeException
398
-     */
399
-    public function setFormAction($form_action)
400
-    {
401
-        if (! is_string($form_action)) {
402
-            throw new InvalidDataTypeException('$form_action', $form_action, 'string');
403
-        }
404
-        $this->form_action = $form_action;
405
-    }
406
-
407
-
408
-
409
-    /**
410
-     * @param array $form_args
411
-     * @throws InvalidDataTypeException
412
-     * @throws InvalidArgumentException
413
-     */
414
-    public function addFormActionArgs($form_args = array())
415
-    {
416
-        if (is_object($form_args)) {
417
-            throw new InvalidDataTypeException(
418
-                '$form_args',
419
-                $form_args,
420
-                'anything other than an object was expected.'
421
-            );
422
-        }
423
-        if (empty($form_args)) {
424
-            throw new InvalidArgumentException(
425
-                esc_html__('The redirect arguments can not be an empty array.', 'event_espresso')
426
-            );
427
-        }
428
-        $this->form_args = array_merge($this->form_args, $form_args);
429
-    }
430
-
431
-
432
-
433
-    /**
434
-     * @return string
435
-     */
436
-    public function formConfig()
437
-    {
438
-        return $this->form_config;
439
-    }
440
-
441
-
442
-
443
-    /**
444
-     * @param string $form_config
445
-     * @throws DomainException
446
-     */
447
-    public function setFormConfig($form_config)
448
-    {
449
-        if (
450
-        ! in_array(
451
-            $form_config,
452
-            array(
453
-                FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
454
-                FormHandler::ADD_FORM_TAGS_ONLY,
455
-                FormHandler::ADD_FORM_SUBMIT_ONLY,
456
-                FormHandler::DO_NOT_SETUP_FORM,
457
-            ),
458
-            true
459
-        )
460
-        ) {
461
-            throw new DomainException(
462
-                sprintf(
463
-                    esc_html__('"%1$s" is not a valid value for the form config. Please use one of the class constants on \EventEspresso\core\libraries\form_sections\form_handlers\Form',
464
-                        'event_espresso'),
465
-                    $form_config
466
-                )
467
-            );
468
-        }
469
-        $this->form_config = $form_config;
470
-    }
471
-
472
-
473
-
474
-    /**
475
-     * called after the form is instantiated
476
-     * and used for performing any logic that needs to occur early
477
-     * before any of the other methods are called.
478
-     * returns true if everything is ok to proceed,
479
-     * and false if no further form logic should be implemented
480
-     *
481
-     * @return boolean
482
-     */
483
-    public function initialize()
484
-    {
485
-        $this->form_has_errors = EE_Error::has_error(true);
486
-        return true;
487
-    }
488
-
489
-
490
-
491
-    /**
492
-     * used for setting up css and js
493
-     *
494
-     * @return void
495
-     * @throws LogicException
496
-     * @throws EE_Error
497
-     */
498
-    public function enqueueStylesAndScripts()
499
-    {
500
-        $this->form(false)->enqueue_js();
501
-    }
502
-
503
-
504
-
505
-    /**
506
-     * creates and returns the actual form
507
-     *
508
-     * @return EE_Form_Section_Proper
509
-     */
510
-    abstract public function generate();
511
-
512
-
513
-
514
-    /**
515
-     * creates and returns an EE_Submit_Input labeled "Submit"
516
-     *
517
-     * @param string $text
518
-     * @return EE_Submit_Input
519
-     */
520
-    public function generateSubmitButton($text = '')
521
-    {
522
-        $text = ! empty($text) ? $text : $this->submitBtnText();
523
-        return new EE_Submit_Input(
524
-            array(
525
-                'html_name'             => 'ee-form-submit-' . $this->slug(),
526
-                'html_id'               => 'ee-form-submit-' . $this->slug(),
527
-                'html_class'            => 'ee-form-submit',
528
-                'html_label'            => ' ',
529
-                'other_html_attributes' => ' rel="' . $this->slug() . '"',
530
-                'default'               => $text,
531
-            )
532
-        );
533
-    }
534
-
535
-
536
-
537
-    /**
538
-     * calls generateSubmitButton() and appends it onto the form along with a float clearing div
539
-     *
540
-     * @param string $text
541
-     * @return void
542
-     * @throws LogicException
543
-     * @throws EE_Error
544
-     */
545
-    public function appendSubmitButton($text = '')
546
-    {
547
-        if ($this->form->subsection_exists($this->slug() . '-submit-btn')) {
548
-            return;
549
-        }
550
-        $this->form->add_subsections(
551
-            array($this->slug() . '-submit-btn' => $this->generateSubmitButton($text)),
552
-            null,
553
-            false
554
-        );
555
-    }
556
-
557
-
558
-
559
-    /**
560
-     * creates and returns an EE_Submit_Input labeled "Cancel"
561
-     *
562
-     * @param string $text
563
-     * @return EE_Submit_Input
564
-     */
565
-    public function generateCancelButton($text = '')
566
-    {
567
-        $cancel_button = new EE_Submit_Input(
568
-            array(
569
-                'html_name'             => 'ee-form-submit-' . $this->slug(), // YES! Same name as submit !!!
570
-                'html_id'               => 'ee-cancel-form-' . $this->slug(),
571
-                'html_class'            => 'ee-cancel-form',
572
-                'html_label'            => ' ',
573
-                'other_html_attributes' => ' rel="' . $this->slug() . '"',
574
-                'default'               => ! empty($text) ? $text : esc_html__('Cancel', 'event_espresso'),
575
-            )
576
-        );
577
-        $cancel_button->set_button_css_attributes(false);
578
-        return $cancel_button;
579
-    }
580
-
581
-
582
-
583
-    /**
584
-     * appends a float clearing div onto end of form
585
-     *
586
-     * @return void
587
-     * @throws EE_Error
588
-     */
589
-    public function clearFormButtonFloats()
590
-    {
591
-        $this->form->add_subsections(
592
-            array(
593
-                'clear-submit-btn-float' => new EE_Form_Section_HTML(
594
-                    EEH_HTML::div('', '', 'clear-float') . EEH_HTML::divx()
595
-                ),
596
-            ),
597
-            null,
598
-            false
599
-        );
600
-    }
601
-
602
-
603
-
604
-    /**
605
-     * takes the generated form and displays it along with ony other non-form HTML that may be required
606
-     * returns a string of HTML that can be directly echoed in a template
607
-     *
608
-     * @return string
609
-     * @throws LogicException
610
-     * @throws EE_Error
611
-     */
612
-    public function display()
613
-    {
614
-        $form_html = apply_filters(
615
-            'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__display__before_form',
616
-            ''
617
-        );
618
-        $form_config = $this->formConfig();
619
-        if (
620
-            $form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
621
-            || $form_config === FormHandler::ADD_FORM_TAGS_ONLY
622
-        ) {
623
-            $form_html .= $this->form()->form_open($this->formAction());
624
-        }
625
-        $form_html .= $this->form(true)->get_html($this->form_has_errors);
626
-        if (
627
-            $form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
628
-            || $form_config === FormHandler::ADD_FORM_TAGS_ONLY
629
-        ) {
630
-            $form_html .= $this->form()->form_close();
631
-        }
632
-        $form_html .= apply_filters(
633
-            'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__display__after_form',
634
-            ''
635
-        );
636
-        return $form_html;
637
-    }
638
-
639
-
640
-
641
-    /**
642
-     * handles processing the form submission
643
-     * returns true or false depending on whether the form was processed successfully or not
644
-     *
645
-     * @param array $submitted_form_data
646
-     * @return array
647
-     * @throws EE_Error
648
-     * @throws LogicException
649
-     * @throws InvalidFormSubmissionException
650
-     */
651
-    public function process($submitted_form_data = array())
652
-    {
653
-        if (! $this->form()->was_submitted($submitted_form_data)) {
654
-            throw new InvalidFormSubmissionException($this->form_name);
655
-        }
656
-        $this->form(true)->receive_form_submission($submitted_form_data);
657
-        if (! $this->form()->is_valid()) {
658
-            throw new InvalidFormSubmissionException(
659
-                $this->form_name,
660
-                sprintf(
661
-                    esc_html__(
662
-                        'The "%1$s" form is invalid. Please correct the following errors and resubmit: %2$s %3$s',
663
-                        'event_espresso'
664
-                    ),
665
-                    $this->form_name,
666
-                    '<br />',
667
-                    $this->form()->submission_error_message()
668
-                )
669
-            );
670
-        }
671
-        return $this->form()->valid_data();
672
-    }
37
+	/**
38
+	 * will add opening and closing HTML form tags as well as a submit button
39
+	 */
40
+	const ADD_FORM_TAGS_AND_SUBMIT = 'add_form_tags_and_submit';
41
+
42
+	/**
43
+	 * will add opening and closing HTML form tags but NOT a submit button
44
+	 */
45
+	const ADD_FORM_TAGS_ONLY = 'add_form_tags_only';
46
+
47
+	/**
48
+	 * will NOT add opening and closing HTML form tags but will add a submit button
49
+	 */
50
+	const ADD_FORM_SUBMIT_ONLY = 'add_form_submit_only';
51
+
52
+	/**
53
+	 * will NOT add opening and closing HTML form tags NOR a submit button
54
+	 */
55
+	const DO_NOT_SETUP_FORM = 'do_not_setup_form';
56
+
57
+	/**
58
+	 * if set to false, then this form has no displayable content,
59
+	 * and will only be used for processing data sent passed via GET or POST
60
+	 * defaults to true ( ie: form has displayable content )
61
+	 *
62
+	 * @var boolean $displayable
63
+	 */
64
+	private $displayable = true;
65
+
66
+	/**
67
+	 * @var string $form_name
68
+	 */
69
+	private $form_name;
70
+
71
+	/**
72
+	 * @var string $admin_name
73
+	 */
74
+	private $admin_name;
75
+
76
+	/**
77
+	 * @var string $slug
78
+	 */
79
+	private $slug;
80
+
81
+	/**
82
+	 * @var string $submit_btn_text
83
+	 */
84
+	private $submit_btn_text;
85
+
86
+	/**
87
+	 * @var string $form_action
88
+	 */
89
+	private $form_action;
90
+
91
+	/**
92
+	 * form params in key value pairs
93
+	 * can be added to form action URL or as hidden inputs
94
+	 *
95
+	 * @var array $form_args
96
+	 */
97
+	private $form_args = array();
98
+
99
+	/**
100
+	 * value of one of the string constant above
101
+	 *
102
+	 * @var string $form_config
103
+	 */
104
+	private $form_config;
105
+
106
+	/**
107
+	 * whether or not the form was determined to be invalid
108
+	 *
109
+	 * @var boolean $form_has_errors
110
+	 */
111
+	private $form_has_errors;
112
+
113
+	/**
114
+	 * the absolute top level form section being used on the page
115
+	 *
116
+	 * @var EE_Form_Section_Proper $form
117
+	 */
118
+	private $form;
119
+
120
+	/**
121
+	 * @var EE_Registry $registry
122
+	 */
123
+	protected $registry;
124
+
125
+
126
+
127
+	/**
128
+	 * Form constructor.
129
+	 *
130
+	 * @param string      $form_name
131
+	 * @param string      $admin_name
132
+	 * @param string      $slug
133
+	 * @param string      $form_action
134
+	 * @param string      $form_config
135
+	 * @param EE_Registry $registry
136
+	 * @throws InvalidDataTypeException
137
+	 * @throws DomainException
138
+	 * @throws InvalidArgumentException
139
+	 */
140
+	public function __construct(
141
+		$form_name,
142
+		$admin_name,
143
+		$slug,
144
+		$form_action = '',
145
+		$form_config = FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
146
+		EE_Registry $registry
147
+	) {
148
+		$this->setFormName($form_name);
149
+		$this->setAdminName($admin_name);
150
+		$this->setSlug($slug);
151
+		$this->setFormAction($form_action);
152
+		$this->setFormConfig($form_config);
153
+		$this->setSubmitBtnText(esc_html__('Submit', 'event_espresso'));
154
+		$this->registry = $registry;
155
+	}
156
+
157
+
158
+
159
+	/**
160
+	 * @return array
161
+	 */
162
+	public static function getFormConfigConstants()
163
+	{
164
+		return array(
165
+			FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
166
+			FormHandler::ADD_FORM_TAGS_ONLY,
167
+			FormHandler::ADD_FORM_SUBMIT_ONLY,
168
+			FormHandler::DO_NOT_SETUP_FORM,
169
+		);
170
+	}
171
+
172
+
173
+
174
+	/**
175
+	 * @param bool $for_display
176
+	 * @return EE_Form_Section_Proper
177
+	 * @throws EE_Error
178
+	 * @throws LogicException
179
+	 */
180
+	public function form($for_display = false)
181
+	{
182
+		if (! $this->formIsValid()) {
183
+			return null;
184
+		}
185
+		if ($for_display) {
186
+			$form_config = $this->formConfig();
187
+			if (
188
+				$form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
189
+				|| $form_config === FormHandler::ADD_FORM_SUBMIT_ONLY
190
+			) {
191
+				$this->appendSubmitButton();
192
+				$this->clearFormButtonFloats();
193
+			}
194
+		}
195
+		return $this->form;
196
+	}
197
+
198
+
199
+
200
+	/**
201
+	 * @return boolean
202
+	 * @throws LogicException
203
+	 */
204
+	public function formIsValid()
205
+	{
206
+		if (! $this->form instanceof EE_Form_Section_Proper) {
207
+			static $generated = false;
208
+			if (! $generated) {
209
+				$generated = true;
210
+				$form = apply_filters(
211
+					'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__formIsValid__generated_form_object',
212
+					$this->generate(),
213
+					$this
214
+				);
215
+				if ($form instanceof EE_Form_Section_Proper) {
216
+					$this->setForm($form);
217
+				}
218
+			}
219
+			return $this->verifyForm();
220
+		}
221
+		return true;
222
+	}
223
+
224
+
225
+
226
+	/**
227
+	 * @return boolean
228
+	 * @throws LogicException
229
+	 */
230
+	public function verifyForm()
231
+	{
232
+		if ($this->form instanceof EE_Form_Section_Proper) {
233
+			return true;
234
+		}
235
+		throw new LogicException(
236
+			sprintf(
237
+				esc_html__('The "%1$s" form is invalid or missing', 'event_espresso'),
238
+				$this->form_name
239
+			)
240
+		);
241
+	}
242
+
243
+
244
+
245
+	/**
246
+	 * @param EE_Form_Section_Proper $form
247
+	 */
248
+	public function setForm(EE_Form_Section_Proper $form)
249
+	{
250
+		$this->form = $form;
251
+	}
252
+
253
+
254
+
255
+	/**
256
+	 * @return boolean
257
+	 */
258
+	public function displayable()
259
+	{
260
+		return $this->displayable;
261
+	}
262
+
263
+
264
+
265
+	/**
266
+	 * @param boolean $displayable
267
+	 */
268
+	public function setDisplayable($displayable = false)
269
+	{
270
+		$this->displayable = filter_var($displayable, FILTER_VALIDATE_BOOLEAN);
271
+	}
272
+
273
+
274
+
275
+	/**
276
+	 * a public name for the form that can be displayed on the frontend of a site
277
+	 *
278
+	 * @return string
279
+	 */
280
+	public function formName()
281
+	{
282
+		return $this->form_name;
283
+	}
284
+
285
+
286
+
287
+	/**
288
+	 * @param string $form_name
289
+	 * @throws InvalidDataTypeException
290
+	 */
291
+	public function setFormName($form_name)
292
+	{
293
+		if (! is_string($form_name)) {
294
+			throw new InvalidDataTypeException('$form_name', $form_name, 'string');
295
+		}
296
+		$this->form_name = $form_name;
297
+	}
298
+
299
+
300
+
301
+	/**
302
+	 * a public name for the form that can be displayed, but only in the admin
303
+	 *
304
+	 * @return string
305
+	 */
306
+	public function adminName()
307
+	{
308
+		return $this->admin_name;
309
+	}
310
+
311
+
312
+
313
+	/**
314
+	 * @param string $admin_name
315
+	 * @throws InvalidDataTypeException
316
+	 */
317
+	public function setAdminName($admin_name)
318
+	{
319
+		if (! is_string($admin_name)) {
320
+			throw new InvalidDataTypeException('$admin_name', $admin_name, 'string');
321
+		}
322
+		$this->admin_name = $admin_name;
323
+	}
324
+
325
+
326
+
327
+	/**
328
+	 * a URL friendly string that can be used for identifying the form
329
+	 *
330
+	 * @return string
331
+	 */
332
+	public function slug()
333
+	{
334
+		return $this->slug;
335
+	}
336
+
337
+
338
+
339
+	/**
340
+	 * @param string $slug
341
+	 * @throws InvalidDataTypeException
342
+	 */
343
+	public function setSlug($slug)
344
+	{
345
+		if (! is_string($slug)) {
346
+			throw new InvalidDataTypeException('$slug', $slug, 'string');
347
+		}
348
+		$this->slug = $slug;
349
+	}
350
+
351
+
352
+
353
+	/**
354
+	 * @return string
355
+	 */
356
+	public function submitBtnText()
357
+	{
358
+		return $this->submit_btn_text;
359
+	}
360
+
361
+
362
+
363
+	/**
364
+	 * @param string $submit_btn_text
365
+	 * @throws InvalidDataTypeException
366
+	 * @throws InvalidArgumentException
367
+	 */
368
+	public function setSubmitBtnText($submit_btn_text)
369
+	{
370
+		if (! is_string($submit_btn_text)) {
371
+			throw new InvalidDataTypeException('$submit_btn_text', $submit_btn_text, 'string');
372
+		}
373
+		if (empty($submit_btn_text)) {
374
+			throw new InvalidArgumentException(
375
+				esc_html__('Can not set Submit button text because an empty string was provided.', 'event_espresso')
376
+			);
377
+		}
378
+		$this->submit_btn_text = $submit_btn_text;
379
+	}
380
+
381
+
382
+
383
+	/**
384
+	 * @return string
385
+	 */
386
+	public function formAction()
387
+	{
388
+		return ! empty($this->form_args)
389
+			? add_query_arg($this->form_args, $this->form_action)
390
+			: $this->form_action;
391
+	}
392
+
393
+
394
+
395
+	/**
396
+	 * @param string $form_action
397
+	 * @throws InvalidDataTypeException
398
+	 */
399
+	public function setFormAction($form_action)
400
+	{
401
+		if (! is_string($form_action)) {
402
+			throw new InvalidDataTypeException('$form_action', $form_action, 'string');
403
+		}
404
+		$this->form_action = $form_action;
405
+	}
406
+
407
+
408
+
409
+	/**
410
+	 * @param array $form_args
411
+	 * @throws InvalidDataTypeException
412
+	 * @throws InvalidArgumentException
413
+	 */
414
+	public function addFormActionArgs($form_args = array())
415
+	{
416
+		if (is_object($form_args)) {
417
+			throw new InvalidDataTypeException(
418
+				'$form_args',
419
+				$form_args,
420
+				'anything other than an object was expected.'
421
+			);
422
+		}
423
+		if (empty($form_args)) {
424
+			throw new InvalidArgumentException(
425
+				esc_html__('The redirect arguments can not be an empty array.', 'event_espresso')
426
+			);
427
+		}
428
+		$this->form_args = array_merge($this->form_args, $form_args);
429
+	}
430
+
431
+
432
+
433
+	/**
434
+	 * @return string
435
+	 */
436
+	public function formConfig()
437
+	{
438
+		return $this->form_config;
439
+	}
440
+
441
+
442
+
443
+	/**
444
+	 * @param string $form_config
445
+	 * @throws DomainException
446
+	 */
447
+	public function setFormConfig($form_config)
448
+	{
449
+		if (
450
+		! in_array(
451
+			$form_config,
452
+			array(
453
+				FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
454
+				FormHandler::ADD_FORM_TAGS_ONLY,
455
+				FormHandler::ADD_FORM_SUBMIT_ONLY,
456
+				FormHandler::DO_NOT_SETUP_FORM,
457
+			),
458
+			true
459
+		)
460
+		) {
461
+			throw new DomainException(
462
+				sprintf(
463
+					esc_html__('"%1$s" is not a valid value for the form config. Please use one of the class constants on \EventEspresso\core\libraries\form_sections\form_handlers\Form',
464
+						'event_espresso'),
465
+					$form_config
466
+				)
467
+			);
468
+		}
469
+		$this->form_config = $form_config;
470
+	}
471
+
472
+
473
+
474
+	/**
475
+	 * called after the form is instantiated
476
+	 * and used for performing any logic that needs to occur early
477
+	 * before any of the other methods are called.
478
+	 * returns true if everything is ok to proceed,
479
+	 * and false if no further form logic should be implemented
480
+	 *
481
+	 * @return boolean
482
+	 */
483
+	public function initialize()
484
+	{
485
+		$this->form_has_errors = EE_Error::has_error(true);
486
+		return true;
487
+	}
488
+
489
+
490
+
491
+	/**
492
+	 * used for setting up css and js
493
+	 *
494
+	 * @return void
495
+	 * @throws LogicException
496
+	 * @throws EE_Error
497
+	 */
498
+	public function enqueueStylesAndScripts()
499
+	{
500
+		$this->form(false)->enqueue_js();
501
+	}
502
+
503
+
504
+
505
+	/**
506
+	 * creates and returns the actual form
507
+	 *
508
+	 * @return EE_Form_Section_Proper
509
+	 */
510
+	abstract public function generate();
511
+
512
+
513
+
514
+	/**
515
+	 * creates and returns an EE_Submit_Input labeled "Submit"
516
+	 *
517
+	 * @param string $text
518
+	 * @return EE_Submit_Input
519
+	 */
520
+	public function generateSubmitButton($text = '')
521
+	{
522
+		$text = ! empty($text) ? $text : $this->submitBtnText();
523
+		return new EE_Submit_Input(
524
+			array(
525
+				'html_name'             => 'ee-form-submit-' . $this->slug(),
526
+				'html_id'               => 'ee-form-submit-' . $this->slug(),
527
+				'html_class'            => 'ee-form-submit',
528
+				'html_label'            => '&nbsp;',
529
+				'other_html_attributes' => ' rel="' . $this->slug() . '"',
530
+				'default'               => $text,
531
+			)
532
+		);
533
+	}
534
+
535
+
536
+
537
+	/**
538
+	 * calls generateSubmitButton() and appends it onto the form along with a float clearing div
539
+	 *
540
+	 * @param string $text
541
+	 * @return void
542
+	 * @throws LogicException
543
+	 * @throws EE_Error
544
+	 */
545
+	public function appendSubmitButton($text = '')
546
+	{
547
+		if ($this->form->subsection_exists($this->slug() . '-submit-btn')) {
548
+			return;
549
+		}
550
+		$this->form->add_subsections(
551
+			array($this->slug() . '-submit-btn' => $this->generateSubmitButton($text)),
552
+			null,
553
+			false
554
+		);
555
+	}
556
+
557
+
558
+
559
+	/**
560
+	 * creates and returns an EE_Submit_Input labeled "Cancel"
561
+	 *
562
+	 * @param string $text
563
+	 * @return EE_Submit_Input
564
+	 */
565
+	public function generateCancelButton($text = '')
566
+	{
567
+		$cancel_button = new EE_Submit_Input(
568
+			array(
569
+				'html_name'             => 'ee-form-submit-' . $this->slug(), // YES! Same name as submit !!!
570
+				'html_id'               => 'ee-cancel-form-' . $this->slug(),
571
+				'html_class'            => 'ee-cancel-form',
572
+				'html_label'            => '&nbsp;',
573
+				'other_html_attributes' => ' rel="' . $this->slug() . '"',
574
+				'default'               => ! empty($text) ? $text : esc_html__('Cancel', 'event_espresso'),
575
+			)
576
+		);
577
+		$cancel_button->set_button_css_attributes(false);
578
+		return $cancel_button;
579
+	}
580
+
581
+
582
+
583
+	/**
584
+	 * appends a float clearing div onto end of form
585
+	 *
586
+	 * @return void
587
+	 * @throws EE_Error
588
+	 */
589
+	public function clearFormButtonFloats()
590
+	{
591
+		$this->form->add_subsections(
592
+			array(
593
+				'clear-submit-btn-float' => new EE_Form_Section_HTML(
594
+					EEH_HTML::div('', '', 'clear-float') . EEH_HTML::divx()
595
+				),
596
+			),
597
+			null,
598
+			false
599
+		);
600
+	}
601
+
602
+
603
+
604
+	/**
605
+	 * takes the generated form and displays it along with ony other non-form HTML that may be required
606
+	 * returns a string of HTML that can be directly echoed in a template
607
+	 *
608
+	 * @return string
609
+	 * @throws LogicException
610
+	 * @throws EE_Error
611
+	 */
612
+	public function display()
613
+	{
614
+		$form_html = apply_filters(
615
+			'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__display__before_form',
616
+			''
617
+		);
618
+		$form_config = $this->formConfig();
619
+		if (
620
+			$form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
621
+			|| $form_config === FormHandler::ADD_FORM_TAGS_ONLY
622
+		) {
623
+			$form_html .= $this->form()->form_open($this->formAction());
624
+		}
625
+		$form_html .= $this->form(true)->get_html($this->form_has_errors);
626
+		if (
627
+			$form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
628
+			|| $form_config === FormHandler::ADD_FORM_TAGS_ONLY
629
+		) {
630
+			$form_html .= $this->form()->form_close();
631
+		}
632
+		$form_html .= apply_filters(
633
+			'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__display__after_form',
634
+			''
635
+		);
636
+		return $form_html;
637
+	}
638
+
639
+
640
+
641
+	/**
642
+	 * handles processing the form submission
643
+	 * returns true or false depending on whether the form was processed successfully or not
644
+	 *
645
+	 * @param array $submitted_form_data
646
+	 * @return array
647
+	 * @throws EE_Error
648
+	 * @throws LogicException
649
+	 * @throws InvalidFormSubmissionException
650
+	 */
651
+	public function process($submitted_form_data = array())
652
+	{
653
+		if (! $this->form()->was_submitted($submitted_form_data)) {
654
+			throw new InvalidFormSubmissionException($this->form_name);
655
+		}
656
+		$this->form(true)->receive_form_submission($submitted_form_data);
657
+		if (! $this->form()->is_valid()) {
658
+			throw new InvalidFormSubmissionException(
659
+				$this->form_name,
660
+				sprintf(
661
+					esc_html__(
662
+						'The "%1$s" form is invalid. Please correct the following errors and resubmit: %2$s %3$s',
663
+						'event_espresso'
664
+					),
665
+					$this->form_name,
666
+					'<br />',
667
+					$this->form()->submission_error_message()
668
+				)
669
+			);
670
+		}
671
+		return $this->form()->valid_data();
672
+	}
673 673
 
674 674
 
675 675
 
Please login to merge, or discard this patch.
Spacing   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -14,7 +14,7 @@  discard block
 block discarded – undo
14 14
 use EventEspresso\core\exceptions\InvalidDataTypeException;
15 15
 use EventEspresso\core\exceptions\InvalidFormSubmissionException;
16 16
 
17
-if (! defined('EVENT_ESPRESSO_VERSION')) {
17
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
18 18
     exit('No direct script access allowed');
19 19
 }
20 20
 
@@ -179,7 +179,7 @@  discard block
 block discarded – undo
179 179
      */
180 180
     public function form($for_display = false)
181 181
     {
182
-        if (! $this->formIsValid()) {
182
+        if ( ! $this->formIsValid()) {
183 183
             return null;
184 184
         }
185 185
         if ($for_display) {
@@ -203,9 +203,9 @@  discard block
 block discarded – undo
203 203
      */
204 204
     public function formIsValid()
205 205
     {
206
-        if (! $this->form instanceof EE_Form_Section_Proper) {
206
+        if ( ! $this->form instanceof EE_Form_Section_Proper) {
207 207
             static $generated = false;
208
-            if (! $generated) {
208
+            if ( ! $generated) {
209 209
                 $generated = true;
210 210
                 $form = apply_filters(
211 211
                     'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__formIsValid__generated_form_object',
@@ -290,7 +290,7 @@  discard block
 block discarded – undo
290 290
      */
291 291
     public function setFormName($form_name)
292 292
     {
293
-        if (! is_string($form_name)) {
293
+        if ( ! is_string($form_name)) {
294 294
             throw new InvalidDataTypeException('$form_name', $form_name, 'string');
295 295
         }
296 296
         $this->form_name = $form_name;
@@ -316,7 +316,7 @@  discard block
 block discarded – undo
316 316
      */
317 317
     public function setAdminName($admin_name)
318 318
     {
319
-        if (! is_string($admin_name)) {
319
+        if ( ! is_string($admin_name)) {
320 320
             throw new InvalidDataTypeException('$admin_name', $admin_name, 'string');
321 321
         }
322 322
         $this->admin_name = $admin_name;
@@ -342,7 +342,7 @@  discard block
 block discarded – undo
342 342
      */
343 343
     public function setSlug($slug)
344 344
     {
345
-        if (! is_string($slug)) {
345
+        if ( ! is_string($slug)) {
346 346
             throw new InvalidDataTypeException('$slug', $slug, 'string');
347 347
         }
348 348
         $this->slug = $slug;
@@ -367,7 +367,7 @@  discard block
 block discarded – undo
367 367
      */
368 368
     public function setSubmitBtnText($submit_btn_text)
369 369
     {
370
-        if (! is_string($submit_btn_text)) {
370
+        if ( ! is_string($submit_btn_text)) {
371 371
             throw new InvalidDataTypeException('$submit_btn_text', $submit_btn_text, 'string');
372 372
         }
373 373
         if (empty($submit_btn_text)) {
@@ -398,7 +398,7 @@  discard block
 block discarded – undo
398 398
      */
399 399
     public function setFormAction($form_action)
400 400
     {
401
-        if (! is_string($form_action)) {
401
+        if ( ! is_string($form_action)) {
402 402
             throw new InvalidDataTypeException('$form_action', $form_action, 'string');
403 403
         }
404 404
         $this->form_action = $form_action;
@@ -522,11 +522,11 @@  discard block
 block discarded – undo
522 522
         $text = ! empty($text) ? $text : $this->submitBtnText();
523 523
         return new EE_Submit_Input(
524 524
             array(
525
-                'html_name'             => 'ee-form-submit-' . $this->slug(),
526
-                'html_id'               => 'ee-form-submit-' . $this->slug(),
525
+                'html_name'             => 'ee-form-submit-'.$this->slug(),
526
+                'html_id'               => 'ee-form-submit-'.$this->slug(),
527 527
                 'html_class'            => 'ee-form-submit',
528 528
                 'html_label'            => '&nbsp;',
529
-                'other_html_attributes' => ' rel="' . $this->slug() . '"',
529
+                'other_html_attributes' => ' rel="'.$this->slug().'"',
530 530
                 'default'               => $text,
531 531
             )
532 532
         );
@@ -544,11 +544,11 @@  discard block
 block discarded – undo
544 544
      */
545 545
     public function appendSubmitButton($text = '')
546 546
     {
547
-        if ($this->form->subsection_exists($this->slug() . '-submit-btn')) {
547
+        if ($this->form->subsection_exists($this->slug().'-submit-btn')) {
548 548
             return;
549 549
         }
550 550
         $this->form->add_subsections(
551
-            array($this->slug() . '-submit-btn' => $this->generateSubmitButton($text)),
551
+            array($this->slug().'-submit-btn' => $this->generateSubmitButton($text)),
552 552
             null,
553 553
             false
554 554
         );
@@ -566,11 +566,11 @@  discard block
 block discarded – undo
566 566
     {
567 567
         $cancel_button = new EE_Submit_Input(
568 568
             array(
569
-                'html_name'             => 'ee-form-submit-' . $this->slug(), // YES! Same name as submit !!!
570
-                'html_id'               => 'ee-cancel-form-' . $this->slug(),
569
+                'html_name'             => 'ee-form-submit-'.$this->slug(), // YES! Same name as submit !!!
570
+                'html_id'               => 'ee-cancel-form-'.$this->slug(),
571 571
                 'html_class'            => 'ee-cancel-form',
572 572
                 'html_label'            => '&nbsp;',
573
-                'other_html_attributes' => ' rel="' . $this->slug() . '"',
573
+                'other_html_attributes' => ' rel="'.$this->slug().'"',
574 574
                 'default'               => ! empty($text) ? $text : esc_html__('Cancel', 'event_espresso'),
575 575
             )
576 576
         );
@@ -591,7 +591,7 @@  discard block
 block discarded – undo
591 591
         $this->form->add_subsections(
592 592
             array(
593 593
                 'clear-submit-btn-float' => new EE_Form_Section_HTML(
594
-                    EEH_HTML::div('', '', 'clear-float') . EEH_HTML::divx()
594
+                    EEH_HTML::div('', '', 'clear-float').EEH_HTML::divx()
595 595
                 ),
596 596
             ),
597 597
             null,
@@ -650,11 +650,11 @@  discard block
 block discarded – undo
650 650
      */
651 651
     public function process($submitted_form_data = array())
652 652
     {
653
-        if (! $this->form()->was_submitted($submitted_form_data)) {
653
+        if ( ! $this->form()->was_submitted($submitted_form_data)) {
654 654
             throw new InvalidFormSubmissionException($this->form_name);
655 655
         }
656 656
         $this->form(true)->receive_form_submission($submitted_form_data);
657
-        if (! $this->form()->is_valid()) {
657
+        if ( ! $this->form()->is_valid()) {
658 658
             throw new InvalidFormSubmissionException(
659 659
                 $this->form_name,
660 660
                 sprintf(
Please login to merge, or discard this patch.
core/db_classes/EE_Ticket.class.php 1 patch
Indentation   +591 added lines, -591 removed lines patch added patch discarded remove patch
@@ -61,15 +61,15 @@  discard block
 block discarded – undo
61 61
 
62 62
 
63 63
 
64
-    /**
65
-     * @param array  $props_n_values          incoming values
66
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
67
-     *                                        used.)
68
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
69
-     *                                        date_format and the second value is the time format
70
-     * @return EE_Ticket
71
-     * @throws \EE_Error
72
-     */
64
+	/**
65
+	 * @param array  $props_n_values          incoming values
66
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
67
+	 *                                        used.)
68
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
69
+	 *                                        date_format and the second value is the time format
70
+	 * @return EE_Ticket
71
+	 * @throws \EE_Error
72
+	 */
73 73
 	public static function new_instance( $props_n_values = array(), $timezone = null, $date_formats = array() ) {
74 74
 		$has_object = parent::_check_for_object( $props_n_values, __CLASS__, $timezone, $date_formats );
75 75
 		return $has_object ? $has_object : new self( $props_n_values, false, $timezone, $date_formats );
@@ -77,36 +77,36 @@  discard block
 block discarded – undo
77 77
 
78 78
 
79 79
 
80
-    /**
81
-     * @param array  $props_n_values  incoming values from the database
82
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
83
-     *                                the website will be used.
84
-     * @return EE_Ticket
85
-     * @throws \EE_Error
86
-     */
80
+	/**
81
+	 * @param array  $props_n_values  incoming values from the database
82
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
83
+	 *                                the website will be used.
84
+	 * @return EE_Ticket
85
+	 * @throws \EE_Error
86
+	 */
87 87
 	public static function new_instance_from_db( $props_n_values = array(), $timezone = null ) {
88 88
 		return new self( $props_n_values, TRUE, $timezone );
89 89
 	}
90 90
 
91 91
 
92 92
 
93
-    /**
94
-     * @return bool
95
-     * @throws \EE_Error
96
-     */
93
+	/**
94
+	 * @return bool
95
+	 * @throws \EE_Error
96
+	 */
97 97
 	public function parent() {
98 98
 		return $this->get( 'TKT_parent' );
99 99
 	}
100 100
 
101 101
 
102 102
 
103
-    /**
104
-     * return if a ticket has quantities available for purchase
105
-     *
106
-     * @param  int $DTT_ID the primary key for a particular datetime
107
-     * @return boolean
108
-     * @throws \EE_Error
109
-     */
103
+	/**
104
+	 * return if a ticket has quantities available for purchase
105
+	 *
106
+	 * @param  int $DTT_ID the primary key for a particular datetime
107
+	 * @return boolean
108
+	 * @throws \EE_Error
109
+	 */
110 110
 	public function available( $DTT_ID = 0 ) {
111 111
 		// are we checking availability for a particular datetime ?
112 112
 		if ( $DTT_ID ) {
@@ -123,14 +123,14 @@  discard block
 block discarded – undo
123 123
 
124 124
 
125 125
 
126
-    /**
127
-     * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
128
-     *
129
-     * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the relevant status const
130
-     * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save further processing
131
-     * @return mixed status int if the display string isn't requested
132
-     * @throws \EE_Error
133
-     */
126
+	/**
127
+	 * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
128
+	 *
129
+	 * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the relevant status const
130
+	 * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save further processing
131
+	 * @return mixed status int if the display string isn't requested
132
+	 * @throws \EE_Error
133
+	 */
134 134
 	public function ticket_status( $display = FALSE, $remaining = null ) {
135 135
 		$remaining = is_bool( $remaining ) ? $remaining : $this->is_remaining();
136 136
 		if ( ! $remaining ) {
@@ -153,14 +153,14 @@  discard block
 block discarded – undo
153 153
 
154 154
 
155 155
 
156
-    /**
157
-     * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale considering ALL the factors used for figuring that out.
158
-     *
159
-     * @access public
160
-     * @param  int $DTT_ID if an int above 0 is included here then we get a specific dtt.
161
-     * @return boolean         true = tickets remaining, false not.
162
-     * @throws \EE_Error
163
-     */
156
+	/**
157
+	 * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale considering ALL the factors used for figuring that out.
158
+	 *
159
+	 * @access public
160
+	 * @param  int $DTT_ID if an int above 0 is included here then we get a specific dtt.
161
+	 * @return boolean         true = tickets remaining, false not.
162
+	 * @throws \EE_Error
163
+	 */
164 164
 	public function is_remaining( $DTT_ID = 0 ) {
165 165
 		$num_remaining = $this->remaining( $DTT_ID );
166 166
 		if ( $num_remaining === 0 ) {
@@ -174,76 +174,76 @@  discard block
 block discarded – undo
174 174
 
175 175
 
176 176
 
177
-    /**
178
-     * return the total number of tickets available for purchase
179
-     *
180
-     * @param  int $DTT_ID the primary key for a particular datetime.
181
-     *                     set to 0 for all related datetimes
182
-     * @return int
183
-     * @throws \EE_Error
184
-     */
177
+	/**
178
+	 * return the total number of tickets available for purchase
179
+	 *
180
+	 * @param  int $DTT_ID the primary key for a particular datetime.
181
+	 *                     set to 0 for all related datetimes
182
+	 * @return int
183
+	 * @throws \EE_Error
184
+	 */
185 185
 	public function remaining( $DTT_ID = 0 ) {
186 186
 		return $this->real_quantity_on_ticket('saleable', $DTT_ID );
187 187
 	}
188 188
 
189 189
 
190 190
 
191
-    /**
192
-     * Gets min
193
-     *
194
-     * @return int
195
-     * @throws \EE_Error
196
-     */
191
+	/**
192
+	 * Gets min
193
+	 *
194
+	 * @return int
195
+	 * @throws \EE_Error
196
+	 */
197 197
 	public function min() {
198 198
 		return $this->get( 'TKT_min' );
199 199
 	}
200 200
 
201 201
 
202 202
 
203
-    /**
204
-     * return if a ticket is no longer available cause its available dates have expired.
205
-     *
206
-     * @return boolean
207
-     * @throws \EE_Error
208
-     */
203
+	/**
204
+	 * return if a ticket is no longer available cause its available dates have expired.
205
+	 *
206
+	 * @return boolean
207
+	 * @throws \EE_Error
208
+	 */
209 209
 	public function is_expired() {
210 210
 		return ( $this->get_raw( 'TKT_end_date' ) < time() );
211 211
 	}
212 212
 
213 213
 
214 214
 
215
-    /**
216
-     * Return if a ticket is yet to go on sale or not
217
-     *
218
-     * @return boolean
219
-     * @throws \EE_Error
220
-     */
215
+	/**
216
+	 * Return if a ticket is yet to go on sale or not
217
+	 *
218
+	 * @return boolean
219
+	 * @throws \EE_Error
220
+	 */
221 221
 	public function is_pending() {
222 222
 		return ( $this->get_raw( 'TKT_start_date' ) > time() );
223 223
 	}
224 224
 
225 225
 
226 226
 
227
-    /**
228
-     * Return if a ticket is on sale or not
229
-     *
230
-     * @return boolean
231
-     * @throws \EE_Error
232
-     */
227
+	/**
228
+	 * Return if a ticket is on sale or not
229
+	 *
230
+	 * @return boolean
231
+	 * @throws \EE_Error
232
+	 */
233 233
 	public function is_on_sale() {
234 234
 		return ( $this->get_raw( 'TKT_start_date' ) < time() && $this->get_raw( 'TKT_end_date' ) > time() );
235 235
 	}
236 236
 
237 237
 
238 238
 
239
-    /**
240
-     * This returns the chronologically last datetime that this ticket is associated with
241
-     *
242
-     * @param string $dt_frmt
243
-     * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with the end date ie: Jan 01 "to" Dec 31
244
-     * @return string
245
-     * @throws \EE_Error
246
-     */
239
+	/**
240
+	 * This returns the chronologically last datetime that this ticket is associated with
241
+	 *
242
+	 * @param string $dt_frmt
243
+	 * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with the end date ie: Jan 01 "to" Dec 31
244
+	 * @return string
245
+	 * @throws \EE_Error
246
+	 */
247 247
 	public function date_range( $dt_frmt = '', $conjunction = ' - ' ) {
248 248
 		$first_date = $this->first_datetime() instanceof EE_Datetime ? $this->first_datetime()->start_date( $dt_frmt ) : '';
249 249
 		$last_date = $this->last_datetime() instanceof EE_Datetime ? $this->last_datetime()->end_date( $dt_frmt ) : '';
@@ -253,12 +253,12 @@  discard block
 block discarded – undo
253 253
 
254 254
 
255 255
 
256
-    /**
257
-     * This returns the chronologically first datetime that this ticket is associated with
258
-     *
259
-     * @return EE_Datetime
260
-     * @throws \EE_Error
261
-     */
256
+	/**
257
+	 * This returns the chronologically first datetime that this ticket is associated with
258
+	 *
259
+	 * @return EE_Datetime
260
+	 * @throws \EE_Error
261
+	 */
262 262
 	public function first_datetime() {
263 263
 		$datetimes = $this->datetimes( array( 'limit' => 1 ) );
264 264
 		return reset( $datetimes );
@@ -266,14 +266,14 @@  discard block
 block discarded – undo
266 266
 
267 267
 
268 268
 
269
-    /**
270
-     * Gets all the datetimes this ticket can be used for attending.
271
-     * Unless otherwise specified, orders datetimes by start date.
272
-     *
273
-     * @param array $query_params see EEM_Base::get_all()
274
-     * @return EE_Datetime[]|EE_Base_Class[]
275
-     * @throws \EE_Error
276
-     */
269
+	/**
270
+	 * Gets all the datetimes this ticket can be used for attending.
271
+	 * Unless otherwise specified, orders datetimes by start date.
272
+	 *
273
+	 * @param array $query_params see EEM_Base::get_all()
274
+	 * @return EE_Datetime[]|EE_Base_Class[]
275
+	 * @throws \EE_Error
276
+	 */
277 277
 	public function datetimes( $query_params = array() ) {
278 278
 		if ( ! isset( $query_params[ 'order_by' ] ) ) {
279 279
 			$query_params[ 'order_by' ][ 'DTT_order' ] = 'ASC';
@@ -283,12 +283,12 @@  discard block
 block discarded – undo
283 283
 
284 284
 
285 285
 
286
-    /**
287
-     * This returns the chronologically last datetime that this ticket is associated with
288
-     *
289
-     * @return EE_Datetime
290
-     * @throws \EE_Error
291
-     */
286
+	/**
287
+	 * This returns the chronologically last datetime that this ticket is associated with
288
+	 *
289
+	 * @return EE_Datetime
290
+	 * @throws \EE_Error
291
+	 */
292 292
 	public function last_datetime() {
293 293
 		$datetimes = $this->datetimes( array( 'limit' => 1, 'order_by' => array( 'DTT_EVT_start' => 'DESC' ) ) );
294 294
 		return end( $datetimes );
@@ -296,19 +296,19 @@  discard block
 block discarded – undo
296 296
 
297 297
 
298 298
 
299
-    /**
300
-     * This returns the total tickets sold depending on the given parameters.
301
-     *
302
-     * @param  string $what   Can be one of two options: 'ticket', 'datetime'.
303
-     *                        'ticket' = total ticket sales for all datetimes this ticket is related to
304
-     *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
305
-     *                        'datetime' = total ticket sales in the datetime_ticket table.
306
-     *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
307
-     *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
308
-     * @param  int    $dtt_id [optional] include the dtt_id with $what = 'datetime'.
309
-     * @return mixed (array|int)          how many tickets have sold
310
-     * @throws \EE_Error
311
-     */
299
+	/**
300
+	 * This returns the total tickets sold depending on the given parameters.
301
+	 *
302
+	 * @param  string $what   Can be one of two options: 'ticket', 'datetime'.
303
+	 *                        'ticket' = total ticket sales for all datetimes this ticket is related to
304
+	 *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
305
+	 *                        'datetime' = total ticket sales in the datetime_ticket table.
306
+	 *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
307
+	 *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
308
+	 * @param  int    $dtt_id [optional] include the dtt_id with $what = 'datetime'.
309
+	 * @return mixed (array|int)          how many tickets have sold
310
+	 * @throws \EE_Error
311
+	 */
312 312
 	public function tickets_sold( $what = 'ticket', $dtt_id = NULL ) {
313 313
 		$total = 0;
314 314
 		$tickets_sold = $this->_all_tickets_sold();
@@ -333,12 +333,12 @@  discard block
 block discarded – undo
333 333
 
334 334
 
335 335
 
336
-    /**
337
-     * This returns an array indexed by datetime_id for tickets sold with this ticket.
338
-     *
339
-     * @return EE_Ticket[]
340
-     * @throws \EE_Error
341
-     */
336
+	/**
337
+	 * This returns an array indexed by datetime_id for tickets sold with this ticket.
338
+	 *
339
+	 * @return EE_Ticket[]
340
+	 * @throws \EE_Error
341
+	 */
342 342
 	protected function _all_tickets_sold() {
343 343
 		$datetimes = $this->get_many_related( 'Datetime' );
344 344
 		$tickets_sold = array();
@@ -354,29 +354,29 @@  discard block
 block discarded – undo
354 354
 
355 355
 
356 356
 
357
-    /**
358
-     * This returns the base price object for the ticket.
359
-     *
360
-     * @param  bool $return_array whether to return as an array indexed by price id or just the object.
361
-     * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
362
-     * @throws \EE_Error
363
-     */
357
+	/**
358
+	 * This returns the base price object for the ticket.
359
+	 *
360
+	 * @param  bool $return_array whether to return as an array indexed by price id or just the object.
361
+	 * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
362
+	 * @throws \EE_Error
363
+	 */
364 364
 	public function base_price( $return_array = FALSE ) {
365 365
 		$_where = array( 'Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price );
366 366
 		return $return_array
367
-            ? $this->get_many_related( 'Price', array( $_where ) )
368
-            : $this->get_first_related( 'Price', array( $_where ) );
367
+			? $this->get_many_related( 'Price', array( $_where ) )
368
+			: $this->get_first_related( 'Price', array( $_where ) );
369 369
 	}
370 370
 
371 371
 
372 372
 
373
-    /**
374
-     * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
375
-     *
376
-     * @access public
377
-     * @return EE_Price[]
378
-     * @throws \EE_Error
379
-     */
373
+	/**
374
+	 * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
375
+	 *
376
+	 * @access public
377
+	 * @return EE_Price[]
378
+	 * @throws \EE_Error
379
+	 */
380 380
 	public function price_modifiers() {
381 381
 		$query_params = array( 0 => array( 'Price_Type.PBT_ID' => array( 'NOT IN', array( EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax ) ) ) );
382 382
 		return $this->prices( $query_params );
@@ -384,132 +384,132 @@  discard block
 block discarded – undo
384 384
 
385 385
 
386 386
 
387
-    /**
388
-     * Gets all the prices that combine to form the final price of this ticket
389
-     *
390
-     * @param array $query_params like EEM_Base::get_all
391
-     * @return EE_Price[]|EE_Base_Class[]
392
-     * @throws \EE_Error
393
-     */
387
+	/**
388
+	 * Gets all the prices that combine to form the final price of this ticket
389
+	 *
390
+	 * @param array $query_params like EEM_Base::get_all
391
+	 * @return EE_Price[]|EE_Base_Class[]
392
+	 * @throws \EE_Error
393
+	 */
394 394
 	public function prices( $query_params = array() ) {
395 395
 		return $this->get_many_related( 'Price', $query_params );
396 396
 	}
397 397
 
398 398
 
399 399
 
400
-    /**
401
-     * Gets all the ticket applicabilities (ie, relations between datetimes and tickets)
402
-     *
403
-     * @param array $query_params see EEM_Base::get_all()
404
-     * @return EE_Datetime_Ticket|EE_Base_Class[]
405
-     * @throws \EE_Error
406
-     */
400
+	/**
401
+	 * Gets all the ticket applicabilities (ie, relations between datetimes and tickets)
402
+	 *
403
+	 * @param array $query_params see EEM_Base::get_all()
404
+	 * @return EE_Datetime_Ticket|EE_Base_Class[]
405
+	 * @throws \EE_Error
406
+	 */
407 407
 	public function datetime_tickets( $query_params = array() ) {
408 408
 		return $this->get_many_related( 'Datetime_Ticket', $query_params );
409 409
 	}
410 410
 
411 411
 
412 412
 
413
-    /**
414
-     * Gets all the datetimes from the db ordered by DTT_order
415
-     *
416
-     * @param boolean $show_expired
417
-     * @param boolean $show_deleted
418
-     * @return EE_Datetime[]
419
-     * @throws \EE_Error
420
-     */
413
+	/**
414
+	 * Gets all the datetimes from the db ordered by DTT_order
415
+	 *
416
+	 * @param boolean $show_expired
417
+	 * @param boolean $show_deleted
418
+	 * @return EE_Datetime[]
419
+	 * @throws \EE_Error
420
+	 */
421 421
 	public function datetimes_ordered( $show_expired = TRUE, $show_deleted = FALSE ) {
422 422
 		return EEM_Datetime::instance( $this->_timezone )->get_datetimes_for_ticket_ordered_by_DTT_order( $this->ID(), $show_expired, $show_deleted );
423 423
 	}
424 424
 
425 425
 
426 426
 
427
-    /**
428
-     * Gets ID
429
-     *
430
-     * @return string
431
-     * @throws \EE_Error
432
-     */
427
+	/**
428
+	 * Gets ID
429
+	 *
430
+	 * @return string
431
+	 * @throws \EE_Error
432
+	 */
433 433
 	public function ID() {
434 434
 		return $this->get( 'TKT_ID' );
435 435
 	}
436 436
 
437 437
 
438 438
 
439
-    /**
440
-     * get the author of the ticket.
441
-     *
442
-     * @since 4.5.0
443
-     * @return int
444
-     * @throws \EE_Error
445
-     */
439
+	/**
440
+	 * get the author of the ticket.
441
+	 *
442
+	 * @since 4.5.0
443
+	 * @return int
444
+	 * @throws \EE_Error
445
+	 */
446 446
 	public function wp_user() {
447 447
 		return $this->get('TKT_wp_user');
448 448
 	}
449 449
 
450 450
 
451 451
 
452
-    /**
453
-     * Gets the template for the ticket
454
-     *
455
-     * @return EE_Ticket_Template|EE_Base_Class
456
-     * @throws \EE_Error
457
-     */
452
+	/**
453
+	 * Gets the template for the ticket
454
+	 *
455
+	 * @return EE_Ticket_Template|EE_Base_Class
456
+	 * @throws \EE_Error
457
+	 */
458 458
 	public function template() {
459 459
 		return $this->get_first_related( 'Ticket_Template' );
460 460
 	}
461 461
 
462 462
 
463 463
 
464
-    /**
465
-     * Simply returns an array of EE_Price objects that are taxes.
466
-     *
467
-     * @return EE_Price[]
468
-     * @throws \EE_Error
469
-     */
464
+	/**
465
+	 * Simply returns an array of EE_Price objects that are taxes.
466
+	 *
467
+	 * @return EE_Price[]
468
+	 * @throws \EE_Error
469
+	 */
470 470
 	public function get_ticket_taxes_for_admin() {
471 471
 		return EE_Taxes::get_taxes_for_admin();
472 472
 	}
473 473
 
474 474
 
475 475
 
476
-    /**
477
-     * @return float
478
-     * @throws \EE_Error
479
-     */
476
+	/**
477
+	 * @return float
478
+	 * @throws \EE_Error
479
+	 */
480 480
 	public function ticket_price() {
481 481
 		return $this->get( 'TKT_price' );
482 482
 	}
483 483
 
484 484
 
485 485
 
486
-    /**
487
-     * @return mixed
488
-     * @throws \EE_Error
489
-     */
486
+	/**
487
+	 * @return mixed
488
+	 * @throws \EE_Error
489
+	 */
490 490
 	public function pretty_price() {
491 491
 		return $this->get_pretty( 'TKT_price' );
492 492
 	}
493 493
 
494 494
 
495 495
 
496
-    /**
497
-     * @return bool
498
-     * @throws \EE_Error
499
-     */
496
+	/**
497
+	 * @return bool
498
+	 * @throws \EE_Error
499
+	 */
500 500
 	public function is_free() {
501 501
 		return $this->get_ticket_total_with_taxes() === (float) 0;
502 502
 	}
503 503
 
504 504
 
505 505
 
506
-    /**
507
-     * get_ticket_total_with_taxes
508
-     *
509
-     * @param bool $no_cache
510
-     * @return float
511
-     * @throws \EE_Error
512
-     */
506
+	/**
507
+	 * get_ticket_total_with_taxes
508
+	 *
509
+	 * @param bool $no_cache
510
+	 * @return float
511
+	 * @throws \EE_Error
512
+	 */
513 513
 	public function get_ticket_total_with_taxes( $no_cache = FALSE ) {
514 514
 		if ($this->_ticket_total_with_taxes === null || $no_cache ) {
515 515
 			$this->_ticket_total_with_taxes = $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin();
@@ -526,201 +526,201 @@  discard block
 block discarded – undo
526 526
 
527 527
 
528 528
 
529
-    /**
530
-     * @return float
531
-     * @throws \EE_Error
532
-     */
529
+	/**
530
+	 * @return float
531
+	 * @throws \EE_Error
532
+	 */
533 533
 	public function get_ticket_subtotal() {
534 534
 		return EE_Taxes::get_subtotal_for_admin( $this );
535 535
 	}
536 536
 
537 537
 
538 538
 
539
-    /**
540
-     * Returns the total taxes applied to this ticket
541
-     *
542
-     * @return float
543
-     * @throws \EE_Error
544
-     */
539
+	/**
540
+	 * Returns the total taxes applied to this ticket
541
+	 *
542
+	 * @return float
543
+	 * @throws \EE_Error
544
+	 */
545 545
 	public function get_ticket_taxes_total_for_admin() {
546 546
 		return EE_Taxes::get_total_taxes_for_admin( $this );
547 547
 	}
548 548
 
549 549
 
550 550
 
551
-    /**
552
-     * Sets name
553
-     *
554
-     * @param string $name
555
-     * @throws \EE_Error
556
-     */
551
+	/**
552
+	 * Sets name
553
+	 *
554
+	 * @param string $name
555
+	 * @throws \EE_Error
556
+	 */
557 557
 	public function set_name( $name ) {
558 558
 		$this->set( 'TKT_name', $name );
559 559
 	}
560 560
 
561 561
 
562 562
 
563
-    /**
564
-     * Gets description
565
-     *
566
-     * @return string
567
-     * @throws \EE_Error
568
-     */
563
+	/**
564
+	 * Gets description
565
+	 *
566
+	 * @return string
567
+	 * @throws \EE_Error
568
+	 */
569 569
 	public function description() {
570 570
 		return $this->get( 'TKT_description' );
571 571
 	}
572 572
 
573 573
 
574 574
 
575
-    /**
576
-     * Sets description
577
-     *
578
-     * @param string $description
579
-     * @throws \EE_Error
580
-     */
575
+	/**
576
+	 * Sets description
577
+	 *
578
+	 * @param string $description
579
+	 * @throws \EE_Error
580
+	 */
581 581
 	public function set_description( $description ) {
582 582
 		$this->set( 'TKT_description', $description );
583 583
 	}
584 584
 
585 585
 
586 586
 
587
-    /**
588
-     * Gets start_date
589
-     *
590
-     * @param string $dt_frmt
591
-     * @param string $tm_frmt
592
-     * @return string
593
-     * @throws \EE_Error
594
-     */
587
+	/**
588
+	 * Gets start_date
589
+	 *
590
+	 * @param string $dt_frmt
591
+	 * @param string $tm_frmt
592
+	 * @return string
593
+	 * @throws \EE_Error
594
+	 */
595 595
 	public function start_date( $dt_frmt = '', $tm_frmt = '' ) {
596 596
 		return $this->_get_datetime( 'TKT_start_date', $dt_frmt, $tm_frmt );
597 597
 	}
598 598
 
599 599
 
600 600
 
601
-    /**
602
-     * Sets start_date
603
-     *
604
-     * @param string $start_date
605
-     * @return void
606
-     * @throws \EE_Error
607
-     */
601
+	/**
602
+	 * Sets start_date
603
+	 *
604
+	 * @param string $start_date
605
+	 * @return void
606
+	 * @throws \EE_Error
607
+	 */
608 608
 	public function set_start_date( $start_date ) {
609 609
 		$this->_set_date_time( 'B', $start_date, 'TKT_start_date' );
610 610
 	}
611 611
 
612 612
 
613 613
 
614
-    /**
615
-     * Gets end_date
616
-     *
617
-     * @param string $dt_frmt
618
-     * @param string $tm_frmt
619
-     * @return string
620
-     * @throws \EE_Error
621
-     */
614
+	/**
615
+	 * Gets end_date
616
+	 *
617
+	 * @param string $dt_frmt
618
+	 * @param string $tm_frmt
619
+	 * @return string
620
+	 * @throws \EE_Error
621
+	 */
622 622
 	public function end_date( $dt_frmt = '', $tm_frmt = '' ) {
623 623
 		return $this->_get_datetime( 'TKT_end_date', $dt_frmt, $tm_frmt );
624 624
 	}
625 625
 
626 626
 
627 627
 
628
-    /**
629
-     * Sets end_date
630
-     *
631
-     * @param string $end_date
632
-     * @return void
633
-     * @throws \EE_Error
634
-     */
628
+	/**
629
+	 * Sets end_date
630
+	 *
631
+	 * @param string $end_date
632
+	 * @return void
633
+	 * @throws \EE_Error
634
+	 */
635 635
 	public function set_end_date( $end_date ) {
636 636
 		$this->_set_date_time( 'B', $end_date, 'TKT_end_date' );
637 637
 	}
638 638
 
639 639
 
640 640
 
641
-    /**
642
-     * Sets sell until time
643
-     *
644
-     * @since 4.5.0
645
-     * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
646
-     * @throws \EE_Error
647
-     */
641
+	/**
642
+	 * Sets sell until time
643
+	 *
644
+	 * @since 4.5.0
645
+	 * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
646
+	 * @throws \EE_Error
647
+	 */
648 648
 	public function set_end_time( $time ) {
649 649
 		$this->_set_time_for( $time, 'TKT_end_date' );
650 650
 	}
651 651
 
652 652
 
653 653
 
654
-    /**
655
-     * Sets min
656
-     *
657
-     * @param int $min
658
-     * @return void
659
-     * @throws \EE_Error
660
-     */
654
+	/**
655
+	 * Sets min
656
+	 *
657
+	 * @param int $min
658
+	 * @return void
659
+	 * @throws \EE_Error
660
+	 */
661 661
 	public function set_min( $min ) {
662 662
 		$this->set( 'TKT_min', $min );
663 663
 	}
664 664
 
665 665
 
666 666
 
667
-    /**
668
-     * Gets max
669
-     *
670
-     * @return int
671
-     * @throws \EE_Error
672
-     */
667
+	/**
668
+	 * Gets max
669
+	 *
670
+	 * @return int
671
+	 * @throws \EE_Error
672
+	 */
673 673
 	public function max() {
674 674
 		return $this->get( 'TKT_max' );
675 675
 	}
676 676
 
677 677
 
678 678
 
679
-    /**
680
-     * Sets max
681
-     *
682
-     * @param int $max
683
-     * @return void
684
-     * @throws \EE_Error
685
-     */
679
+	/**
680
+	 * Sets max
681
+	 *
682
+	 * @param int $max
683
+	 * @return void
684
+	 * @throws \EE_Error
685
+	 */
686 686
 	public function set_max( $max ) {
687 687
 		$this->set( 'TKT_max', $max );
688 688
 	}
689 689
 
690 690
 
691 691
 
692
-    /**
693
-     * Sets price
694
-     *
695
-     * @param float $price
696
-     * @return void
697
-     * @throws \EE_Error
698
-     */
692
+	/**
693
+	 * Sets price
694
+	 *
695
+	 * @param float $price
696
+	 * @return void
697
+	 * @throws \EE_Error
698
+	 */
699 699
 	public function set_price( $price ) {
700 700
 		$this->set( 'TKT_price', $price );
701 701
 	}
702 702
 
703 703
 
704 704
 
705
-    /**
706
-     * Gets sold
707
-     *
708
-     * @return int
709
-     * @throws \EE_Error
710
-     */
705
+	/**
706
+	 * Gets sold
707
+	 *
708
+	 * @return int
709
+	 * @throws \EE_Error
710
+	 */
711 711
 	public function sold() {
712 712
 		return $this->get_raw( 'TKT_sold' );
713 713
 	}
714 714
 
715 715
 
716 716
 
717
-    /**
718
-     * Sets sold
719
-     *
720
-     * @param int $sold
721
-     * @return void
722
-     * @throws \EE_Error
723
-     */
717
+	/**
718
+	 * Sets sold
719
+	 *
720
+	 * @param int $sold
721
+	 * @return void
722
+	 * @throws \EE_Error
723
+	 */
724 724
 	public function set_sold( $sold ) {
725 725
 		// sold can not go below zero
726 726
 		$sold = max( 0, $sold );
@@ -729,13 +729,13 @@  discard block
 block discarded – undo
729 729
 
730 730
 
731 731
 
732
-    /**
733
-     * increments sold by amount passed by $qty
734
-     *
735
-     * @param int $qty
736
-     * @return void
737
-     * @throws \EE_Error
738
-     */
732
+	/**
733
+	 * increments sold by amount passed by $qty
734
+	 *
735
+	 * @param int $qty
736
+	 * @return void
737
+	 * @throws \EE_Error
738
+	 */
739 739
 	public function increase_sold( $qty = 1 ) {
740 740
 		$sold = $this->sold() + $qty;
741 741
 		// remove ticket reservation, but don't adjust datetime reservations,  because that will happen
@@ -747,13 +747,13 @@  discard block
 block discarded – undo
747 747
 
748 748
 
749 749
 
750
-    /**
751
-     * Increases sold on related datetimes
752
-     *
753
-     * @param int $qty
754
-     * @return void
755
-     * @throws \EE_Error
756
-     */
750
+	/**
751
+	 * Increases sold on related datetimes
752
+	 *
753
+	 * @param int $qty
754
+	 * @return void
755
+	 * @throws \EE_Error
756
+	 */
757 757
 	protected function _increase_sold_for_datetimes( $qty = 1 ) {
758 758
 		$datetimes = $this->datetimes();
759 759
 		if ( is_array( $datetimes ) ) {
@@ -768,13 +768,13 @@  discard block
 block discarded – undo
768 768
 
769 769
 
770 770
 
771
-    /**
772
-     * decrements (subtracts) sold by amount passed by $qty
773
-     *
774
-     * @param int $qty
775
-     * @return void
776
-     * @throws \EE_Error
777
-     */
771
+	/**
772
+	 * decrements (subtracts) sold by amount passed by $qty
773
+	 *
774
+	 * @param int $qty
775
+	 * @return void
776
+	 * @throws \EE_Error
777
+	 */
778 778
 	public function decrease_sold( $qty = 1 ) {
779 779
 		$sold = $this->sold() - $qty;
780 780
 		$this->_decrease_sold_for_datetimes( $qty );
@@ -783,13 +783,13 @@  discard block
 block discarded – undo
783 783
 
784 784
 
785 785
 
786
-    /**
787
-     * Decreases sold on related datetimes
788
-     *
789
-     * @param int $qty
790
-     * @return void
791
-     * @throws \EE_Error
792
-     */
786
+	/**
787
+	 * Decreases sold on related datetimes
788
+	 *
789
+	 * @param int $qty
790
+	 * @return void
791
+	 * @throws \EE_Error
792
+	 */
793 793
 	protected function _decrease_sold_for_datetimes( $qty = 1 ) {
794 794
 		$datetimes = $this->datetimes();
795 795
 		if ( is_array( $datetimes ) ) {
@@ -804,25 +804,25 @@  discard block
 block discarded – undo
804 804
 
805 805
 
806 806
 
807
-    /**
808
-     * Gets qty of reserved tickets
809
-     *
810
-     * @return int
811
-     * @throws \EE_Error
812
-     */
807
+	/**
808
+	 * Gets qty of reserved tickets
809
+	 *
810
+	 * @return int
811
+	 * @throws \EE_Error
812
+	 */
813 813
 	public function reserved() {
814 814
 		return $this->get_raw( 'TKT_reserved' );
815 815
 	}
816 816
 
817 817
 
818 818
 
819
-    /**
820
-     * Sets reserved
821
-     *
822
-     * @param int $reserved
823
-     * @return void
824
-     * @throws \EE_Error
825
-     */
819
+	/**
820
+	 * Sets reserved
821
+	 *
822
+	 * @param int $reserved
823
+	 * @return void
824
+	 * @throws \EE_Error
825
+	 */
826 826
 	public function set_reserved( $reserved ) {
827 827
 		// reserved can not go below zero
828 828
 		$reserved = max( 0, (int) $reserved );
@@ -831,13 +831,13 @@  discard block
 block discarded – undo
831 831
 
832 832
 
833 833
 
834
-    /**
835
-     * increments reserved by amount passed by $qty
836
-     *
837
-     * @param int $qty
838
-     * @return void
839
-     * @throws \EE_Error
840
-     */
834
+	/**
835
+	 * increments reserved by amount passed by $qty
836
+	 *
837
+	 * @param int $qty
838
+	 * @return void
839
+	 * @throws \EE_Error
840
+	 */
841 841
 	public function increase_reserved( $qty = 1 ) {
842 842
 		$qty = absint( $qty );
843 843
 		$reserved = $this->reserved() + $qty;
@@ -847,13 +847,13 @@  discard block
 block discarded – undo
847 847
 
848 848
 
849 849
 
850
-    /**
851
-     * Increases sold on related datetimes
852
-     *
853
-     * @param int $qty
854
-     * @return void
855
-     * @throws \EE_Error
856
-     */
850
+	/**
851
+	 * Increases sold on related datetimes
852
+	 *
853
+	 * @param int $qty
854
+	 * @return void
855
+	 * @throws \EE_Error
856
+	 */
857 857
 	protected function _increase_reserved_for_datetimes( $qty = 1 ) {
858 858
 		$datetimes = $this->datetimes();
859 859
 		if ( is_array( $datetimes ) ) {
@@ -868,14 +868,14 @@  discard block
 block discarded – undo
868 868
 
869 869
 
870 870
 
871
-    /**
872
-     * decrements (subtracts) reserved by amount passed by $qty
873
-     *
874
-     * @param int  $qty
875
-     * @param bool $adjust_datetimes
876
-     * @return void
877
-     * @throws \EE_Error
878
-     */
871
+	/**
872
+	 * decrements (subtracts) reserved by amount passed by $qty
873
+	 *
874
+	 * @param int  $qty
875
+	 * @param bool $adjust_datetimes
876
+	 * @return void
877
+	 * @throws \EE_Error
878
+	 */
879 879
 	public function decrease_reserved( $qty = 1, $adjust_datetimes = true ) {
880 880
 		$reserved = $this->reserved() - absint( $qty );
881 881
 		if ( $adjust_datetimes ) {
@@ -886,13 +886,13 @@  discard block
 block discarded – undo
886 886
 
887 887
 
888 888
 
889
-    /**
890
-     * Increases sold on related datetimes
891
-     *
892
-     * @param int $qty
893
-     * @return void
894
-     * @throws \EE_Error
895
-     */
889
+	/**
890
+	 * Increases sold on related datetimes
891
+	 *
892
+	 * @param int $qty
893
+	 * @return void
894
+	 * @throws \EE_Error
895
+	 */
896 896
 	protected function _decrease_reserved_for_datetimes( $qty = 1 ) {
897 897
 		$datetimes = $this->datetimes();
898 898
 		if ( is_array( $datetimes ) ) {
@@ -907,18 +907,18 @@  discard block
 block discarded – undo
907 907
 
908 908
 
909 909
 
910
-    /**
911
-     * Gets ticket quantity
912
-     *
913
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
914
-     *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
915
-     *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
916
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
917
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
918
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
919
-     * @return int
920
-     * @throws \EE_Error
921
-     */
910
+	/**
911
+	 * Gets ticket quantity
912
+	 *
913
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
914
+	 *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
915
+	 *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
916
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
917
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
918
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
919
+	 * @return int
920
+	 * @throws \EE_Error
921
+	 */
922 922
 	public function qty( $context = '' ) {
923 923
 		switch ( $context ) {
924 924
 			case 'reg_limit' :
@@ -932,19 +932,19 @@  discard block
 block discarded – undo
932 932
 
933 933
 
934 934
 
935
-    /**
936
-     * Gets ticket quantity
937
-     *
938
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
939
-     *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
940
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
941
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
942
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
943
-     * @param  int   $DTT_ID      the primary key for a particular datetime.
944
-     *                            set to 0 for all related datetimes
945
-     * @return int
946
-     * @throws \EE_Error
947
-     */
935
+	/**
936
+	 * Gets ticket quantity
937
+	 *
938
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
939
+	 *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
940
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
941
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
942
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
943
+	 * @param  int   $DTT_ID      the primary key for a particular datetime.
944
+	 *                            set to 0 for all related datetimes
945
+	 * @return int
946
+	 * @throws \EE_Error
947
+	 */
948 948
 	public function real_quantity_on_ticket( $context = 'reg_limit', $DTT_ID = 0 ) {
949 949
 		$raw = $this->get_raw( 'TKT_qty' );
950 950
 		// return immediately if it's zero
@@ -1027,212 +1027,212 @@  discard block
 block discarded – undo
1027 1027
 
1028 1028
 
1029 1029
 
1030
-    /**
1031
-     * Gets uses
1032
-     *
1033
-     * @return int
1034
-     * @throws \EE_Error
1035
-     */
1030
+	/**
1031
+	 * Gets uses
1032
+	 *
1033
+	 * @return int
1034
+	 * @throws \EE_Error
1035
+	 */
1036 1036
 	public function uses() {
1037 1037
 		return $this->get( 'TKT_uses' );
1038 1038
 	}
1039 1039
 
1040 1040
 
1041 1041
 
1042
-    /**
1043
-     * Sets uses
1044
-     *
1045
-     * @param int $uses
1046
-     * @return void
1047
-     * @throws \EE_Error
1048
-     */
1042
+	/**
1043
+	 * Sets uses
1044
+	 *
1045
+	 * @param int $uses
1046
+	 * @return void
1047
+	 * @throws \EE_Error
1048
+	 */
1049 1049
 	public function set_uses( $uses ) {
1050 1050
 		$this->set( 'TKT_uses', $uses );
1051 1051
 	}
1052 1052
 
1053 1053
 
1054 1054
 
1055
-    /**
1056
-     * returns whether ticket is required or not.
1057
-     *
1058
-     * @return boolean
1059
-     * @throws \EE_Error
1060
-     */
1055
+	/**
1056
+	 * returns whether ticket is required or not.
1057
+	 *
1058
+	 * @return boolean
1059
+	 * @throws \EE_Error
1060
+	 */
1061 1061
 	public function required() {
1062 1062
 		return $this->get( 'TKT_required' );
1063 1063
 	}
1064 1064
 
1065 1065
 
1066 1066
 
1067
-    /**
1068
-     * sets the TKT_required property
1069
-     *
1070
-     * @param boolean $required
1071
-     * @return void
1072
-     * @throws \EE_Error
1073
-     */
1067
+	/**
1068
+	 * sets the TKT_required property
1069
+	 *
1070
+	 * @param boolean $required
1071
+	 * @return void
1072
+	 * @throws \EE_Error
1073
+	 */
1074 1074
 	public function set_required( $required ) {
1075 1075
 		$this->set( 'TKT_required', $required );
1076 1076
 	}
1077 1077
 
1078 1078
 
1079 1079
 
1080
-    /**
1081
-     * Gets taxable
1082
-     *
1083
-     * @return boolean
1084
-     * @throws \EE_Error
1085
-     */
1080
+	/**
1081
+	 * Gets taxable
1082
+	 *
1083
+	 * @return boolean
1084
+	 * @throws \EE_Error
1085
+	 */
1086 1086
 	public function taxable() {
1087 1087
 		return $this->get( 'TKT_taxable' );
1088 1088
 	}
1089 1089
 
1090 1090
 
1091 1091
 
1092
-    /**
1093
-     * Sets taxable
1094
-     *
1095
-     * @param boolean $taxable
1096
-     * @return void
1097
-     * @throws \EE_Error
1098
-     */
1092
+	/**
1093
+	 * Sets taxable
1094
+	 *
1095
+	 * @param boolean $taxable
1096
+	 * @return void
1097
+	 * @throws \EE_Error
1098
+	 */
1099 1099
 	public function set_taxable( $taxable ) {
1100 1100
 		$this->set( 'TKT_taxable', $taxable );
1101 1101
 	}
1102 1102
 
1103 1103
 
1104 1104
 
1105
-    /**
1106
-     * Gets is_default
1107
-     *
1108
-     * @return boolean
1109
-     * @throws \EE_Error
1110
-     */
1105
+	/**
1106
+	 * Gets is_default
1107
+	 *
1108
+	 * @return boolean
1109
+	 * @throws \EE_Error
1110
+	 */
1111 1111
 	public function is_default() {
1112 1112
 		return $this->get( 'TKT_is_default' );
1113 1113
 	}
1114 1114
 
1115 1115
 
1116 1116
 
1117
-    /**
1118
-     * Sets is_default
1119
-     *
1120
-     * @param boolean $is_default
1121
-     * @return void
1122
-     * @throws \EE_Error
1123
-     */
1117
+	/**
1118
+	 * Sets is_default
1119
+	 *
1120
+	 * @param boolean $is_default
1121
+	 * @return void
1122
+	 * @throws \EE_Error
1123
+	 */
1124 1124
 	public function set_is_default( $is_default ) {
1125 1125
 		$this->set( 'TKT_is_default', $is_default );
1126 1126
 	}
1127 1127
 
1128 1128
 
1129 1129
 
1130
-    /**
1131
-     * Gets order
1132
-     *
1133
-     * @return int
1134
-     * @throws \EE_Error
1135
-     */
1130
+	/**
1131
+	 * Gets order
1132
+	 *
1133
+	 * @return int
1134
+	 * @throws \EE_Error
1135
+	 */
1136 1136
 	public function order() {
1137 1137
 		return $this->get( 'TKT_order' );
1138 1138
 	}
1139 1139
 
1140 1140
 
1141 1141
 
1142
-    /**
1143
-     * Sets order
1144
-     *
1145
-     * @param int $order
1146
-     * @return void
1147
-     * @throws \EE_Error
1148
-     */
1142
+	/**
1143
+	 * Sets order
1144
+	 *
1145
+	 * @param int $order
1146
+	 * @return void
1147
+	 * @throws \EE_Error
1148
+	 */
1149 1149
 	public function set_order( $order ) {
1150 1150
 		$this->set( 'TKT_order', $order );
1151 1151
 	}
1152 1152
 
1153 1153
 
1154 1154
 
1155
-    /**
1156
-     * Gets row
1157
-     *
1158
-     * @return int
1159
-     * @throws \EE_Error
1160
-     */
1155
+	/**
1156
+	 * Gets row
1157
+	 *
1158
+	 * @return int
1159
+	 * @throws \EE_Error
1160
+	 */
1161 1161
 	public function row() {
1162 1162
 		return $this->get( 'TKT_row' );
1163 1163
 	}
1164 1164
 
1165 1165
 
1166 1166
 
1167
-    /**
1168
-     * Sets row
1169
-     *
1170
-     * @param int $row
1171
-     * @return void
1172
-     * @throws \EE_Error
1173
-     */
1167
+	/**
1168
+	 * Sets row
1169
+	 *
1170
+	 * @param int $row
1171
+	 * @return void
1172
+	 * @throws \EE_Error
1173
+	 */
1174 1174
 	public function set_row( $row ) {
1175 1175
 		$this->set( 'TKT_row', $row );
1176 1176
 	}
1177 1177
 
1178 1178
 
1179 1179
 
1180
-    /**
1181
-     * Gets deleted
1182
-     *
1183
-     * @return boolean
1184
-     * @throws \EE_Error
1185
-     */
1180
+	/**
1181
+	 * Gets deleted
1182
+	 *
1183
+	 * @return boolean
1184
+	 * @throws \EE_Error
1185
+	 */
1186 1186
 	public function deleted() {
1187 1187
 		return $this->get( 'TKT_deleted' );
1188 1188
 	}
1189 1189
 
1190 1190
 
1191 1191
 
1192
-    /**
1193
-     * Sets deleted
1194
-     *
1195
-     * @param boolean $deleted
1196
-     * @return void
1197
-     * @throws \EE_Error
1198
-     */
1192
+	/**
1193
+	 * Sets deleted
1194
+	 *
1195
+	 * @param boolean $deleted
1196
+	 * @return void
1197
+	 * @throws \EE_Error
1198
+	 */
1199 1199
 	public function set_deleted( $deleted ) {
1200 1200
 		$this->set( 'TKT_deleted', $deleted );
1201 1201
 	}
1202 1202
 
1203 1203
 
1204 1204
 
1205
-    /**
1206
-     * Gets parent
1207
-     *
1208
-     * @return int
1209
-     * @throws \EE_Error
1210
-     */
1205
+	/**
1206
+	 * Gets parent
1207
+	 *
1208
+	 * @return int
1209
+	 * @throws \EE_Error
1210
+	 */
1211 1211
 	public function parent_ID() {
1212 1212
 		return $this->get( 'TKT_parent' );
1213 1213
 	}
1214 1214
 
1215 1215
 
1216 1216
 
1217
-    /**
1218
-     * Sets parent
1219
-     *
1220
-     * @param int $parent
1221
-     * @return void
1222
-     * @throws \EE_Error
1223
-     */
1217
+	/**
1218
+	 * Sets parent
1219
+	 *
1220
+	 * @param int $parent
1221
+	 * @return void
1222
+	 * @throws \EE_Error
1223
+	 */
1224 1224
 	public function set_parent_ID( $parent ) {
1225 1225
 		$this->set( 'TKT_parent', $parent );
1226 1226
 	}
1227 1227
 
1228 1228
 
1229 1229
 
1230
-    /**
1231
-     * Gets a string which is handy for showing in gateways etc that describes the ticket.
1232
-     *
1233
-     * @return string
1234
-     * @throws \EE_Error
1235
-     */
1230
+	/**
1231
+	 * Gets a string which is handy for showing in gateways etc that describes the ticket.
1232
+	 *
1233
+	 * @return string
1234
+	 * @throws \EE_Error
1235
+	 */
1236 1236
 	public function name_and_info() {
1237 1237
 		$times = array();
1238 1238
 		foreach ( $this->datetimes() as $datetime ) {
@@ -1243,67 +1243,67 @@  discard block
 block discarded – undo
1243 1243
 
1244 1244
 
1245 1245
 
1246
-    /**
1247
-     * Gets name
1248
-     *
1249
-     * @return string
1250
-     * @throws \EE_Error
1251
-     */
1246
+	/**
1247
+	 * Gets name
1248
+	 *
1249
+	 * @return string
1250
+	 * @throws \EE_Error
1251
+	 */
1252 1252
 	public function name() {
1253 1253
 		return $this->get( 'TKT_name' );
1254 1254
 	}
1255 1255
 
1256 1256
 
1257 1257
 
1258
-    /**
1259
-     * Gets price
1260
-     *
1261
-     * @return float
1262
-     * @throws \EE_Error
1263
-     */
1258
+	/**
1259
+	 * Gets price
1260
+	 *
1261
+	 * @return float
1262
+	 * @throws \EE_Error
1263
+	 */
1264 1264
 	public function price() {
1265 1265
 		return $this->get( 'TKT_price' );
1266 1266
 	}
1267 1267
 
1268 1268
 
1269 1269
 
1270
-    /**
1271
-     * Gets all the registrations for this ticket
1272
-     *
1273
-     * @param array $query_params like EEM_Base::get_all's
1274
-     * @return EE_Registration[]|EE_Base_Class[]
1275
-     * @throws \EE_Error
1276
-     */
1270
+	/**
1271
+	 * Gets all the registrations for this ticket
1272
+	 *
1273
+	 * @param array $query_params like EEM_Base::get_all's
1274
+	 * @return EE_Registration[]|EE_Base_Class[]
1275
+	 * @throws \EE_Error
1276
+	 */
1277 1277
 	public function registrations( $query_params = array() ) {
1278 1278
 		return $this->get_many_related( 'Registration', $query_params );
1279 1279
 	}
1280 1280
 
1281 1281
 
1282 1282
 
1283
-    /**
1284
-     * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1285
-     * into account
1286
-     *
1287
-     * @return int
1288
-     * @throws \EE_Error
1289
-     */
1283
+	/**
1284
+	 * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1285
+	 * into account
1286
+	 *
1287
+	 * @return int
1288
+	 * @throws \EE_Error
1289
+	 */
1290 1290
 	public function update_tickets_sold() {
1291
-        $count_regs_for_this_ticket = $this->count_registrations(
1292
-            array(
1293
-                array(
1294
-                    'STS_ID'      => EEM_Registration::status_id_approved,
1295
-                    'REG_deleted' => 0,
1296
-                ),
1297
-            )
1298
-        );
1299
-        $sold = $this->sold();
1300
-        if ($count_regs_for_this_ticket > $sold) {
1301
-            $this->increase_sold($count_regs_for_this_ticket - $sold);
1302
-            $this->save();
1303
-        } else if ($count_regs_for_this_ticket < $sold) {
1304
-            $this->decrease_sold($count_regs_for_this_ticket - $sold);
1305
-            $this->save();
1306
-        }
1291
+		$count_regs_for_this_ticket = $this->count_registrations(
1292
+			array(
1293
+				array(
1294
+					'STS_ID'      => EEM_Registration::status_id_approved,
1295
+					'REG_deleted' => 0,
1296
+				),
1297
+			)
1298
+		);
1299
+		$sold = $this->sold();
1300
+		if ($count_regs_for_this_ticket > $sold) {
1301
+			$this->increase_sold($count_regs_for_this_ticket - $sold);
1302
+			$this->save();
1303
+		} else if ($count_regs_for_this_ticket < $sold) {
1304
+			$this->decrease_sold($count_regs_for_this_ticket - $sold);
1305
+			$this->save();
1306
+		}
1307 1307
 		return $count_regs_for_this_ticket;
1308 1308
 	}
1309 1309
 
@@ -1331,21 +1331,21 @@  discard block
 block discarded – undo
1331 1331
 
1332 1332
 
1333 1333
 
1334
-    /**
1335
-     * Implementation of the EEI_Event_Relation interface method
1336
-     *
1337
-     * @see EEI_Event_Relation for comments
1338
-     * @return EE_Event
1339
-     * @throws \EE_Error
1340
-     * @throws UnexpectedEntityException
1341
-     */
1334
+	/**
1335
+	 * Implementation of the EEI_Event_Relation interface method
1336
+	 *
1337
+	 * @see EEI_Event_Relation for comments
1338
+	 * @return EE_Event
1339
+	 * @throws \EE_Error
1340
+	 * @throws UnexpectedEntityException
1341
+	 */
1342 1342
 	public function get_related_event() {
1343 1343
 		//get one datetime to use for getting the event
1344 1344
 		$datetime = $this->first_datetime();
1345 1345
 		if ( ! $datetime instanceof \EE_Datetime ) {
1346 1346
 			throw new UnexpectedEntityException(
1347 1347
 				$datetime,
1348
-                'EE_Datetime',
1348
+				'EE_Datetime',
1349 1349
 				sprintf(
1350 1350
 					__( 'The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1351 1351
 					$this->name()
@@ -1356,7 +1356,7 @@  discard block
 block discarded – undo
1356 1356
 		if ( ! $event instanceof \EE_Event ) {
1357 1357
 			throw new UnexpectedEntityException(
1358 1358
 				$event,
1359
-                'EE_Event',
1359
+				'EE_Event',
1360 1360
 				sprintf(
1361 1361
 					__( 'The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1362 1362
 					$this->name()
@@ -1368,14 +1368,14 @@  discard block
 block discarded – undo
1368 1368
 
1369 1369
 
1370 1370
 
1371
-    /**
1372
-     * Implementation of the EEI_Event_Relation interface method
1373
-     *
1374
-     * @see EEI_Event_Relation for comments
1375
-     * @return string
1376
-     * @throws UnexpectedEntityException
1377
-     * @throws \EE_Error
1378
-     */
1371
+	/**
1372
+	 * Implementation of the EEI_Event_Relation interface method
1373
+	 *
1374
+	 * @see EEI_Event_Relation for comments
1375
+	 * @return string
1376
+	 * @throws UnexpectedEntityException
1377
+	 * @throws \EE_Error
1378
+	 */
1379 1379
 	public function get_event_name() {
1380 1380
 		$event = $this->get_related_event();
1381 1381
 		return $event instanceof EE_Event ? $event->name() : '';
@@ -1383,28 +1383,28 @@  discard block
 block discarded – undo
1383 1383
 
1384 1384
 
1385 1385
 
1386
-    /**
1387
-     * Implementation of the EEI_Event_Relation interface method
1388
-     *
1389
-     * @see EEI_Event_Relation for comments
1390
-     * @return int
1391
-     * @throws UnexpectedEntityException
1392
-     * @throws \EE_Error
1393
-     */
1386
+	/**
1387
+	 * Implementation of the EEI_Event_Relation interface method
1388
+	 *
1389
+	 * @see EEI_Event_Relation for comments
1390
+	 * @return int
1391
+	 * @throws UnexpectedEntityException
1392
+	 * @throws \EE_Error
1393
+	 */
1394 1394
 	public function get_event_ID() {
1395 1395
 		$event = $this->get_related_event();
1396 1396
 		return $event instanceof EE_Event ? $event->ID() : 0;
1397 1397
 	}
1398 1398
 
1399 1399
 
1400
-    /**
1401
-     * This simply returns whether a ticket can be permanently deleted or not.
1402
-     * The criteria for determining this is whether the ticket has any related registrations.
1403
-     * If there are none then it can be permanently deleted.
1404
-     *
1405
-     * @return bool
1406
-     */
1400
+	/**
1401
+	 * This simply returns whether a ticket can be permanently deleted or not.
1402
+	 * The criteria for determining this is whether the ticket has any related registrations.
1403
+	 * If there are none then it can be permanently deleted.
1404
+	 *
1405
+	 * @return bool
1406
+	 */
1407 1407
 	public function is_permanently_deleteable() {
1408
-	    return $this->count_registrations() === 0;
1409
-    }
1408
+		return $this->count_registrations() === 0;
1409
+	}
1410 1410
 } //end EE_Ticket class
Please login to merge, or discard this patch.
caffeinated/admin/new/pricing/espresso_events_Pricing_Hooks.class.php 2 patches
Indentation   +2108 added lines, -2108 removed lines patch added patch discarded remove patch
@@ -15,2114 +15,2114 @@
 block discarded – undo
15 15
 class espresso_events_Pricing_Hooks extends EE_Admin_Hooks
16 16
 {
17 17
 
18
-    /**
19
-     * This property is just used to hold the status of whether an event is currently being
20
-     * created (true) or edited (false)
21
-     *
22
-     * @access protected
23
-     * @var bool
24
-     */
25
-    protected $_is_creating_event;
26
-
27
-
28
-    /**
29
-     * Used to contain the format strings for date and time that will be used for php date and
30
-     * time.
31
-     * Is set in the _set_hooks_properties() method.
32
-     *
33
-     * @var array
34
-     */
35
-    protected $_date_format_strings;
36
-
37
-
38
-    /**
39
-     * @var string $_date_time_format
40
-     */
41
-    protected $_date_time_format;
42
-
43
-
44
-
45
-    /**
46
-     *
47
-     */
48
-    protected function _set_hooks_properties()
49
-    {
50
-        $this->_name = 'pricing';
51
-        //capability check
52
-        if (! EE_Registry::instance()->CAP->current_user_can(
53
-            'ee_read_default_prices',
54
-            'advanced_ticket_datetime_metabox'
55
-        )) {
56
-            return;
57
-        }
58
-        $this->_setup_metaboxes();
59
-        $this->_set_date_time_formats();
60
-        $this->_validate_format_strings();
61
-        $this->_set_scripts_styles();
62
-        // commented out temporarily until logic is implemented in callback
63
-        // add_action(
64
-        //     'AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_Extend_Events_Admin_Page',
65
-        //     array($this, 'autosave_handling')
66
-        // );
67
-        add_filter(
68
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
69
-            array($this, 'caf_updates')
70
-        );
71
-    }
72
-
73
-
74
-
75
-    /**
76
-     * @return void
77
-     */
78
-    protected function _setup_metaboxes()
79
-    {
80
-        //if we were going to add our own metaboxes we'd use the below.
81
-        $this->_metaboxes = array(
82
-            0 => array(
83
-                'page_route' => array('edit', 'create_new'),
84
-                'func'       => 'pricing_metabox',
85
-                'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
86
-                'priority'   => 'high',
87
-                'context'    => 'normal',
88
-            ),
89
-        );
90
-        $this->_remove_metaboxes = array(
91
-            0 => array(
92
-                'page_route' => array('edit', 'create_new'),
93
-                'id'         => 'espresso_event_editor_tickets',
94
-                'context'    => 'normal',
95
-            ),
96
-        );
97
-    }
98
-
99
-
100
-
101
-    /**
102
-     * @return void
103
-     */
104
-    protected function _set_date_time_formats()
105
-    {
106
-        /**
107
-         * Format strings for date and time.  Defaults are existing behaviour from 4.1.
108
-         * Note, that if you return null as the value for 'date', and 'time' in the array, then
109
-         * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
110
-         *
111
-         * @since 4.6.7
112
-         * @var array  Expected an array returned with 'date' and 'time' keys.
113
-         */
114
-        $this->_date_format_strings = apply_filters(
115
-            'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
116
-            array(
117
-                'date' => 'Y-m-d',
118
-                'time' => 'h:i a',
119
-            )
120
-        );
121
-        //validate
122
-        $this->_date_format_strings['date'] = isset($this->_date_format_strings['date'])
123
-            ? $this->_date_format_strings['date']
124
-            : null;
125
-        $this->_date_format_strings['time'] = isset($this->_date_format_strings['time'])
126
-            ? $this->_date_format_strings['time']
127
-            : null;
128
-        $this->_date_time_format = $this->_date_format_strings['date'] . ' ' . $this->_date_format_strings['time'];
129
-    }
130
-
131
-
132
-
133
-    /**
134
-     * @return void
135
-     */
136
-    protected function _validate_format_strings()
137
-    {
138
-        //validate format strings
139
-        $format_validation = EEH_DTT_Helper::validate_format_string(
140
-            $this->_date_time_format
141
-        );
142
-        if (is_array($format_validation)) {
143
-            $msg = '<p>';
144
-            $msg .= sprintf(
145
-                esc_html__(
146
-                    'The format "%s" was likely added via a filter and is invalid for the following reasons:',
147
-                    'event_espresso'
148
-                ),
149
-                $this->_date_time_format
150
-            );
151
-            $msg .= '</p><ul>';
152
-            foreach ($format_validation as $error) {
153
-                $msg .= '<li>' . $error . '</li>';
154
-            }
155
-            $msg .= '</ul><p>';
156
-            $msg .= sprintf(
157
-                esc_html__(
158
-                    '%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
159
-                    'event_espresso'
160
-                ),
161
-                '<span style="color:#D54E21;">',
162
-                '</span>'
163
-            );
164
-            $msg .= '</p>';
165
-            EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
166
-            $this->_date_format_strings = array(
167
-                'date' => 'Y-m-d',
168
-                'time' => 'h:i a',
169
-            );
170
-        }
171
-    }
172
-
173
-
174
-
175
-    /**
176
-     * @return void
177
-     */
178
-    protected function _set_scripts_styles()
179
-    {
180
-        $this->_scripts_styles = array(
181
-            'registers'   => array(
182
-                'ee-tickets-datetimes-css' => array(
183
-                    'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
184
-                    'type' => 'css',
185
-                ),
186
-                'ee-dtt-ticket-metabox'    => array(
187
-                    'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
188
-                    'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
189
-                ),
190
-            ),
191
-            'deregisters' => array(
192
-                'event-editor-css'       => array('type' => 'css'),
193
-                'event-datetime-metabox' => array('type' => 'js'),
194
-            ),
195
-            'enqueues'    => array(
196
-                'ee-tickets-datetimes-css' => array('edit', 'create_new'),
197
-                'ee-dtt-ticket-metabox'    => array('edit', 'create_new'),
198
-            ),
199
-            'localize'    => array(
200
-                'ee-dtt-ticket-metabox' => array(
201
-                    'DTT_TRASH_BLOCK'       => array(
202
-                        'main_warning'            => esc_html__(
203
-                            'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
204
-                            'event_espresso'
205
-                        ),
206
-                        'after_warning'           => esc_html__(
207
-                            'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
208
-                            'event_espresso'
209
-                        ),
210
-                        'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
211
-                                                     . esc_html__('Cancel', 'event_espresso') . '</button>',
212
-                        'close_button'            => '<button class="button-secondary ee-modal-cancel">'
213
-                                                     . esc_html__('Close', 'event_espresso') . '</button>',
214
-                        'single_warning_from_tkt' => esc_html__(
215
-                            'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
216
-                            'event_espresso'
217
-                        ),
218
-                        'single_warning_from_dtt' => esc_html__(
219
-                            'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
220
-                            'event_espresso'
221
-                        ),
222
-                        'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
223
-                                                     . esc_html__('Dismiss', 'event_espresso') . '</button>',
224
-                    ),
225
-                    'DTT_ERROR_MSG'         => array(
226
-                        'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
227
-                        'dismiss_button' => '<div class="save-cancel-button-container"><button class="button-secondary ee-modal-cancel">'
228
-                                            . esc_html__('Dismiss', 'event_espresso') . '</button></div>',
229
-                    ),
230
-                    'DTT_OVERSELL_WARNING'  => array(
231
-                        'datetime_ticket' => esc_html__(
232
-                            'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
233
-                            'event_espresso'
234
-                        ),
235
-                        'ticket_datetime' => esc_html__(
236
-                            'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
237
-                            'event_espresso'
238
-                        ),
239
-                    ),
240
-                    'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
241
-                        $this->_date_format_strings['date'],
242
-                        $this->_date_format_strings['time']
243
-                    ),
244
-                    'DTT_START_OF_WEEK'     => array('dayValue' => (int)get_option('start_of_week')),
245
-                ),
246
-            ),
247
-        );
248
-    }
249
-
250
-
251
-
252
-    /**
253
-     * @param array $update_callbacks
254
-     * @return array
255
-     */
256
-    public function caf_updates(array $update_callbacks)
257
-    {
258
-        foreach ($update_callbacks as $key => $callback) {
259
-            if ($callback[1] === '_default_tickets_update') {
260
-                unset($update_callbacks[$key]);
261
-            }
262
-        }
263
-        $update_callbacks[] = array($this, 'datetime_and_tickets_caf_update');
264
-        return $update_callbacks;
265
-    }
266
-
267
-
268
-    /**
269
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
270
-     *
271
-     * @param  EE_Event $event The Event object we're attaching data to
272
-     * @param  array $data The request data from the form
273
-     * @throws EE_Error
274
-     * @throws InvalidArgumentException
275
-     */
276
-    public function datetime_and_tickets_caf_update($event, $data)
277
-    {
278
-        //first we need to start with datetimes cause they are the "root" items attached to events.
279
-        $saved_datetimes = $this->_update_datetimes($event, $data);
280
-        //next tackle the tickets (and prices?)
281
-        $this->_update_tickets($event, $saved_datetimes, $data);
282
-    }
283
-
284
-
285
-    /**
286
-     * update event_datetimes
287
-     *
288
-     * @param  EE_Event $event Event being updated
289
-     * @param  array $data the request data from the form
290
-     * @return EE_Datetime[]
291
-     * @throws InvalidArgumentException
292
-     * @throws EE_Error
293
-     */
294
-    protected function _update_datetimes($event, $data)
295
-    {
296
-        $timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
297
-        $saved_dtt_ids = array();
298
-        $saved_dtt_objs = array();
299
-        if (empty($data['edit_event_datetimes']) || !is_array($data['edit_event_datetimes'])) {
300
-            throw new InvalidArgumentException(
301
-                esc_html__(
302
-                    'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
303
-                    'event_espresso'
304
-                )
305
-            );
306
-        }
307
-        foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
308
-            //trim all values to ensure any excess whitespace is removed.
309
-            $datetime_data = array_map(
310
-                function ($datetime_data) {
311
-                    return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
312
-                },
313
-                $datetime_data
314
-            );
315
-            $datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
316
-                                            && ! empty($datetime_data['DTT_EVT_end'])
317
-                ? $datetime_data['DTT_EVT_end']
318
-                : $datetime_data['DTT_EVT_start'];
319
-            $datetime_values = array(
320
-                'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
321
-                    ? $datetime_data['DTT_ID']
322
-                    : null,
323
-                'DTT_name'        => ! empty($datetime_data['DTT_name'])
324
-                    ? $datetime_data['DTT_name']
325
-                    : '',
326
-                'DTT_description' => ! empty($datetime_data['DTT_description'])
327
-                    ? $datetime_data['DTT_description']
328
-                    : '',
329
-                'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
330
-                'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
331
-                'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
332
-                    ? EE_INF
333
-                    : $datetime_data['DTT_reg_limit'],
334
-                'DTT_order'       => ! isset($datetime_data['DTT_order'])
335
-                    ? $row
336
-                    : $datetime_data['DTT_order'],
337
-            );
338
-            // if we have an id then let's get existing object first and then set the new values.
339
-            // Otherwise we instantiate a new object for save.
340
-            if (! empty($datetime_data['DTT_ID'])) {
341
-                $datetime = EE_Registry::instance()
342
-                                       ->load_model('Datetime', array($timezone))
343
-                                       ->get_one_by_ID($datetime_data['DTT_ID']);
344
-                //set date and time format according to what is set in this class.
345
-                $datetime->set_date_format($this->_date_format_strings['date']);
346
-                $datetime->set_time_format($this->_date_format_strings['time']);
347
-                foreach ($datetime_values as $field => $value) {
348
-                    $datetime->set($field, $value);
349
-                }
350
-                // make sure the $dtt_id here is saved just in case
351
-                // after the add_relation_to() the autosave replaces it.
352
-                // We need to do this so we dont' TRASH the parent DTT.
353
-                // (save the ID for both key and value to avoid duplications)
354
-                $saved_dtt_ids[$datetime->ID()] = $datetime->ID();
355
-            } else {
356
-                $datetime = EE_Registry::instance()->load_class(
357
-                    'Datetime',
358
-                    array(
359
-                        $datetime_values,
360
-                        $timezone,
361
-                        array($this->_date_format_strings['date'], $this->_date_format_strings['time']),
362
-                    ),
363
-                    false,
364
-                    false
365
-                );
366
-                foreach ($datetime_values as $field => $value) {
367
-                    $datetime->set($field, $value);
368
-                }
369
-            }
370
-            $datetime->save();
371
-            $datetime = $event->_add_relation_to($datetime, 'Datetime');
372
-            // before going any further make sure our dates are setup correctly
373
-            // so that the end date is always equal or greater than the start date.
374
-            if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
375
-                $datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
376
-                $datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
377
-                $datetime->save();
378
-            }
379
-            //	now we have to make sure we add the new DTT_ID to the $saved_dtt_ids array
380
-            // because it is possible there was a new one created for the autosave.
381
-            // (save the ID for both key and value to avoid duplications)
382
-            $DTT_ID = $datetime->ID();
383
-            $saved_dtt_ids[$DTT_ID] = $DTT_ID;
384
-            $saved_dtt_objs[$row] = $datetime;
385
-            //todo if ANY of these updates fail then we want the appropriate global error message.
386
-        }
387
-        $event->save();
388
-        // now we need to REMOVE any datetimes that got deleted.
389
-        // Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
390
-        // So its safe to permanently delete at this point.
391
-        $old_datetimes = explode(',', $data['datetime_IDs']);
392
-        $old_datetimes = $old_datetimes[0] === '' ? array() : $old_datetimes;
393
-        if (is_array($old_datetimes)) {
394
-            $datetimes_to_delete = array_diff($old_datetimes, $saved_dtt_ids);
395
-            foreach ($datetimes_to_delete as $id) {
396
-                $id = absint($id);
397
-                if (empty($id)) {
398
-                    continue;
399
-                }
400
-                $dtt_to_remove = EE_Registry::instance()->load_model('Datetime')->get_one_by_ID($id);
401
-                //remove tkt relationships.
402
-                $related_tickets = $dtt_to_remove->get_many_related('Ticket');
403
-                foreach ($related_tickets as $tkt) {
404
-                    $dtt_to_remove->_remove_relation_to($tkt, 'Ticket');
405
-                }
406
-                $event->_remove_relation_to($id, 'Datetime');
407
-                $dtt_to_remove->refresh_cache_of_related_objects();
408
-            }
409
-        }
410
-        return $saved_dtt_objs;
411
-    }
412
-
413
-
414
-    /**
415
-     * update tickets
416
-     *
417
-     * @param  EE_Event $event Event object being updated
418
-     * @param  EE_Datetime[] $saved_datetimes an array of datetime ids being updated
419
-     * @param  array $data incoming request data
420
-     * @return EE_Ticket[]
421
-     * @throws InvalidArgumentException
422
-     * @throws EE_Error
423
-     */
424
-    protected function _update_tickets($event, $saved_datetimes, $data)
425
-    {
426
-        $new_tkt = null;
427
-        $new_default = null;
428
-        //stripslashes because WP filtered the $_POST ($data) array to add slashes
429
-        $data = stripslashes_deep($data);
430
-        $timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
431
-        $saved_tickets = $datetimes_on_existing = array();
432
-        $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
433
-        if(empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])){
434
-            throw new InvalidArgumentException(
435
-                esc_html__(
436
-                    'The "edit_tickets" array is invalid therefore the event can not be updated.',
437
-                    'event_espresso'
438
-                )
439
-            );
440
-        }
441
-        foreach ($data['edit_tickets'] as $row => $tkt) {
442
-            $update_prices = $create_new_TKT = false;
443
-            // figure out what datetimes were added to the ticket
444
-            // and what datetimes were removed from the ticket in the session.
445
-            $starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][$row]);
446
-            $tkt_dtt_rows = explode(',', $data['ticket_datetime_rows'][$row]);
447
-            $datetimes_added = array_diff($tkt_dtt_rows, $starting_tkt_dtt_rows);
448
-            $datetimes_removed = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
449
-            // trim inputs to ensure any excess whitespace is removed.
450
-            $tkt = array_map(
451
-                function ($ticket_data) {
452
-                    return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
453
-                },
454
-                $tkt
455
-            );
456
-            // note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
457
-            // because we're doing calculations prior to using the models.
458
-            // note incoming ['TKT_price'] value is already in standard notation (via js).
459
-            $ticket_price = isset($tkt['TKT_price'])
460
-                ? round((float)$tkt['TKT_price'], 3)
461
-                : 0;
462
-            //note incoming base price needs converted from localized value.
463
-            $base_price = isset($tkt['TKT_base_price'])
464
-                ? EEH_Money::convert_to_float_from_localized_money($tkt['TKT_base_price'])
465
-                : 0;
466
-            //if ticket price == 0 and $base_price != 0 then ticket price == base_price
467
-            $ticket_price = $ticket_price === 0 && $base_price !== 0
468
-                ? $base_price
469
-                : $ticket_price;
470
-            $base_price_id = isset($tkt['TKT_base_price_ID'])
471
-                ? $tkt['TKT_base_price_ID']
472
-                : 0;
473
-            $price_rows = is_array($data['edit_prices']) && isset($data['edit_prices'][$row])
474
-                ? $data['edit_prices'][$row]
475
-                : array();
476
-            $now = null;
477
-            if (empty($tkt['TKT_start_date'])) {
478
-                //lets' use now in the set timezone.
479
-                $now = new DateTime('now', new DateTimeZone($event->get_timezone()));
480
-                $tkt['TKT_start_date'] = $now->format($this->_date_time_format);
481
-            }
482
-            if (empty($tkt['TKT_end_date'])) {
483
-                /**
484
-                 * set the TKT_end_date to the first datetime attached to the ticket.
485
-                 */
486
-                $first_dtt = $saved_datetimes[reset($tkt_dtt_rows)];
487
-                $tkt['TKT_end_date'] = $first_dtt->start_date_and_time($this->_date_time_format);
488
-            }
489
-            $TKT_values = array(
490
-                'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
491
-                'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
492
-                'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
493
-                'TKT_description' => ! empty($tkt['TKT_description'])
494
-                                     && $tkt['TKT_description'] !== esc_html__(
495
-                    'You can modify this description',
496
-                    'event_espresso'
497
-                )
498
-                    ? $tkt['TKT_description']
499
-                    : '',
500
-                'TKT_start_date'  => $tkt['TKT_start_date'],
501
-                'TKT_end_date'    => $tkt['TKT_end_date'],
502
-                'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === ''
503
-                    ? EE_INF
504
-                    : $tkt['TKT_qty'],
505
-                'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === ''
506
-                    ? EE_INF
507
-                    : $tkt['TKT_uses'],
508
-                'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
509
-                'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
510
-                'TKT_row'         => $row,
511
-                'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : 0,
512
-                'TKT_taxable'     => ! empty($tkt['TKT_taxable']) ? 1 : 0,
513
-                'TKT_required'    => ! empty($tkt['TKT_required']) ? 1 : 0,
514
-                'TKT_price'       => $ticket_price,
515
-            );
516
-            // if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
517
-            // which means in turn that the prices will become new prices as well.
518
-            if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
519
-                $TKT_values['TKT_ID'] = 0;
520
-                $TKT_values['TKT_is_default'] = 0;
521
-                $update_prices = true;
522
-            }
523
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
524
-            // we actually do our saves ahead of doing any add_relations to
525
-            // because its entirely possible that this ticket wasn't removed or added to any datetime in the session
526
-            // but DID have it's items modified.
527
-            // keep in mind that if the TKT has been sold (and we have changed pricing information),
528
-            // then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
529
-            if (absint($TKT_values['TKT_ID'])) {
530
-                $ticket = EE_Registry::instance()
531
-                                     ->load_model('Ticket', array($timezone))
532
-                                     ->get_one_by_ID($tkt['TKT_ID']);
533
-                if ($ticket instanceof EE_Ticket) {
534
-                    $ticket = $this->_update_ticket_datetimes(
535
-                        $ticket,
536
-                        $saved_datetimes,
537
-                        $datetimes_added,
538
-                        $datetimes_removed
539
-                    );
540
-                    // are there any registrations using this ticket ?
541
-                    $tickets_sold = $ticket->count_related(
542
-                        'Registration',
543
-                        array(
544
-                            array(
545
-                                'STS_ID' => array('NOT IN', array(EEM_Registration::status_id_incomplete)),
546
-                            ),
547
-                        )
548
-                    );
549
-                    //set ticket formats
550
-                    $ticket->set_date_format($this->_date_format_strings['date']);
551
-                    $ticket->set_time_format($this->_date_format_strings['time']);
552
-                    // let's just check the total price for the existing ticket
553
-                    // and determine if it matches the new total price.
554
-                    // if they are different then we create a new ticket (if tickets sold)
555
-                    // if they aren't different then we go ahead and modify existing ticket.
556
-                    $create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
557
-                    //set new values
558
-                    foreach ($TKT_values as $field => $value) {
559
-                        if ($field === 'TKT_qty') {
560
-                            $ticket->set_qty($value);
561
-                        } else {
562
-                            $ticket->set($field, $value);
563
-                        }
564
-                    }
565
-                    // if $create_new_TKT is false then we can safely update the existing ticket.
566
-                    // Otherwise we have to create a new ticket.
567
-                    if ($create_new_TKT) {
568
-                        $new_tkt = $this->_duplicate_ticket($ticket, $price_rows, $ticket_price, $base_price,
569
-                            $base_price_id);
570
-                    }
571
-                }
572
-            } else {
573
-                // no TKT_id so a new TKT
574
-                $ticket = EE_Ticket::new_instance(
575
-                    $TKT_values,
576
-                    $timezone,
577
-                    array($this->_date_format_strings['date'], $this->_date_format_strings['time'])
578
-                );
579
-                if ($ticket instanceof EE_Ticket) {
580
-                    // make sure ticket has an ID of setting relations won't work
581
-                    $ticket->save();
582
-                    $ticket = $this->_update_ticket_datetimes(
583
-                        $ticket,
584
-                        $saved_datetimes,
585
-                        $datetimes_added,
586
-                        $datetimes_removed
587
-                    );
588
-                    $update_prices = true;
589
-                }
590
-            }
591
-            //make sure any current values have been saved.
592
-            //$ticket->save();
593
-            // before going any further make sure our dates are setup correctly
594
-            // so that the end date is always equal or greater than the start date.
595
-            if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
596
-                $ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
597
-                $ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
598
-            }
599
-            //let's make sure the base price is handled
600
-            $ticket = ! $create_new_TKT ? $this->_add_prices_to_ticket(array(), $ticket, $update_prices, $base_price,
601
-                $base_price_id) : $ticket;
602
-            //add/update price_modifiers
603
-            $ticket = ! $create_new_TKT ? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices) : $ticket;
604
-            //need to make sue that the TKT_price is accurate after saving the prices.
605
-            $ticket->ensure_TKT_Price_correct();
606
-            //handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
607
-            if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
608
-                $update_prices = true;
609
-                $new_default = clone $ticket;
610
-                $new_default->set('TKT_ID', 0);
611
-                $new_default->set('TKT_is_default', 1);
612
-                $new_default->set('TKT_row', 1);
613
-                $new_default->set('TKT_price', $ticket_price);
614
-                // remove any dtt relations cause we DON'T want dtt relations attached
615
-                // (note this is just removing the cached relations in the object)
616
-                $new_default->_remove_relations('Datetime');
617
-                //todo we need to add the current attached prices as new prices to the new default ticket.
618
-                $new_default = $this->_add_prices_to_ticket($price_rows, $new_default, $update_prices);
619
-                //don't forget the base price!
620
-                $new_default = $this->_add_prices_to_ticket(
621
-                    array(),
622
-                    $new_default,
623
-                    $update_prices,
624
-                    $base_price,
625
-                    $base_price_id
626
-                );
627
-                $new_default->save();
628
-                do_action(
629
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
630
-                    $new_default,
631
-                    $row,
632
-                    $ticket,
633
-                    $data
634
-                );
635
-            }
636
-            // DO ALL dtt relationships for both current tickets and any archived tickets
637
-            // for the given dtt that are related to the current ticket.
638
-            // TODO... not sure exactly how we're going to do this considering we don't know
639
-            // what current ticket the archived tickets are related to
640
-            // (and TKT_parent is used for autosaves so that's not a field we can reliably use).
641
-            //let's assign any tickets that have been setup to the saved_tickets tracker
642
-            //save existing TKT
643
-            $ticket->save();
644
-            if ($create_new_TKT && $new_tkt instanceof EE_Ticket) {
645
-                //save new TKT
646
-                $new_tkt->save();
647
-                //add new ticket to array
648
-                $saved_tickets[$new_tkt->ID()] = $new_tkt;
649
-                do_action(
650
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
651
-                    $new_tkt,
652
-                    $row,
653
-                    $tkt,
654
-                    $data
655
-                );
656
-            } else {
657
-                //add tkt to saved tkts
658
-                $saved_tickets[$ticket->ID()] = $ticket;
659
-                do_action(
660
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
661
-                    $ticket,
662
-                    $row,
663
-                    $tkt,
664
-                    $data
665
-                );
666
-            }
667
-        }
668
-        // now we need to handle tickets actually "deleted permanently".
669
-        // There are cases where we'd want this to happen
670
-        // (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
671
-        // Or a draft event was saved and in the process of editing a ticket is trashed.
672
-        // No sense in keeping all the related data in the db!
673
-        $old_tickets = isset($old_tickets[0]) && $old_tickets[0] === '' ? array() : $old_tickets;
674
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
675
-        foreach ($tickets_removed as $id) {
676
-            $id = absint($id);
677
-            //get the ticket for this id
678
-            $tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
679
-            //if this tkt is a default tkt we leave it alone cause it won't be attached to the datetime
680
-            if ($tkt_to_remove->get('TKT_is_default')) {
681
-                continue;
682
-            }
683
-            // if this tkt has any registrations attached so then we just ARCHIVE
684
-            // because we don't actually permanently delete these tickets.
685
-            if ($tkt_to_remove->count_related('Registration') > 0) {
686
-                $tkt_to_remove->delete();
687
-                continue;
688
-            }
689
-            // need to get all the related datetimes on this ticket and remove from every single one of them
690
-            // (remember this process can ONLY kick off if there are NO tkts_sold)
691
-            $datetimes = $tkt_to_remove->get_many_related('Datetime');
692
-            foreach ($datetimes as $datetime) {
693
-                $tkt_to_remove->_remove_relation_to($datetime, 'Datetime');
694
-            }
695
-            // need to do the same for prices (except these prices can also be deleted because again,
696
-            // tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
697
-            $tkt_to_remove->delete_related_permanently('Price');
698
-            do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $tkt_to_remove);
699
-            // finally let's delete this ticket
700
-            // (which should not be blocked at this point b/c we've removed all our relationships)
701
-            $tkt_to_remove->delete_permanently();
702
-        }
703
-        return $saved_tickets;
704
-    }
705
-
706
-
707
-
708
-    /**
709
-     * @access  protected
710
-     * @param \EE_Ticket     $ticket
711
-     * @param \EE_Datetime[] $saved_datetimes
712
-     * @param \EE_Datetime[] $added_datetimes
713
-     * @param \EE_Datetime[] $removed_datetimes
714
-     * @return \EE_Ticket
715
-     * @throws \EE_Error
716
-     */
717
-    protected function _update_ticket_datetimes(
718
-        EE_Ticket $ticket,
719
-        $saved_datetimes = array(),
720
-        $added_datetimes = array(),
721
-        $removed_datetimes = array()
722
-    ) {
723
-        // to start we have to add the ticket to all the datetimes its supposed to be with,
724
-        // and removing the ticket from datetimes it got removed from.
725
-        // first let's add datetimes
726
-        if (! empty($added_datetimes) && is_array($added_datetimes)) {
727
-            foreach ($added_datetimes as $row_id) {
728
-                $row_id = (int)$row_id;
729
-                if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
730
-                    $ticket->_add_relation_to($saved_datetimes[$row_id], 'Datetime');
731
-                    // Is this an existing ticket (has an ID) and does it have any sold?
732
-                    // If so, then we need to add that to the DTT sold because this DTT is getting added.
733
-                    if ($ticket->ID() && $ticket->sold() > 0) {
734
-                        $saved_datetimes[$row_id]->increase_sold($ticket->sold());
735
-                        $saved_datetimes[$row_id]->save();
736
-                    }
737
-                }
738
-            }
739
-        }
740
-        // then remove datetimes
741
-        if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
742
-            foreach ($removed_datetimes as $row_id) {
743
-                $row_id = (int)$row_id;
744
-                // its entirely possible that a datetime got deleted (instead of just removed from relationship.
745
-                // So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
746
-                if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
747
-                    $ticket->_remove_relation_to($saved_datetimes[$row_id], 'Datetime');
748
-                    // Is this an existing ticket (has an ID) and does it have any sold?
749
-                    // If so, then we need to remove it's sold from the DTT_sold.
750
-                    if ($ticket->ID() && $ticket->sold() > 0) {
751
-                        $saved_datetimes[$row_id]->decrease_sold($ticket->sold());
752
-                        $saved_datetimes[$row_id]->save();
753
-                    }
754
-                }
755
-            }
756
-        }
757
-        // cap ticket qty by datetime reg limits
758
-        $ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
759
-        return $ticket;
760
-    }
761
-
762
-
763
-
764
-    /**
765
-     * @access  protected
766
-     * @param \EE_Ticket $ticket
767
-     * @param array      $price_rows
768
-     * @param int        $ticket_price
769
-     * @param int        $base_price
770
-     * @param int        $base_price_id
771
-     * @return \EE_Ticket
772
-     * @throws \EE_Error
773
-     */
774
-    protected function _duplicate_ticket(
775
-        EE_Ticket $ticket,
776
-        $price_rows = array(),
777
-        $ticket_price = 0,
778
-        $base_price = 0,
779
-        $base_price_id = 0
780
-    ) {
781
-        // create new ticket that's a copy of the existing
782
-        // except a new id of course (and not archived)
783
-        // AND has the new TKT_price associated with it.
784
-        $new_ticket = clone $ticket;
785
-        $new_ticket->set('TKT_ID', 0);
786
-        $new_ticket->set_deleted(0);
787
-        $new_ticket->set_price($ticket_price);
788
-        $new_ticket->set_sold(0);
789
-        // let's get a new ID for this ticket
790
-        $new_ticket->save();
791
-        // we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
792
-        $datetimes_on_existing = $ticket->datetimes();
793
-        $new_ticket = $this->_update_ticket_datetimes(
794
-            $new_ticket,
795
-            $datetimes_on_existing,
796
-            array_keys($datetimes_on_existing)
797
-        );
798
-        // $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
799
-        // if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
800
-        // available.
801
-        if ($ticket->sold() > 0) {
802
-            $new_qty = $ticket->qty() - $ticket->sold();
803
-            $new_ticket->set_qty($new_qty);
804
-        }
805
-        //now we update the prices just for this ticket
806
-        $new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
807
-        //and we update the base price
808
-        $new_ticket = $this->_add_prices_to_ticket(array(), $new_ticket, true, $base_price, $base_price_id);
809
-        return $new_ticket;
810
-    }
811
-
812
-
813
-
814
-    /**
815
-     * This attaches a list of given prices to a ticket.
816
-     * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
817
-     * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
818
-     * price info and prices are automatically "archived" via the ticket.
819
-     *
820
-     * @access  private
821
-     * @param array     $prices        Array of prices from the form.
822
-     * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
823
-     * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
824
-     * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
825
-     * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
826
-     * @return EE_Ticket
827
-     * @throws EE_Error
828
-     */
829
-    protected function _add_prices_to_ticket(
830
-        $prices = array(),
831
-        EE_Ticket $ticket,
832
-        $new_prices = false,
833
-        $base_price = false,
834
-        $base_price_id = false
835
-    ) {
836
-        // let's just get any current prices that may exist on the given ticket
837
-        // so we can remove any prices that got trashed in this session.
838
-        $current_prices_on_ticket = $base_price !== false
839
-            ? $ticket->base_price(true)
840
-            : $ticket->price_modifiers();
841
-        $updated_prices = array();
842
-        // if $base_price ! FALSE then updating a base price.
843
-        if ($base_price !== false) {
844
-            $prices[1] = array(
845
-                'PRC_ID'     => $new_prices || $base_price_id === 1 ? null : $base_price_id,
846
-                'PRT_ID'     => 1,
847
-                'PRC_amount' => $base_price,
848
-                'PRC_name'   => $ticket->get('TKT_name'),
849
-                'PRC_desc'   => $ticket->get('TKT_description'),
850
-            );
851
-        }
852
-        //possibly need to save tkt
853
-        if (! $ticket->ID()) {
854
-            $ticket->save();
855
-        }
856
-        foreach ($prices as $row => $prc) {
857
-            $prt_id = ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null;
858
-            if (empty($prt_id)) {
859
-                continue;
860
-            } //prices MUST have a price type id.
861
-            $PRC_values = array(
862
-                'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
863
-                'PRT_ID'         => $prt_id,
864
-                'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
865
-                'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
866
-                'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
867
-                'PRC_is_default' => false,
868
-                //make sure we set PRC_is_default to false for all ticket saves from event_editor
869
-                'PRC_order'      => $row,
870
-            );
871
-            if ($new_prices || empty($PRC_values['PRC_ID'])) {
872
-                $PRC_values['PRC_ID'] = 0;
873
-                $price = EE_Registry::instance()->load_class(
874
-                    'Price',
875
-                    array($PRC_values),
876
-                    false,
877
-                    false
878
-                );
879
-            } else {
880
-                $price = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
881
-                //update this price with new values
882
-                foreach ($PRC_values as $field => $value) {
883
-                    $price->set($field, $value);
884
-                }
885
-            }
886
-            $price->save();
887
-            $updated_prices[$price->ID()] = $price;
888
-            $ticket->_add_relation_to($price, 'Price');
889
-        }
890
-        //now let's remove any prices that got removed from the ticket
891
-        if (! empty ($current_prices_on_ticket)) {
892
-            $current = array_keys($current_prices_on_ticket);
893
-            $updated = array_keys($updated_prices);
894
-            $prices_to_remove = array_diff($current, $updated);
895
-            if (! empty($prices_to_remove)) {
896
-                foreach ($prices_to_remove as $prc_id) {
897
-                    $p = $current_prices_on_ticket[$prc_id];
898
-                    $ticket->_remove_relation_to($p, 'Price');
899
-                    //delete permanently the price
900
-                    $p->delete_permanently();
901
-                }
902
-            }
903
-        }
904
-        return $ticket;
905
-    }
906
-
907
-
908
-
909
-    /**
910
-     * @param Events_Admin_Page $event_admin_obj
911
-     * @return Events_Admin_Page
912
-     */
913
-    public function autosave_handling( Events_Admin_Page $event_admin_obj)
914
-    {
915
-        return $event_admin_obj;
916
-        //doing nothing for the moment.
917
-        // todo when I get to this remember that I need to set the template args on the $event_admin_obj
918
-        // (use the set_template_args() method)
919
-        /**
920
-         * need to remember to handle TICKET DEFAULT saves correctly:  I've got two input fields in the dom:
921
-         * 1. TKT_is_default_selector (visible)
922
-         * 2. TKT_is_default (hidden)
923
-         * I think we'll use the TKT_is_default for recording whether the ticket displayed IS a default ticket
924
-         * (on new event creations). Whereas the TKT_is_default_selector is for the user to indicate they want
925
-         * this ticket to be saved as a default.
926
-         * The tricky part is, on an initial display on create or edit (or after manually updating),
927
-         * the TKT_is_default_selector will always be unselected and the TKT_is_default will only be true
928
-         * if this is a create.  However, after an autosave, users will want some sort of indicator that
929
-         * the TKT HAS been saved as a default..
930
-         * in other words we don't want to remove the check on TKT_is_default_selector. So here's what I'm thinking.
931
-         * On Autosave:
932
-         * 1. If TKT_is_default is true: we create a new TKT, send back the new id and add id to related elements,
933
-         * then set the TKT_is_default to false.
934
-         * 2. If TKT_is_default_selector is true: we create/edit existing ticket (following conditions above as well).
935
-         *  We do NOT create a new default ticket.  The checkbox stays selected after autosave.
936
-         * 3. only on MANUAL update do we check for the selection and if selected create the new default ticket.
937
-         */
938
-    }
939
-
940
-
941
-
942
-    /**
943
-     * @throws DomainException
944
-     * @throws EE_Error
945
-     */
946
-    public function pricing_metabox()
947
-    {
948
-        $existing_datetime_ids = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = array();
949
-        $event = $this->_adminpage_obj->get_cpt_model_obj();
950
-        //set is_creating_event property.
951
-        $EVT_ID = $event->ID();
952
-        $this->_is_creating_event = absint($EVT_ID) === 0;
953
-        //default main template args
954
-        $main_template_args = array(
955
-            'event_datetime_help_link' => EEH_Template::get_help_tab_link(
956
-                'event_editor_event_datetimes_help_tab',
957
-                $this->_adminpage_obj->page_slug,
958
-                $this->_adminpage_obj->get_req_action(),
959
-                false,
960
-                false
961
-            ),
962
-            // todo need to add a filter to the template for the help text
963
-            // in the Events_Admin_Page core file so we can add further help
964
-            'existing_datetime_ids'    => '',
965
-            'total_dtt_rows'           => 1,
966
-            'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
967
-                'add_new_dtt_info',
968
-                $this->_adminpage_obj->page_slug,
969
-                $this->_adminpage_obj->get_req_action(),
970
-                false,
971
-                false
972
-            ),
973
-            //todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
974
-            'datetime_rows'            => '',
975
-            'show_tickets_container'   => '',
976
-            //$this->_adminpage_obj->get_cpt_model_obj()->ID() > 1 ? ' style="display:none;"' : '',
977
-            'ticket_rows'              => '',
978
-            'existing_ticket_ids'      => '',
979
-            'total_ticket_rows'        => 1,
980
-            'ticket_js_structure'      => '',
981
-            'ee_collapsible_status'    => ' ee-collapsible-open'
982
-            //$this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
983
-        );
984
-        $timezone = $event instanceof EE_Event ? $event->timezone_string() : null;
985
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
986
-        /**
987
-         * 1. Start with retrieving Datetimes
988
-         * 2. For each datetime get related tickets
989
-         * 3. For each ticket get related prices
990
-         */
991
-        /** @var EEM_Datetime $datetime_model */
992
-        $datetime_model = EE_Registry::instance()->load_model('Datetime', array($timezone));
993
-        $datetimes = $datetime_model->get_all_event_dates($EVT_ID);
994
-        $main_template_args['total_dtt_rows'] = count($datetimes);
995
-        /**
996
-         * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
997
-         * for why we are counting $datetime_row and then setting that on the Datetime object
998
-         */
999
-        $datetime_row = 1;
1000
-        foreach ($datetimes as $datetime) {
1001
-            $DTT_ID = $datetime->get('DTT_ID');
1002
-            $datetime->set('DTT_order', $datetime_row);
1003
-            $existing_datetime_ids[] = $DTT_ID;
1004
-            //tickets attached
1005
-            $related_tickets = $datetime->ID() > 0
1006
-                ? $datetime->get_many_related(
1007
-                    'Ticket',
1008
-                    array(
1009
-                        array(
1010
-                            'OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0),
1011
-                        ),
1012
-                        'default_where_conditions' => 'none',
1013
-                        'order_by'                 => array('TKT_order' => 'ASC'),
1014
-                    )
1015
-                )
1016
-                : array();
1017
-            //if there are no related tickets this is likely a new event OR autodraft
1018
-            // event so we need to generate the default tickets because datetimes
1019
-            // ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1020
-            // datetime on the event.
1021
-            if (empty ($related_tickets) && count($datetimes) < 2) {
1022
-                /** @var EEM_Ticket $ticket_model */
1023
-                $ticket_model = EE_Registry::instance()->load_model('Ticket');
1024
-                $related_tickets = $ticket_model->get_all_default_tickets();
1025
-                // this should be ordered by TKT_ID, so let's grab the first default ticket
1026
-                // (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1027
-                $default_prices = EEM_Price::instance()->get_all_default_prices();
1028
-                $main_default_ticket = reset($related_tickets);
1029
-                if ($main_default_ticket instanceof EE_Ticket) {
1030
-                    foreach ($default_prices as $default_price) {
1031
-                        if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1032
-                            continue;
1033
-                        }
1034
-                        $main_default_ticket->cache('Price', $default_price);
1035
-                    }
1036
-                }
1037
-            }
1038
-            // we can't actually setup rows in this loop yet cause we don't know all
1039
-            // the unique tickets for this event yet (tickets are linked through all datetimes).
1040
-            // So we're going to temporarily cache some of that information.
1041
-            //loop through and setup the ticket rows and make sure the order is set.
1042
-            foreach ($related_tickets as $ticket) {
1043
-                $TKT_ID = $ticket->get('TKT_ID');
1044
-                $ticket_row = $ticket->get('TKT_row');
1045
-                //we only want unique tickets in our final display!!
1046
-                if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1047
-                    $existing_ticket_ids[] = $TKT_ID;
1048
-                    $all_tickets[] = $ticket;
1049
-                }
1050
-                //temporary cache of this ticket info for this datetime for later processing of datetime rows.
1051
-                $datetime_tickets[$DTT_ID][] = $ticket_row;
1052
-                //temporary cache of this datetime info for this ticket for later processing of ticket rows.
1053
-                if (
1054
-                    ! isset($ticket_datetimes[$TKT_ID])
1055
-                    || ! in_array($datetime_row, $ticket_datetimes[$TKT_ID], true)
1056
-                ) {
1057
-                    $ticket_datetimes[$TKT_ID][] = $datetime_row;
1058
-                }
1059
-            }
1060
-            $datetime_row++;
1061
-        }
1062
-        $main_template_args['total_ticket_rows'] = count($existing_ticket_ids);
1063
-        $main_template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1064
-        $main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1065
-        //sort $all_tickets by order
1066
-        usort(
1067
-            $all_tickets,
1068
-            function (EE_Ticket $a, EE_Ticket $b) {
1069
-                $a_order = (int)$a->get('TKT_order');
1070
-                $b_order = (int)$b->get('TKT_order');
1071
-                if ($a_order === $b_order) {
1072
-                    return 0;
1073
-                }
1074
-                return ($a_order < $b_order) ? -1 : 1;
1075
-            }
1076
-        );
1077
-        // k NOW we have all the data we need for setting up the dtt rows
1078
-        // and ticket rows so we start our dtt loop again.
1079
-        $datetime_row = 1;
1080
-        foreach ($datetimes as $datetime) {
1081
-            $main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1082
-                $datetime_row,
1083
-                $datetime,
1084
-                $datetime_tickets,
1085
-                $all_tickets,
1086
-                false,
1087
-                $datetimes
1088
-            );
1089
-            $datetime_row++;
1090
-        }
1091
-        //then loop through all tickets for the ticket rows.
1092
-        $ticket_row = 1;
1093
-        foreach ($all_tickets as $ticket) {
1094
-            $main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1095
-                $ticket_row,
1096
-                $ticket,
1097
-                $ticket_datetimes,
1098
-                $datetimes,
1099
-                false,
1100
-                $all_tickets
1101
-            );
1102
-            $ticket_row++;
1103
-        }
1104
-        $main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1105
-        EEH_Template::display_template(
1106
-            PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1107
-            $main_template_args
1108
-        );
1109
-    }
1110
-
1111
-
1112
-
1113
-    /**
1114
-     * @param int         $datetime_row
1115
-     * @param EE_Datetime $datetime
1116
-     * @param array       $datetime_tickets
1117
-     * @param array       $all_tickets
1118
-     * @param bool        $default
1119
-     * @param array       $all_datetimes
1120
-     * @return mixed
1121
-     * @throws DomainException
1122
-     * @throws EE_Error
1123
-     */
1124
-    protected function _get_datetime_row(
1125
-        $datetime_row,
1126
-        EE_Datetime $datetime,
1127
-        $datetime_tickets = array(),
1128
-        $all_tickets = array(),
1129
-        $default = false,
1130
-        $all_datetimes = array()
1131
-    ) {
1132
-        $dtt_display_template_args = array(
1133
-            'dtt_edit_row'             => $this->_get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes),
1134
-            'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1135
-                $datetime_row,
1136
-                $datetime,
1137
-                $datetime_tickets,
1138
-                $all_tickets,
1139
-                $default
1140
-            ),
1141
-            'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1142
-        );
1143
-        return EEH_Template::display_template(
1144
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1145
-            $dtt_display_template_args,
1146
-            true
1147
-        );
1148
-    }
1149
-
1150
-
1151
-
1152
-    /**
1153
-     * This method is used to generate a dtt fields  edit row.
1154
-     * The same row is used to generate a row with valid DTT objects
1155
-     * and the default row that is used as the skeleton by the js.
1156
-     *
1157
-     * @param int           $datetime_row  The row number for the row being generated.
1158
-     * @param EE_Datetime   $datetime
1159
-     * @param bool          $default       Whether a default row is being generated or not.
1160
-     * @param EE_Datetime[] $all_datetimes This is the array of all datetimes used in the editor.
1161
-     * @return string
1162
-     * @throws DomainException
1163
-     * @throws EE_Error
1164
-     */
1165
-    protected function _get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes)
1166
-    {
1167
-        // if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1168
-        $default = ! $datetime instanceof EE_Datetime ? true : $default;
1169
-        $template_args = array(
1170
-            'dtt_row'              => $default ? 'DTTNUM' : $datetime_row,
1171
-            'event_datetimes_name' => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1172
-            'edit_dtt_expanded'    => '',
1173
-            'DTT_ID'               => $default ? '' : $datetime->ID(),
1174
-            'DTT_name'             => $default ? '' : $datetime->name(),
1175
-            'DTT_description'      => $default ? '' : $datetime->description(),
1176
-            'DTT_EVT_start'        => $default ? '' : $datetime->start_date($this->_date_time_format),
1177
-            'DTT_EVT_end'          => $default ? '' : $datetime->end_date($this->_date_time_format),
1178
-            'DTT_reg_limit'        => $default
1179
-                ? ''
1180
-                : $datetime->get_pretty(
1181
-                    'DTT_reg_limit',
1182
-                    'input'
1183
-                ),
1184
-            'DTT_order'            => $default ? 'DTTNUM' : $datetime_row,
1185
-            'dtt_sold'             => $default ? '0' : $datetime->get('DTT_sold'),
1186
-            'dtt_reserved'         => $default ? '0' : $datetime->reserved(),
1187
-            'clone_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1188
-                ? ''
1189
-                : 'clone-icon ee-icon ee-icon-clone clickable',
1190
-            'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1191
-                ? 'ee-lock-icon'
1192
-                : 'trash-icon dashicons dashicons-post-trash clickable',
1193
-            'reg_list_url'         => $default || ! $datetime->event() instanceof \EE_Event
1194
-                ? ''
1195
-                : EE_Admin_Page::add_query_args_and_nonce(
1196
-                    array('event_id' => $datetime->event()->ID(), 'datetime_id' => $datetime->ID()),
1197
-                    REG_ADMIN_URL
1198
-                ),
1199
-        );
1200
-        $template_args['show_trash'] = count($all_datetimes) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1201
-            ? ' style="display:none"'
1202
-            : '';
1203
-        //allow filtering of template args at this point.
1204
-        $template_args = apply_filters(
1205
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1206
-            $template_args,
1207
-            $datetime_row,
1208
-            $datetime,
1209
-            $default,
1210
-            $all_datetimes,
1211
-            $this->_is_creating_event
1212
-        );
1213
-        return EEH_Template::display_template(
1214
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1215
-            $template_args,
1216
-            true
1217
-        );
1218
-    }
1219
-
1220
-
1221
-
1222
-    /**
1223
-     * @param int         $datetime_row
1224
-     * @param EE_Datetime $datetime
1225
-     * @param array       $datetime_tickets
1226
-     * @param array       $all_tickets
1227
-     * @param bool        $default
1228
-     * @return mixed
1229
-     * @throws DomainException
1230
-     * @throws EE_Error
1231
-     */
1232
-    protected function _get_dtt_attached_tickets_row(
1233
-        $datetime_row,
1234
-        $datetime,
1235
-        $datetime_tickets = array(),
1236
-        $all_tickets = array(),
1237
-        $default
1238
-    ) {
1239
-        $template_args = array(
1240
-            'dtt_row'                           => $default ? 'DTTNUM' : $datetime_row,
1241
-            'event_datetimes_name'              => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1242
-            'DTT_description'                   => $default ? '' : $datetime->description(),
1243
-            'datetime_tickets_list'             => $default ? '<li class="hidden"></li>' : '',
1244
-            'show_tickets_row'                  => ' style="display:none;"',
1245
-            'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1246
-                'add_new_ticket_via_datetime',
1247
-                $this->_adminpage_obj->page_slug,
1248
-                $this->_adminpage_obj->get_req_action(),
1249
-                false,
1250
-                false
1251
-            ),
1252
-            //todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1253
-            'DTT_ID'                            => $default ? '' : $datetime->ID(),
1254
-        );
1255
-        //need to setup the list items (but only if this isn't a default skeleton setup)
1256
-        if (! $default) {
1257
-            $ticket_row = 1;
1258
-            foreach ($all_tickets as $ticket) {
1259
-                $template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1260
-                    $datetime_row,
1261
-                    $ticket_row,
1262
-                    $datetime,
1263
-                    $ticket,
1264
-                    $datetime_tickets,
1265
-                    $default
1266
-                );
1267
-                $ticket_row++;
1268
-            }
1269
-        }
1270
-        //filter template args at this point
1271
-        $template_args = apply_filters(
1272
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1273
-            $template_args,
1274
-            $datetime_row,
1275
-            $datetime,
1276
-            $datetime_tickets,
1277
-            $all_tickets,
1278
-            $default,
1279
-            $this->_is_creating_event
1280
-        );
1281
-        return EEH_Template::display_template(
1282
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1283
-            $template_args,
1284
-            true
1285
-        );
1286
-    }
1287
-
1288
-
1289
-
1290
-    /**
1291
-     * @param int         $datetime_row
1292
-     * @param int         $ticket_row
1293
-     * @param EE_Datetime $datetime
1294
-     * @param EE_Ticket   $ticket
1295
-     * @param array       $datetime_tickets
1296
-     * @param bool        $default
1297
-     * @return mixed
1298
-     * @throws DomainException
1299
-     * @throws EE_Error
1300
-     */
1301
-    protected function _get_datetime_tickets_list_item(
1302
-        $datetime_row,
1303
-        $ticket_row,
1304
-        $datetime,
1305
-        $ticket,
1306
-        $datetime_tickets = array(),
1307
-        $default
1308
-    ) {
1309
-        $dtt_tkts = $datetime instanceof EE_Datetime && isset($datetime_tickets[$datetime->ID()])
1310
-            ? $datetime_tickets[$datetime->ID()]
1311
-            : array();
1312
-        $display_row = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1313
-        $no_ticket = $default && empty($ticket);
1314
-        $template_args = array(
1315
-            'dtt_row'                 => $default
1316
-                ? 'DTTNUM'
1317
-                : $datetime_row,
1318
-            'tkt_row'                 => $no_ticket
1319
-                ? 'TICKETNUM'
1320
-                : $ticket_row,
1321
-            'datetime_ticket_checked' => in_array($display_row, $dtt_tkts, true)
1322
-                ? ' checked="checked"'
1323
-                : '',
1324
-            'ticket_selected'         => in_array($display_row, $dtt_tkts, true)
1325
-                ? ' ticket-selected'
1326
-                : '',
1327
-            'TKT_name'                => $no_ticket
1328
-                ? 'TKTNAME'
1329
-                : $ticket->get('TKT_name'),
1330
-            'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1331
-                ? ' tkt-status-' . EE_Ticket::onsale
1332
-                : ' tkt-status-' . $ticket->ticket_status(),
1333
-        );
1334
-        //filter template args
1335
-        $template_args = apply_filters(
1336
-            'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1337
-            $template_args,
1338
-            $datetime_row,
1339
-            $ticket_row,
1340
-            $datetime,
1341
-            $ticket,
1342
-            $datetime_tickets,
1343
-            $default,
1344
-            $this->_is_creating_event
1345
-        );
1346
-        return EEH_Template::display_template(
1347
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1348
-            $template_args,
1349
-            true
1350
-        );
1351
-    }
1352
-
1353
-
1354
-
1355
-    /**
1356
-     * This generates the ticket row for tickets.
1357
-     * This same method is used to generate both the actual rows and the js skeleton row
1358
-     * (when default === true)
1359
-     *
1360
-     * @param int           $ticket_row       Represents the row number being generated.
1361
-     * @param               $ticket
1362
-     * @param EE_Datetime[] $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1363
-     *                                        or empty for default
1364
-     * @param EE_Datetime[] $all_datetimes    All Datetimes on the event or empty for default.
1365
-     * @param bool          $default          Whether default row being generated or not.
1366
-     * @param EE_Ticket[]   $all_tickets      This is an array of all tickets attached to the event
1367
-     *                                        (or empty in the case of defaults)
1368
-     * @return mixed
1369
-     * @throws DomainException
1370
-     * @throws EE_Error
1371
-     */
1372
-    protected function _get_ticket_row(
1373
-        $ticket_row,
1374
-        $ticket,
1375
-        $ticket_datetimes,
1376
-        $all_datetimes,
1377
-        $default = false,
1378
-        $all_tickets = array()
1379
-    ) {
1380
-        // if $ticket is not an instance of EE_Ticket then force default to true.
1381
-        $default = ! $ticket instanceof EE_Ticket ? true : $default;
1382
-        $prices = ! empty($ticket) && ! $default ? $ticket->get_many_related('Price',
1383
-            array('default_where_conditions' => 'none', 'order_by' => array('PRC_order' => 'ASC'))) : array();
1384
-        // if there is only one price (which would be the base price)
1385
-        // or NO prices and this ticket is a default ticket,
1386
-        // let's just make sure there are no cached default prices on the object.
1387
-        // This is done by not including any query_params.
1388
-        if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1389
-            $prices = $ticket->prices();
1390
-        }
1391
-        // check if we're dealing with a default ticket in which case
1392
-        // we don't want any starting_ticket_datetime_row values set
1393
-        // (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1394
-        // This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1395
-        $default_dtt = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1396
-        $tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
1397
-            ? $ticket_datetimes[$ticket->ID()]
1398
-            : array();
1399
-        $ticket_subtotal = $default ? 0 : $ticket->get_ticket_subtotal();
1400
-        $base_price = $default ? null : $ticket->base_price();
1401
-        $count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1402
-        //breaking out complicated condition for ticket_status
1403
-        if ($default) {
1404
-            $ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1405
-        } else {
1406
-            $ticket_status_class = $ticket->is_default()
1407
-                ? ' tkt-status-' . EE_Ticket::onsale
1408
-                : ' tkt-status-' . $ticket->ticket_status();
1409
-        }
1410
-        //breaking out complicated condition for TKT_taxable
1411
-        if ($default) {
1412
-            $TKT_taxable = '';
1413
-        } else {
1414
-            $TKT_taxable = $ticket->taxable()
1415
-                ? ' checked="checked"'
1416
-                : '';
1417
-        }
1418
-        if ($default) {
1419
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1420
-        } elseif ($ticket->is_default()) {
1421
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1422
-        } else {
1423
-            $TKT_status = $ticket->ticket_status(true);
1424
-        }
1425
-        if ($default) {
1426
-            $TKT_min = '';
1427
-        } else {
1428
-            $TKT_min = $ticket->min();
1429
-            if ($TKT_min === -1 || $TKT_min === 0) {
1430
-                $TKT_min = '';
1431
-            }
1432
-        }
1433
-        $template_args = array(
1434
-            'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1435
-            'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1436
-            //on initial page load this will always be the correct order.
1437
-            'tkt_status_class'              => $ticket_status_class,
1438
-            'display_edit_tkt_row'          => ' style="display:none;"',
1439
-            'edit_tkt_expanded'             => '',
1440
-            'edit_tickets_name'             => $default ? 'TICKETNAMEATTR' : 'edit_tickets',
1441
-            'TKT_name'                      => $default ? '' : $ticket->name(),
1442
-            'TKT_start_date'                => $default
1443
-                ? ''
1444
-                : $ticket->get_date('TKT_start_date', $this->_date_time_format),
1445
-            'TKT_end_date'                  => $default
1446
-                ? ''
1447
-                : $ticket->get_date('TKT_end_date', $this->_date_time_format),
1448
-            'TKT_status'                    => $TKT_status,
1449
-            'TKT_price'                     => $default
1450
-                ? ''
1451
-                : EEH_Template::format_currency(
1452
-                    $ticket->get_ticket_total_with_taxes(),
1453
-                    false,
1454
-                    false
1455
-                ),
1456
-            'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1457
-            'TKT_price_amount'              => $default ? 0 : $ticket_subtotal,
1458
-            'TKT_qty'                       => $default
1459
-                ? ''
1460
-                : $ticket->get_pretty('TKT_qty', 'symbol'),
1461
-            'TKT_qty_for_input'             => $default
1462
-                ? ''
1463
-                : $ticket->get_pretty('TKT_qty', 'input'),
1464
-            'TKT_uses'                      => $default
1465
-                ? ''
1466
-                : $ticket->get_pretty('TKT_uses', 'input'),
1467
-            'TKT_min'                       => $TKT_min,
1468
-            'TKT_max'                       => $default
1469
-                ? ''
1470
-                : $ticket->get_pretty('TKT_max', 'input'),
1471
-            'TKT_sold'                      => $default ? 0 : $ticket->tickets_sold('ticket'),
1472
-            'TKT_reserved'                  => $default ? 0 : $ticket->reserved(),
1473
-            'TKT_registrations'             => $default
1474
-                ? 0
1475
-                : $ticket->count_registrations(
1476
-                    array(
1477
-                        array(
1478
-                            'STS_ID' => array(
1479
-                                '!=',
1480
-                                EEM_Registration::status_id_incomplete,
1481
-                            ),
1482
-                        ),
1483
-                    )
1484
-                ),
1485
-            'TKT_ID'                        => $default ? 0 : $ticket->ID(),
1486
-            'TKT_description'               => $default ? '' : $ticket->description(),
1487
-            'TKT_is_default'                => $default ? 0 : $ticket->is_default(),
1488
-            'TKT_required'                  => $default ? 0 : $ticket->required(),
1489
-            'TKT_is_default_selector'       => '',
1490
-            'ticket_price_rows'             => '',
1491
-            'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1492
-                ? ''
1493
-                : $base_price->get_pretty('PRC_amount', 'localized_float'),
1494
-            'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price ? 0 : $base_price->ID(),
1495
-            'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1496
-                ? ''
1497
-                : ' style="display:none;"',
1498
-            'show_price_mod_button'         => count($prices) > 1
1499
-                                               || ($default && $count_price_mods > 0)
1500
-                                               || (! $default && $ticket->deleted())
1501
-                ? ' style="display:none;"'
1502
-                : '',
1503
-            'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
1504
-            'ticket_datetimes_list'         => $default ? '<li class="hidden"></li>' : '',
1505
-            'starting_ticket_datetime_rows' => $default || $default_dtt ? '' : implode(',', $tkt_datetimes),
1506
-            'ticket_datetime_rows'          => $default ? '' : implode(',', $tkt_datetimes),
1507
-            'existing_ticket_price_ids'     => $default ? '' : implode(',', array_keys($prices)),
1508
-            'ticket_template_id'            => $default ? 0 : $ticket->get('TTM_ID'),
1509
-            'TKT_taxable'                   => $TKT_taxable,
1510
-            'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1511
-                ? ''
1512
-                : ' style="display:none"',
1513
-            'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1514
-            'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1515
-                $ticket_subtotal,
1516
-                false,
1517
-                false
1518
-            ),
1519
-            'TKT_subtotal_amount'           => $ticket_subtotal,
1520
-            'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1521
-            'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1522
-            'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1523
-                ? ' ticket-archived'
1524
-                : '',
1525
-            'trash_icon'                    => $ticket instanceof EE_Ticket
1526
-                                               && $ticket->deleted()
1527
-                                               && ! $ticket->is_permanently_deleteable()
1528
-                ? 'ee-lock-icon '
1529
-                : 'trash-icon dashicons dashicons-post-trash clickable',
1530
-            'clone_icon'                    => $ticket instanceof EE_Ticket && $ticket->deleted()
1531
-                ? ''
1532
-                : 'clone-icon ee-icon ee-icon-clone clickable',
1533
-        );
1534
-        $template_args['trash_hidden'] = count($all_tickets) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1535
-            ? ' style="display:none"'
1536
-            : '';
1537
-        //handle rows that should NOT be empty
1538
-        if (empty($template_args['TKT_start_date'])) {
1539
-            //if empty then the start date will be now.
1540
-            $template_args['TKT_start_date'] = date($this->_date_time_format,
1541
-                current_time('timestamp'));
1542
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1543
-        }
1544
-        if (empty($template_args['TKT_end_date'])) {
1545
-            //get the earliest datetime (if present);
1546
-            $earliest_dtt = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1547
-                ? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1548
-                    'Datetime',
1549
-                    array('order_by' => array('DTT_EVT_start' => 'ASC'))
1550
-                )
1551
-                : null;
1552
-            if (! empty($earliest_dtt)) {
1553
-                $template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1554
-                    'DTT_EVT_start',
1555
-                    $this->_date_time_format
1556
-                );
1557
-            } else {
1558
-                //default so let's just use what's been set for the default date-time which is 30 days from now.
1559
-                $template_args['TKT_end_date'] = date(
1560
-                    $this->_date_time_format,
1561
-                    mktime(24, 0, 0, date('m'), date('d') + 29, date('Y')
1562
-                    )
1563
-                );
1564
-            }
1565
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1566
-        }
1567
-        //generate ticket_datetime items
1568
-        if (! $default) {
1569
-            $datetime_row = 1;
1570
-            foreach ($all_datetimes as $datetime) {
1571
-                $template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1572
-                    $datetime_row,
1573
-                    $ticket_row,
1574
-                    $datetime,
1575
-                    $ticket,
1576
-                    $ticket_datetimes,
1577
-                    $default
1578
-                );
1579
-                $datetime_row++;
1580
-            }
1581
-        }
1582
-        $price_row = 1;
1583
-        foreach ($prices as $price) {
1584
-            if (! $price instanceof EE_Price)  {
1585
-                continue;
1586
-            }
1587
-            if ($price->is_base_price()) {
1588
-                $price_row++;
1589
-                continue;
1590
-            }
1591
-            $show_trash = !((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1592
-            $show_create = !(count($prices) > 1 && count($prices) !== $price_row);
1593
-            $template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1594
-                $ticket_row,
1595
-                $price_row,
1596
-                $price,
1597
-                $default,
1598
-                $ticket,
1599
-                $show_trash,
1600
-                $show_create
1601
-            );
1602
-            $price_row++;
1603
-        }
1604
-        //filter $template_args
1605
-        $template_args = apply_filters(
1606
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1607
-            $template_args,
1608
-            $ticket_row,
1609
-            $ticket,
1610
-            $ticket_datetimes,
1611
-            $all_datetimes,
1612
-            $default,
1613
-            $all_tickets,
1614
-            $this->_is_creating_event
1615
-        );
1616
-        return EEH_Template::display_template(
1617
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1618
-            $template_args,
1619
-            true
1620
-        );
1621
-    }
1622
-
1623
-
1624
-
1625
-    /**
1626
-     * @param int            $ticket_row
1627
-     * @param EE_Ticket|null $ticket
1628
-     * @return string
1629
-     * @throws DomainException
1630
-     * @throws EE_Error
1631
-     */
1632
-    protected function _get_tax_rows($ticket_row, $ticket)
1633
-    {
1634
-        $tax_rows = '';
1635
-        /** @var EE_Price[] $taxes */
1636
-        $taxes = empty($ticket) ? EE_Taxes::get_taxes_for_admin() : $ticket->get_ticket_taxes_for_admin();
1637
-        foreach ($taxes as $tax) {
1638
-            $tax_added = $this->_get_tax_added($tax, $ticket);
1639
-            $template_args = array(
1640
-                'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1641
-                    ? ''
1642
-                    : ' style="display:none;"',
1643
-                'tax_id'            => $tax->ID(),
1644
-                'tkt_row'           => $ticket_row,
1645
-                'tax_label'         => $tax->get('PRC_name'),
1646
-                'tax_added'         => $tax_added,
1647
-                'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1648
-                'tax_amount'        => $tax->get('PRC_amount'),
1649
-            );
1650
-            $template_args = apply_filters(
1651
-                'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1652
-                $template_args,
1653
-                $ticket_row,
1654
-                $ticket,
1655
-                $this->_is_creating_event
1656
-            );
1657
-            $tax_rows .= EEH_Template::display_template(
1658
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1659
-                $template_args,
1660
-                true
1661
-            );
1662
-        }
1663
-        return $tax_rows;
1664
-    }
1665
-
1666
-
1667
-
1668
-    /**
1669
-     * @param EE_Price       $tax
1670
-     * @param EE_Ticket|null $ticket
1671
-     * @return float|int
1672
-     * @throws EE_Error
1673
-     */
1674
-    protected function _get_tax_added(EE_Price $tax, $ticket)
1675
-    {
1676
-        $subtotal = empty($ticket) ? 0 : $ticket->get_ticket_subtotal();
1677
-        return $subtotal * $tax->get('PRC_amount') / 100;
1678
-    }
1679
-
1680
-
1681
-
1682
-    /**
1683
-     * @param int            $ticket_row
1684
-     * @param int            $price_row
1685
-     * @param EE_Price|null  $price
1686
-     * @param bool           $default
1687
-     * @param EE_Ticket|null $ticket
1688
-     * @param bool           $show_trash
1689
-     * @param bool           $show_create
1690
-     * @return mixed
1691
-     * @throws DomainException
1692
-     * @throws EE_Error
1693
-     */
1694
-    protected function _get_ticket_price_row(
1695
-        $ticket_row,
1696
-        $price_row,
1697
-        $price,
1698
-        $default,
1699
-        $ticket,
1700
-        $show_trash = true,
1701
-        $show_create = true
1702
-    ) {
1703
-        $send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1704
-        $template_args = array(
1705
-            'tkt_row'               => $default && empty($ticket)
1706
-                ? 'TICKETNUM'
1707
-                : $ticket_row,
1708
-            'PRC_order'             => $default && empty($price)
1709
-                ? 'PRICENUM'
1710
-                : $price_row,
1711
-            'edit_prices_name'      => $default && empty($price)
1712
-                ? 'PRICENAMEATTR'
1713
-                : 'edit_prices',
1714
-            'price_type_selector'   => $default && empty($price)
1715
-                ? $this->_get_base_price_template($ticket_row, $price_row, $price, $default)
1716
-                : $this->_get_price_type_selector($ticket_row, $price_row, $price, $default, $send_disabled),
1717
-            'PRC_ID'                => $default && empty($price)
1718
-                ? 0
1719
-                : $price->ID(),
1720
-            'PRC_is_default'        => $default && empty($price)
1721
-                ? 0
1722
-                : $price->get('PRC_is_default'),
1723
-            'PRC_name'              => $default && empty($price)
1724
-                ? ''
1725
-                : $price->get('PRC_name'),
1726
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1727
-            'show_plus_or_minus'    => $default && empty($price)
1728
-                ? ''
1729
-                : ' style="display:none;"',
1730
-            'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1731
-                ? ' style="display:none;"'
1732
-                : '',
1733
-            'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1734
-                ? ' style="display:none;"'
1735
-                : '',
1736
-            'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1737
-                ? ' style="display:none"'
1738
-                : '',
1739
-            'PRC_amount'            => $default && empty($price)
1740
-                ? 0
1741
-                : $price->get_pretty('PRC_amount',
1742
-                    'localized_float'),
1743
-            'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1744
-                ? ' style="display:none;"'
1745
-                : '',
1746
-            'show_trash_icon'       => $show_trash
1747
-                ? ''
1748
-                : ' style="display:none;"',
1749
-            'show_create_button'    => $show_create
1750
-                ? ''
1751
-                : ' style="display:none;"',
1752
-            'PRC_desc'              => $default && empty($price)
1753
-                ? ''
1754
-                : $price->get('PRC_desc'),
1755
-            'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1756
-        );
1757
-        $template_args = apply_filters(
1758
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1759
-            $template_args,
1760
-            $ticket_row,
1761
-            $price_row,
1762
-            $price,
1763
-            $default,
1764
-            $ticket,
1765
-            $show_trash,
1766
-            $show_create,
1767
-            $this->_is_creating_event
1768
-        );
1769
-        return EEH_Template::display_template(
1770
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1771
-            $template_args,
1772
-            true
1773
-        );
1774
-    }
1775
-
1776
-
1777
-
1778
-    /**
1779
-     * @param int      $ticket_row
1780
-     * @param int      $price_row
1781
-     * @param EE_Price $price
1782
-     * @param bool     $default
1783
-     * @param bool     $disabled
1784
-     * @return mixed
1785
-     * @throws DomainException
1786
-     * @throws EE_Error
1787
-     */
1788
-    protected function _get_price_type_selector($ticket_row, $price_row, $price, $default, $disabled = false)
1789
-    {
1790
-        if ($price->is_base_price()) {
1791
-            return $this->_get_base_price_template($ticket_row, $price_row, $price, $default);
1792
-        }
1793
-        return $this->_get_price_modifier_template($ticket_row, $price_row, $price, $default, $disabled);
1794
-    }
1795
-
1796
-
1797
-
1798
-    /**
1799
-     * @param int      $ticket_row
1800
-     * @param int      $price_row
1801
-     * @param EE_Price $price
1802
-     * @param bool     $default
1803
-     * @return mixed
1804
-     * @throws DomainException
1805
-     * @throws EE_Error
1806
-     */
1807
-    protected function _get_base_price_template($ticket_row, $price_row, $price, $default)
1808
-    {
1809
-        $template_args = array(
1810
-            'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1811
-            'PRC_order'                 => $default && empty($price) ? 'PRICENUM' : $price_row,
1812
-            'PRT_ID'                    => $default && empty($price) ? 1 : $price->get('PRT_ID'),
1813
-            'PRT_name'                  => esc_html__('Price', 'event_espresso'),
1814
-            'price_selected_operator'   => '+',
1815
-            'price_selected_is_percent' => 0,
1816
-        );
1817
-        $template_args = apply_filters(
1818
-            'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
1819
-            $template_args,
1820
-            $ticket_row,
1821
-            $price_row,
1822
-            $price,
1823
-            $default,
1824
-            $this->_is_creating_event
1825
-        );
1826
-        return EEH_Template::display_template(
1827
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1828
-            $template_args,
1829
-            true
1830
-        );
1831
-    }
1832
-
1833
-
1834
-
1835
-    /**
1836
-     * @param int      $ticket_row
1837
-     * @param int      $price_row
1838
-     * @param EE_Price $price
1839
-     * @param bool     $default
1840
-     * @param bool     $disabled
1841
-     * @return mixed
1842
-     * @throws DomainException
1843
-     * @throws EE_Error
1844
-     */
1845
-    protected function _get_price_modifier_template(
1846
-        $ticket_row,
1847
-        $price_row,
1848
-        $price,
1849
-        $default,
1850
-        $disabled = false
1851
-    ) {
1852
-        $select_name = $default && ! $price instanceof EE_Price
1853
-            ? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1854
-            : 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1855
-        /** @var EEM_Price_Type $price_type_model */
1856
-        $price_type_model = EE_Registry::instance()->load_model('Price_Type');
1857
-        $price_types = $price_type_model->get_all(array(
1858
-            array(
1859
-                'OR' => array(
1860
-                    'PBT_ID'  => '2',
1861
-                    'PBT_ID*' => '3',
1862
-                ),
1863
-            ),
1864
-        ));
1865
-        $all_price_types = $default && ! $price instanceof EE_Price
1866
-            ? array(esc_html__('Select Modifier', 'event_espresso'))
1867
-            : array();
1868
-        $selected_price_type_id = $default && ! $price instanceof EE_Price ? 0 : $price->type();
1869
-        $price_option_spans = '';
1870
-        //setup price types for selector
1871
-        foreach ($price_types as $price_type) {
1872
-            if (! $price_type instanceof EE_Price_Type) {
1873
-                continue;
1874
-            }
1875
-            $all_price_types[$price_type->ID()] = $price_type->get('PRT_name');
1876
-            //while we're in the loop let's setup the option spans used by js
1877
-            $span_args = array(
1878
-                'PRT_ID'         => $price_type->ID(),
1879
-                'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1880
-                'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1881
-            );
1882
-            $price_option_spans .= EEH_Template::display_template(
1883
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1884
-                $span_args,
1885
-                true
1886
-            );
1887
-        }
1888
-        $select_name = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]' : $select_name;
1889
-        $select_input = new EE_Select_Input(
1890
-            $all_price_types,
1891
-            array(
1892
-                'default'               => $selected_price_type_id,
1893
-                'html_name'             => $select_name,
1894
-                'html_class'            => 'edit-price-PRT_ID',
1895
-                'html_other_attributes' => $disabled ? 'style="width:auto;" disabled' : 'style="width:auto;"',
1896
-            )
1897
-        );
1898
-        $price_selected_operator = $price instanceof EE_Price && $price->is_discount() ? '-' : '+';
1899
-        $price_selected_operator = $default && ! $price instanceof EE_Price ? '' : $price_selected_operator;
1900
-        $price_selected_is_percent = $price instanceof EE_Price && $price->is_percent() ? 1 : 0;
1901
-        $price_selected_is_percent = $default && ! $price instanceof EE_Price ? '' : $price_selected_is_percent;
1902
-        $template_args = array(
1903
-            'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1904
-            'PRC_order'                 => $default && ! $price instanceof EE_Price ? 'PRICENUM' : $price_row,
1905
-            'price_modifier_selector'   => $select_input->get_html_for_input(),
1906
-            'main_name'                 => $select_name,
1907
-            'selected_price_type_id'    => $selected_price_type_id,
1908
-            'price_option_spans'        => $price_option_spans,
1909
-            'price_selected_operator'   => $price_selected_operator,
1910
-            'price_selected_is_percent' => $price_selected_is_percent,
1911
-            'disabled'                  => $disabled,
1912
-        );
1913
-        $template_args = apply_filters(
1914
-            'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1915
-            $template_args,
1916
-            $ticket_row,
1917
-            $price_row,
1918
-            $price,
1919
-            $default,
1920
-            $disabled,
1921
-            $this->_is_creating_event
1922
-        );
1923
-        return EEH_Template::display_template(
1924
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
1925
-            $template_args,
1926
-            true
1927
-        );
1928
-    }
1929
-
1930
-
1931
-
1932
-    /**
1933
-     * @param int              $datetime_row
1934
-     * @param int              $ticket_row
1935
-     * @param EE_Datetime|null $datetime
1936
-     * @param EE_Ticket|null   $ticket
1937
-     * @param array            $ticket_datetimes
1938
-     * @param bool             $default
1939
-     * @return mixed
1940
-     * @throws DomainException
1941
-     * @throws EE_Error
1942
-     */
1943
-    protected function _get_ticket_datetime_list_item(
1944
-        $datetime_row,
1945
-        $ticket_row,
1946
-        $datetime,
1947
-        $ticket,
1948
-        $ticket_datetimes = array(),
1949
-        $default
1950
-    ) {
1951
-        $tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
1952
-            ? $ticket_datetimes[$ticket->ID()]
1953
-            : array();
1954
-        $template_args = array(
1955
-            'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
1956
-                ? 'DTTNUM'
1957
-                : $datetime_row,
1958
-            'tkt_row'                  => $default
1959
-                ? 'TICKETNUM'
1960
-                : $ticket_row,
1961
-            'ticket_datetime_selected' => in_array($datetime_row, $tkt_datetimes, true)
1962
-                ? ' ticket-selected'
1963
-                : '',
1964
-            'ticket_datetime_checked'  => in_array($datetime_row, $tkt_datetimes, true)
1965
-                ? ' checked="checked"'
1966
-                : '',
1967
-            'DTT_name'                 => $default && empty($datetime)
1968
-                ? 'DTTNAME'
1969
-                : $datetime->get_dtt_display_name(true),
1970
-            'tkt_status_class'         => '',
1971
-        );
1972
-        $template_args = apply_filters(
1973
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
1974
-            $template_args,
1975
-            $datetime_row,
1976
-            $ticket_row,
1977
-            $datetime,
1978
-            $ticket,
1979
-            $ticket_datetimes,
1980
-            $default,
1981
-            $this->_is_creating_event
1982
-        );
1983
-        return EEH_Template::display_template(
1984
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
1985
-            $template_args,
1986
-            true
1987
-        );
1988
-    }
1989
-
1990
-
1991
-
1992
-    /**
1993
-     * @param array $all_datetimes
1994
-     * @param array $all_tickets
1995
-     * @return mixed
1996
-     * @throws DomainException
1997
-     * @throws EE_Error
1998
-     */
1999
-    protected function _get_ticket_js_structure($all_datetimes = array(), $all_tickets = array())
2000
-    {
2001
-        $template_args = array(
2002
-            'default_datetime_edit_row'                => $this->_get_dtt_edit_row(
2003
-                'DTTNUM',
2004
-                null,
2005
-                true,
2006
-                $all_datetimes
2007
-            ),
2008
-            'default_ticket_row'                       => $this->_get_ticket_row(
2009
-                'TICKETNUM',
2010
-                null,
2011
-                array(),
2012
-                array(),
2013
-                true
2014
-            ),
2015
-            'default_price_row'                        => $this->_get_ticket_price_row(
2016
-                'TICKETNUM',
2017
-                'PRICENUM',
2018
-                null,
2019
-                true,
2020
-                null
2021
-            ),
2022
-            'default_price_rows'                       => '',
2023
-            'default_base_price_amount'                => 0,
2024
-            'default_base_price_name'                  => '',
2025
-            'default_base_price_description'           => '',
2026
-            'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2027
-                'TICKETNUM',
2028
-                'PRICENUM',
2029
-                null,
2030
-                true
2031
-            ),
2032
-            'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2033
-                'DTTNUM',
2034
-                null,
2035
-                array(),
2036
-                array(),
2037
-                true
2038
-            ),
2039
-            'existing_available_datetime_tickets_list' => '',
2040
-            'existing_available_ticket_datetimes_list' => '',
2041
-            'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2042
-                'DTTNUM',
2043
-                'TICKETNUM',
2044
-                null,
2045
-                null,
2046
-                array(),
2047
-                true
2048
-            ),
2049
-            'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2050
-                'DTTNUM',
2051
-                'TICKETNUM',
2052
-                null,
2053
-                null,
2054
-                array(),
2055
-                true
2056
-            ),
2057
-        );
2058
-        $ticket_row = 1;
2059
-        foreach ($all_tickets as $ticket) {
2060
-            $template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2061
-                'DTTNUM',
2062
-                $ticket_row,
2063
-                null,
2064
-                $ticket,
2065
-                array(),
2066
-                true
2067
-            );
2068
-            $ticket_row++;
2069
-        }
2070
-        $datetime_row = 1;
2071
-        foreach ($all_datetimes as $datetime) {
2072
-            $template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2073
-                $datetime_row,
2074
-                'TICKETNUM',
2075
-                $datetime,
2076
-                null,
2077
-                array(),
2078
-                true
2079
-            );
2080
-            $datetime_row++;
2081
-        }
2082
-        /** @var EEM_Price $price_model */
2083
-        $price_model = EE_Registry::instance()->load_model('Price');
2084
-        $default_prices = $price_model->get_all_default_prices();
2085
-        $price_row = 1;
2086
-        foreach ($default_prices as $price) {
2087
-            if (! $price instanceof EE_Price) {
2088
-                continue;
2089
-            }
2090
-            if ($price->is_base_price()) {
2091
-                $template_args['default_base_price_amount'] = $price->get_pretty(
2092
-                    'PRC_amount',
2093
-                    'localized_float'
2094
-                );
2095
-                $template_args['default_base_price_name'] = $price->get('PRC_name');
2096
-                $template_args['default_base_price_description'] = $price->get('PRC_desc');
2097
-                $price_row++;
2098
-                continue;
2099
-            }
2100
-            $show_trash = !((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2101
-            $show_create = !(count($default_prices) > 1 && count($default_prices) !== $price_row);
2102
-            $template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2103
-                'TICKETNUM',
2104
-                $price_row,
2105
-                $price,
2106
-                true,
2107
-                null,
2108
-                $show_trash,
2109
-                $show_create
2110
-            );
2111
-            $price_row++;
2112
-        }
2113
-        $template_args = apply_filters(
2114
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2115
-            $template_args,
2116
-            $all_datetimes,
2117
-            $all_tickets,
2118
-            $this->_is_creating_event
2119
-        );
2120
-        return EEH_Template::display_template(
2121
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2122
-            $template_args,
2123
-            true
2124
-        );
2125
-    }
18
+	/**
19
+	 * This property is just used to hold the status of whether an event is currently being
20
+	 * created (true) or edited (false)
21
+	 *
22
+	 * @access protected
23
+	 * @var bool
24
+	 */
25
+	protected $_is_creating_event;
26
+
27
+
28
+	/**
29
+	 * Used to contain the format strings for date and time that will be used for php date and
30
+	 * time.
31
+	 * Is set in the _set_hooks_properties() method.
32
+	 *
33
+	 * @var array
34
+	 */
35
+	protected $_date_format_strings;
36
+
37
+
38
+	/**
39
+	 * @var string $_date_time_format
40
+	 */
41
+	protected $_date_time_format;
42
+
43
+
44
+
45
+	/**
46
+	 *
47
+	 */
48
+	protected function _set_hooks_properties()
49
+	{
50
+		$this->_name = 'pricing';
51
+		//capability check
52
+		if (! EE_Registry::instance()->CAP->current_user_can(
53
+			'ee_read_default_prices',
54
+			'advanced_ticket_datetime_metabox'
55
+		)) {
56
+			return;
57
+		}
58
+		$this->_setup_metaboxes();
59
+		$this->_set_date_time_formats();
60
+		$this->_validate_format_strings();
61
+		$this->_set_scripts_styles();
62
+		// commented out temporarily until logic is implemented in callback
63
+		// add_action(
64
+		//     'AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_Extend_Events_Admin_Page',
65
+		//     array($this, 'autosave_handling')
66
+		// );
67
+		add_filter(
68
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
69
+			array($this, 'caf_updates')
70
+		);
71
+	}
72
+
73
+
74
+
75
+	/**
76
+	 * @return void
77
+	 */
78
+	protected function _setup_metaboxes()
79
+	{
80
+		//if we were going to add our own metaboxes we'd use the below.
81
+		$this->_metaboxes = array(
82
+			0 => array(
83
+				'page_route' => array('edit', 'create_new'),
84
+				'func'       => 'pricing_metabox',
85
+				'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
86
+				'priority'   => 'high',
87
+				'context'    => 'normal',
88
+			),
89
+		);
90
+		$this->_remove_metaboxes = array(
91
+			0 => array(
92
+				'page_route' => array('edit', 'create_new'),
93
+				'id'         => 'espresso_event_editor_tickets',
94
+				'context'    => 'normal',
95
+			),
96
+		);
97
+	}
98
+
99
+
100
+
101
+	/**
102
+	 * @return void
103
+	 */
104
+	protected function _set_date_time_formats()
105
+	{
106
+		/**
107
+		 * Format strings for date and time.  Defaults are existing behaviour from 4.1.
108
+		 * Note, that if you return null as the value for 'date', and 'time' in the array, then
109
+		 * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
110
+		 *
111
+		 * @since 4.6.7
112
+		 * @var array  Expected an array returned with 'date' and 'time' keys.
113
+		 */
114
+		$this->_date_format_strings = apply_filters(
115
+			'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
116
+			array(
117
+				'date' => 'Y-m-d',
118
+				'time' => 'h:i a',
119
+			)
120
+		);
121
+		//validate
122
+		$this->_date_format_strings['date'] = isset($this->_date_format_strings['date'])
123
+			? $this->_date_format_strings['date']
124
+			: null;
125
+		$this->_date_format_strings['time'] = isset($this->_date_format_strings['time'])
126
+			? $this->_date_format_strings['time']
127
+			: null;
128
+		$this->_date_time_format = $this->_date_format_strings['date'] . ' ' . $this->_date_format_strings['time'];
129
+	}
130
+
131
+
132
+
133
+	/**
134
+	 * @return void
135
+	 */
136
+	protected function _validate_format_strings()
137
+	{
138
+		//validate format strings
139
+		$format_validation = EEH_DTT_Helper::validate_format_string(
140
+			$this->_date_time_format
141
+		);
142
+		if (is_array($format_validation)) {
143
+			$msg = '<p>';
144
+			$msg .= sprintf(
145
+				esc_html__(
146
+					'The format "%s" was likely added via a filter and is invalid for the following reasons:',
147
+					'event_espresso'
148
+				),
149
+				$this->_date_time_format
150
+			);
151
+			$msg .= '</p><ul>';
152
+			foreach ($format_validation as $error) {
153
+				$msg .= '<li>' . $error . '</li>';
154
+			}
155
+			$msg .= '</ul><p>';
156
+			$msg .= sprintf(
157
+				esc_html__(
158
+					'%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
159
+					'event_espresso'
160
+				),
161
+				'<span style="color:#D54E21;">',
162
+				'</span>'
163
+			);
164
+			$msg .= '</p>';
165
+			EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
166
+			$this->_date_format_strings = array(
167
+				'date' => 'Y-m-d',
168
+				'time' => 'h:i a',
169
+			);
170
+		}
171
+	}
172
+
173
+
174
+
175
+	/**
176
+	 * @return void
177
+	 */
178
+	protected function _set_scripts_styles()
179
+	{
180
+		$this->_scripts_styles = array(
181
+			'registers'   => array(
182
+				'ee-tickets-datetimes-css' => array(
183
+					'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
184
+					'type' => 'css',
185
+				),
186
+				'ee-dtt-ticket-metabox'    => array(
187
+					'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
188
+					'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
189
+				),
190
+			),
191
+			'deregisters' => array(
192
+				'event-editor-css'       => array('type' => 'css'),
193
+				'event-datetime-metabox' => array('type' => 'js'),
194
+			),
195
+			'enqueues'    => array(
196
+				'ee-tickets-datetimes-css' => array('edit', 'create_new'),
197
+				'ee-dtt-ticket-metabox'    => array('edit', 'create_new'),
198
+			),
199
+			'localize'    => array(
200
+				'ee-dtt-ticket-metabox' => array(
201
+					'DTT_TRASH_BLOCK'       => array(
202
+						'main_warning'            => esc_html__(
203
+							'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
204
+							'event_espresso'
205
+						),
206
+						'after_warning'           => esc_html__(
207
+							'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
208
+							'event_espresso'
209
+						),
210
+						'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
211
+													 . esc_html__('Cancel', 'event_espresso') . '</button>',
212
+						'close_button'            => '<button class="button-secondary ee-modal-cancel">'
213
+													 . esc_html__('Close', 'event_espresso') . '</button>',
214
+						'single_warning_from_tkt' => esc_html__(
215
+							'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
216
+							'event_espresso'
217
+						),
218
+						'single_warning_from_dtt' => esc_html__(
219
+							'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
220
+							'event_espresso'
221
+						),
222
+						'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
223
+													 . esc_html__('Dismiss', 'event_espresso') . '</button>',
224
+					),
225
+					'DTT_ERROR_MSG'         => array(
226
+						'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
227
+						'dismiss_button' => '<div class="save-cancel-button-container"><button class="button-secondary ee-modal-cancel">'
228
+											. esc_html__('Dismiss', 'event_espresso') . '</button></div>',
229
+					),
230
+					'DTT_OVERSELL_WARNING'  => array(
231
+						'datetime_ticket' => esc_html__(
232
+							'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
233
+							'event_espresso'
234
+						),
235
+						'ticket_datetime' => esc_html__(
236
+							'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
237
+							'event_espresso'
238
+						),
239
+					),
240
+					'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
241
+						$this->_date_format_strings['date'],
242
+						$this->_date_format_strings['time']
243
+					),
244
+					'DTT_START_OF_WEEK'     => array('dayValue' => (int)get_option('start_of_week')),
245
+				),
246
+			),
247
+		);
248
+	}
249
+
250
+
251
+
252
+	/**
253
+	 * @param array $update_callbacks
254
+	 * @return array
255
+	 */
256
+	public function caf_updates(array $update_callbacks)
257
+	{
258
+		foreach ($update_callbacks as $key => $callback) {
259
+			if ($callback[1] === '_default_tickets_update') {
260
+				unset($update_callbacks[$key]);
261
+			}
262
+		}
263
+		$update_callbacks[] = array($this, 'datetime_and_tickets_caf_update');
264
+		return $update_callbacks;
265
+	}
266
+
267
+
268
+	/**
269
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
270
+	 *
271
+	 * @param  EE_Event $event The Event object we're attaching data to
272
+	 * @param  array $data The request data from the form
273
+	 * @throws EE_Error
274
+	 * @throws InvalidArgumentException
275
+	 */
276
+	public function datetime_and_tickets_caf_update($event, $data)
277
+	{
278
+		//first we need to start with datetimes cause they are the "root" items attached to events.
279
+		$saved_datetimes = $this->_update_datetimes($event, $data);
280
+		//next tackle the tickets (and prices?)
281
+		$this->_update_tickets($event, $saved_datetimes, $data);
282
+	}
283
+
284
+
285
+	/**
286
+	 * update event_datetimes
287
+	 *
288
+	 * @param  EE_Event $event Event being updated
289
+	 * @param  array $data the request data from the form
290
+	 * @return EE_Datetime[]
291
+	 * @throws InvalidArgumentException
292
+	 * @throws EE_Error
293
+	 */
294
+	protected function _update_datetimes($event, $data)
295
+	{
296
+		$timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
297
+		$saved_dtt_ids = array();
298
+		$saved_dtt_objs = array();
299
+		if (empty($data['edit_event_datetimes']) || !is_array($data['edit_event_datetimes'])) {
300
+			throw new InvalidArgumentException(
301
+				esc_html__(
302
+					'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
303
+					'event_espresso'
304
+				)
305
+			);
306
+		}
307
+		foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
308
+			//trim all values to ensure any excess whitespace is removed.
309
+			$datetime_data = array_map(
310
+				function ($datetime_data) {
311
+					return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
312
+				},
313
+				$datetime_data
314
+			);
315
+			$datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
316
+											&& ! empty($datetime_data['DTT_EVT_end'])
317
+				? $datetime_data['DTT_EVT_end']
318
+				: $datetime_data['DTT_EVT_start'];
319
+			$datetime_values = array(
320
+				'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
321
+					? $datetime_data['DTT_ID']
322
+					: null,
323
+				'DTT_name'        => ! empty($datetime_data['DTT_name'])
324
+					? $datetime_data['DTT_name']
325
+					: '',
326
+				'DTT_description' => ! empty($datetime_data['DTT_description'])
327
+					? $datetime_data['DTT_description']
328
+					: '',
329
+				'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
330
+				'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
331
+				'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
332
+					? EE_INF
333
+					: $datetime_data['DTT_reg_limit'],
334
+				'DTT_order'       => ! isset($datetime_data['DTT_order'])
335
+					? $row
336
+					: $datetime_data['DTT_order'],
337
+			);
338
+			// if we have an id then let's get existing object first and then set the new values.
339
+			// Otherwise we instantiate a new object for save.
340
+			if (! empty($datetime_data['DTT_ID'])) {
341
+				$datetime = EE_Registry::instance()
342
+									   ->load_model('Datetime', array($timezone))
343
+									   ->get_one_by_ID($datetime_data['DTT_ID']);
344
+				//set date and time format according to what is set in this class.
345
+				$datetime->set_date_format($this->_date_format_strings['date']);
346
+				$datetime->set_time_format($this->_date_format_strings['time']);
347
+				foreach ($datetime_values as $field => $value) {
348
+					$datetime->set($field, $value);
349
+				}
350
+				// make sure the $dtt_id here is saved just in case
351
+				// after the add_relation_to() the autosave replaces it.
352
+				// We need to do this so we dont' TRASH the parent DTT.
353
+				// (save the ID for both key and value to avoid duplications)
354
+				$saved_dtt_ids[$datetime->ID()] = $datetime->ID();
355
+			} else {
356
+				$datetime = EE_Registry::instance()->load_class(
357
+					'Datetime',
358
+					array(
359
+						$datetime_values,
360
+						$timezone,
361
+						array($this->_date_format_strings['date'], $this->_date_format_strings['time']),
362
+					),
363
+					false,
364
+					false
365
+				);
366
+				foreach ($datetime_values as $field => $value) {
367
+					$datetime->set($field, $value);
368
+				}
369
+			}
370
+			$datetime->save();
371
+			$datetime = $event->_add_relation_to($datetime, 'Datetime');
372
+			// before going any further make sure our dates are setup correctly
373
+			// so that the end date is always equal or greater than the start date.
374
+			if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
375
+				$datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
376
+				$datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
377
+				$datetime->save();
378
+			}
379
+			//	now we have to make sure we add the new DTT_ID to the $saved_dtt_ids array
380
+			// because it is possible there was a new one created for the autosave.
381
+			// (save the ID for both key and value to avoid duplications)
382
+			$DTT_ID = $datetime->ID();
383
+			$saved_dtt_ids[$DTT_ID] = $DTT_ID;
384
+			$saved_dtt_objs[$row] = $datetime;
385
+			//todo if ANY of these updates fail then we want the appropriate global error message.
386
+		}
387
+		$event->save();
388
+		// now we need to REMOVE any datetimes that got deleted.
389
+		// Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
390
+		// So its safe to permanently delete at this point.
391
+		$old_datetimes = explode(',', $data['datetime_IDs']);
392
+		$old_datetimes = $old_datetimes[0] === '' ? array() : $old_datetimes;
393
+		if (is_array($old_datetimes)) {
394
+			$datetimes_to_delete = array_diff($old_datetimes, $saved_dtt_ids);
395
+			foreach ($datetimes_to_delete as $id) {
396
+				$id = absint($id);
397
+				if (empty($id)) {
398
+					continue;
399
+				}
400
+				$dtt_to_remove = EE_Registry::instance()->load_model('Datetime')->get_one_by_ID($id);
401
+				//remove tkt relationships.
402
+				$related_tickets = $dtt_to_remove->get_many_related('Ticket');
403
+				foreach ($related_tickets as $tkt) {
404
+					$dtt_to_remove->_remove_relation_to($tkt, 'Ticket');
405
+				}
406
+				$event->_remove_relation_to($id, 'Datetime');
407
+				$dtt_to_remove->refresh_cache_of_related_objects();
408
+			}
409
+		}
410
+		return $saved_dtt_objs;
411
+	}
412
+
413
+
414
+	/**
415
+	 * update tickets
416
+	 *
417
+	 * @param  EE_Event $event Event object being updated
418
+	 * @param  EE_Datetime[] $saved_datetimes an array of datetime ids being updated
419
+	 * @param  array $data incoming request data
420
+	 * @return EE_Ticket[]
421
+	 * @throws InvalidArgumentException
422
+	 * @throws EE_Error
423
+	 */
424
+	protected function _update_tickets($event, $saved_datetimes, $data)
425
+	{
426
+		$new_tkt = null;
427
+		$new_default = null;
428
+		//stripslashes because WP filtered the $_POST ($data) array to add slashes
429
+		$data = stripslashes_deep($data);
430
+		$timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
431
+		$saved_tickets = $datetimes_on_existing = array();
432
+		$old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
433
+		if(empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])){
434
+			throw new InvalidArgumentException(
435
+				esc_html__(
436
+					'The "edit_tickets" array is invalid therefore the event can not be updated.',
437
+					'event_espresso'
438
+				)
439
+			);
440
+		}
441
+		foreach ($data['edit_tickets'] as $row => $tkt) {
442
+			$update_prices = $create_new_TKT = false;
443
+			// figure out what datetimes were added to the ticket
444
+			// and what datetimes were removed from the ticket in the session.
445
+			$starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][$row]);
446
+			$tkt_dtt_rows = explode(',', $data['ticket_datetime_rows'][$row]);
447
+			$datetimes_added = array_diff($tkt_dtt_rows, $starting_tkt_dtt_rows);
448
+			$datetimes_removed = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
449
+			// trim inputs to ensure any excess whitespace is removed.
450
+			$tkt = array_map(
451
+				function ($ticket_data) {
452
+					return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
453
+				},
454
+				$tkt
455
+			);
456
+			// note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
457
+			// because we're doing calculations prior to using the models.
458
+			// note incoming ['TKT_price'] value is already in standard notation (via js).
459
+			$ticket_price = isset($tkt['TKT_price'])
460
+				? round((float)$tkt['TKT_price'], 3)
461
+				: 0;
462
+			//note incoming base price needs converted from localized value.
463
+			$base_price = isset($tkt['TKT_base_price'])
464
+				? EEH_Money::convert_to_float_from_localized_money($tkt['TKT_base_price'])
465
+				: 0;
466
+			//if ticket price == 0 and $base_price != 0 then ticket price == base_price
467
+			$ticket_price = $ticket_price === 0 && $base_price !== 0
468
+				? $base_price
469
+				: $ticket_price;
470
+			$base_price_id = isset($tkt['TKT_base_price_ID'])
471
+				? $tkt['TKT_base_price_ID']
472
+				: 0;
473
+			$price_rows = is_array($data['edit_prices']) && isset($data['edit_prices'][$row])
474
+				? $data['edit_prices'][$row]
475
+				: array();
476
+			$now = null;
477
+			if (empty($tkt['TKT_start_date'])) {
478
+				//lets' use now in the set timezone.
479
+				$now = new DateTime('now', new DateTimeZone($event->get_timezone()));
480
+				$tkt['TKT_start_date'] = $now->format($this->_date_time_format);
481
+			}
482
+			if (empty($tkt['TKT_end_date'])) {
483
+				/**
484
+				 * set the TKT_end_date to the first datetime attached to the ticket.
485
+				 */
486
+				$first_dtt = $saved_datetimes[reset($tkt_dtt_rows)];
487
+				$tkt['TKT_end_date'] = $first_dtt->start_date_and_time($this->_date_time_format);
488
+			}
489
+			$TKT_values = array(
490
+				'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
491
+				'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
492
+				'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
493
+				'TKT_description' => ! empty($tkt['TKT_description'])
494
+									 && $tkt['TKT_description'] !== esc_html__(
495
+					'You can modify this description',
496
+					'event_espresso'
497
+				)
498
+					? $tkt['TKT_description']
499
+					: '',
500
+				'TKT_start_date'  => $tkt['TKT_start_date'],
501
+				'TKT_end_date'    => $tkt['TKT_end_date'],
502
+				'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === ''
503
+					? EE_INF
504
+					: $tkt['TKT_qty'],
505
+				'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === ''
506
+					? EE_INF
507
+					: $tkt['TKT_uses'],
508
+				'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
509
+				'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
510
+				'TKT_row'         => $row,
511
+				'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : 0,
512
+				'TKT_taxable'     => ! empty($tkt['TKT_taxable']) ? 1 : 0,
513
+				'TKT_required'    => ! empty($tkt['TKT_required']) ? 1 : 0,
514
+				'TKT_price'       => $ticket_price,
515
+			);
516
+			// if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
517
+			// which means in turn that the prices will become new prices as well.
518
+			if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
519
+				$TKT_values['TKT_ID'] = 0;
520
+				$TKT_values['TKT_is_default'] = 0;
521
+				$update_prices = true;
522
+			}
523
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
524
+			// we actually do our saves ahead of doing any add_relations to
525
+			// because its entirely possible that this ticket wasn't removed or added to any datetime in the session
526
+			// but DID have it's items modified.
527
+			// keep in mind that if the TKT has been sold (and we have changed pricing information),
528
+			// then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
529
+			if (absint($TKT_values['TKT_ID'])) {
530
+				$ticket = EE_Registry::instance()
531
+									 ->load_model('Ticket', array($timezone))
532
+									 ->get_one_by_ID($tkt['TKT_ID']);
533
+				if ($ticket instanceof EE_Ticket) {
534
+					$ticket = $this->_update_ticket_datetimes(
535
+						$ticket,
536
+						$saved_datetimes,
537
+						$datetimes_added,
538
+						$datetimes_removed
539
+					);
540
+					// are there any registrations using this ticket ?
541
+					$tickets_sold = $ticket->count_related(
542
+						'Registration',
543
+						array(
544
+							array(
545
+								'STS_ID' => array('NOT IN', array(EEM_Registration::status_id_incomplete)),
546
+							),
547
+						)
548
+					);
549
+					//set ticket formats
550
+					$ticket->set_date_format($this->_date_format_strings['date']);
551
+					$ticket->set_time_format($this->_date_format_strings['time']);
552
+					// let's just check the total price for the existing ticket
553
+					// and determine if it matches the new total price.
554
+					// if they are different then we create a new ticket (if tickets sold)
555
+					// if they aren't different then we go ahead and modify existing ticket.
556
+					$create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
557
+					//set new values
558
+					foreach ($TKT_values as $field => $value) {
559
+						if ($field === 'TKT_qty') {
560
+							$ticket->set_qty($value);
561
+						} else {
562
+							$ticket->set($field, $value);
563
+						}
564
+					}
565
+					// if $create_new_TKT is false then we can safely update the existing ticket.
566
+					// Otherwise we have to create a new ticket.
567
+					if ($create_new_TKT) {
568
+						$new_tkt = $this->_duplicate_ticket($ticket, $price_rows, $ticket_price, $base_price,
569
+							$base_price_id);
570
+					}
571
+				}
572
+			} else {
573
+				// no TKT_id so a new TKT
574
+				$ticket = EE_Ticket::new_instance(
575
+					$TKT_values,
576
+					$timezone,
577
+					array($this->_date_format_strings['date'], $this->_date_format_strings['time'])
578
+				);
579
+				if ($ticket instanceof EE_Ticket) {
580
+					// make sure ticket has an ID of setting relations won't work
581
+					$ticket->save();
582
+					$ticket = $this->_update_ticket_datetimes(
583
+						$ticket,
584
+						$saved_datetimes,
585
+						$datetimes_added,
586
+						$datetimes_removed
587
+					);
588
+					$update_prices = true;
589
+				}
590
+			}
591
+			//make sure any current values have been saved.
592
+			//$ticket->save();
593
+			// before going any further make sure our dates are setup correctly
594
+			// so that the end date is always equal or greater than the start date.
595
+			if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
596
+				$ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
597
+				$ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
598
+			}
599
+			//let's make sure the base price is handled
600
+			$ticket = ! $create_new_TKT ? $this->_add_prices_to_ticket(array(), $ticket, $update_prices, $base_price,
601
+				$base_price_id) : $ticket;
602
+			//add/update price_modifiers
603
+			$ticket = ! $create_new_TKT ? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices) : $ticket;
604
+			//need to make sue that the TKT_price is accurate after saving the prices.
605
+			$ticket->ensure_TKT_Price_correct();
606
+			//handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
607
+			if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
608
+				$update_prices = true;
609
+				$new_default = clone $ticket;
610
+				$new_default->set('TKT_ID', 0);
611
+				$new_default->set('TKT_is_default', 1);
612
+				$new_default->set('TKT_row', 1);
613
+				$new_default->set('TKT_price', $ticket_price);
614
+				// remove any dtt relations cause we DON'T want dtt relations attached
615
+				// (note this is just removing the cached relations in the object)
616
+				$new_default->_remove_relations('Datetime');
617
+				//todo we need to add the current attached prices as new prices to the new default ticket.
618
+				$new_default = $this->_add_prices_to_ticket($price_rows, $new_default, $update_prices);
619
+				//don't forget the base price!
620
+				$new_default = $this->_add_prices_to_ticket(
621
+					array(),
622
+					$new_default,
623
+					$update_prices,
624
+					$base_price,
625
+					$base_price_id
626
+				);
627
+				$new_default->save();
628
+				do_action(
629
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
630
+					$new_default,
631
+					$row,
632
+					$ticket,
633
+					$data
634
+				);
635
+			}
636
+			// DO ALL dtt relationships for both current tickets and any archived tickets
637
+			// for the given dtt that are related to the current ticket.
638
+			// TODO... not sure exactly how we're going to do this considering we don't know
639
+			// what current ticket the archived tickets are related to
640
+			// (and TKT_parent is used for autosaves so that's not a field we can reliably use).
641
+			//let's assign any tickets that have been setup to the saved_tickets tracker
642
+			//save existing TKT
643
+			$ticket->save();
644
+			if ($create_new_TKT && $new_tkt instanceof EE_Ticket) {
645
+				//save new TKT
646
+				$new_tkt->save();
647
+				//add new ticket to array
648
+				$saved_tickets[$new_tkt->ID()] = $new_tkt;
649
+				do_action(
650
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
651
+					$new_tkt,
652
+					$row,
653
+					$tkt,
654
+					$data
655
+				);
656
+			} else {
657
+				//add tkt to saved tkts
658
+				$saved_tickets[$ticket->ID()] = $ticket;
659
+				do_action(
660
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
661
+					$ticket,
662
+					$row,
663
+					$tkt,
664
+					$data
665
+				);
666
+			}
667
+		}
668
+		// now we need to handle tickets actually "deleted permanently".
669
+		// There are cases where we'd want this to happen
670
+		// (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
671
+		// Or a draft event was saved and in the process of editing a ticket is trashed.
672
+		// No sense in keeping all the related data in the db!
673
+		$old_tickets = isset($old_tickets[0]) && $old_tickets[0] === '' ? array() : $old_tickets;
674
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
675
+		foreach ($tickets_removed as $id) {
676
+			$id = absint($id);
677
+			//get the ticket for this id
678
+			$tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
679
+			//if this tkt is a default tkt we leave it alone cause it won't be attached to the datetime
680
+			if ($tkt_to_remove->get('TKT_is_default')) {
681
+				continue;
682
+			}
683
+			// if this tkt has any registrations attached so then we just ARCHIVE
684
+			// because we don't actually permanently delete these tickets.
685
+			if ($tkt_to_remove->count_related('Registration') > 0) {
686
+				$tkt_to_remove->delete();
687
+				continue;
688
+			}
689
+			// need to get all the related datetimes on this ticket and remove from every single one of them
690
+			// (remember this process can ONLY kick off if there are NO tkts_sold)
691
+			$datetimes = $tkt_to_remove->get_many_related('Datetime');
692
+			foreach ($datetimes as $datetime) {
693
+				$tkt_to_remove->_remove_relation_to($datetime, 'Datetime');
694
+			}
695
+			// need to do the same for prices (except these prices can also be deleted because again,
696
+			// tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
697
+			$tkt_to_remove->delete_related_permanently('Price');
698
+			do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $tkt_to_remove);
699
+			// finally let's delete this ticket
700
+			// (which should not be blocked at this point b/c we've removed all our relationships)
701
+			$tkt_to_remove->delete_permanently();
702
+		}
703
+		return $saved_tickets;
704
+	}
705
+
706
+
707
+
708
+	/**
709
+	 * @access  protected
710
+	 * @param \EE_Ticket     $ticket
711
+	 * @param \EE_Datetime[] $saved_datetimes
712
+	 * @param \EE_Datetime[] $added_datetimes
713
+	 * @param \EE_Datetime[] $removed_datetimes
714
+	 * @return \EE_Ticket
715
+	 * @throws \EE_Error
716
+	 */
717
+	protected function _update_ticket_datetimes(
718
+		EE_Ticket $ticket,
719
+		$saved_datetimes = array(),
720
+		$added_datetimes = array(),
721
+		$removed_datetimes = array()
722
+	) {
723
+		// to start we have to add the ticket to all the datetimes its supposed to be with,
724
+		// and removing the ticket from datetimes it got removed from.
725
+		// first let's add datetimes
726
+		if (! empty($added_datetimes) && is_array($added_datetimes)) {
727
+			foreach ($added_datetimes as $row_id) {
728
+				$row_id = (int)$row_id;
729
+				if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
730
+					$ticket->_add_relation_to($saved_datetimes[$row_id], 'Datetime');
731
+					// Is this an existing ticket (has an ID) and does it have any sold?
732
+					// If so, then we need to add that to the DTT sold because this DTT is getting added.
733
+					if ($ticket->ID() && $ticket->sold() > 0) {
734
+						$saved_datetimes[$row_id]->increase_sold($ticket->sold());
735
+						$saved_datetimes[$row_id]->save();
736
+					}
737
+				}
738
+			}
739
+		}
740
+		// then remove datetimes
741
+		if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
742
+			foreach ($removed_datetimes as $row_id) {
743
+				$row_id = (int)$row_id;
744
+				// its entirely possible that a datetime got deleted (instead of just removed from relationship.
745
+				// So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
746
+				if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
747
+					$ticket->_remove_relation_to($saved_datetimes[$row_id], 'Datetime');
748
+					// Is this an existing ticket (has an ID) and does it have any sold?
749
+					// If so, then we need to remove it's sold from the DTT_sold.
750
+					if ($ticket->ID() && $ticket->sold() > 0) {
751
+						$saved_datetimes[$row_id]->decrease_sold($ticket->sold());
752
+						$saved_datetimes[$row_id]->save();
753
+					}
754
+				}
755
+			}
756
+		}
757
+		// cap ticket qty by datetime reg limits
758
+		$ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
759
+		return $ticket;
760
+	}
761
+
762
+
763
+
764
+	/**
765
+	 * @access  protected
766
+	 * @param \EE_Ticket $ticket
767
+	 * @param array      $price_rows
768
+	 * @param int        $ticket_price
769
+	 * @param int        $base_price
770
+	 * @param int        $base_price_id
771
+	 * @return \EE_Ticket
772
+	 * @throws \EE_Error
773
+	 */
774
+	protected function _duplicate_ticket(
775
+		EE_Ticket $ticket,
776
+		$price_rows = array(),
777
+		$ticket_price = 0,
778
+		$base_price = 0,
779
+		$base_price_id = 0
780
+	) {
781
+		// create new ticket that's a copy of the existing
782
+		// except a new id of course (and not archived)
783
+		// AND has the new TKT_price associated with it.
784
+		$new_ticket = clone $ticket;
785
+		$new_ticket->set('TKT_ID', 0);
786
+		$new_ticket->set_deleted(0);
787
+		$new_ticket->set_price($ticket_price);
788
+		$new_ticket->set_sold(0);
789
+		// let's get a new ID for this ticket
790
+		$new_ticket->save();
791
+		// we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
792
+		$datetimes_on_existing = $ticket->datetimes();
793
+		$new_ticket = $this->_update_ticket_datetimes(
794
+			$new_ticket,
795
+			$datetimes_on_existing,
796
+			array_keys($datetimes_on_existing)
797
+		);
798
+		// $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
799
+		// if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
800
+		// available.
801
+		if ($ticket->sold() > 0) {
802
+			$new_qty = $ticket->qty() - $ticket->sold();
803
+			$new_ticket->set_qty($new_qty);
804
+		}
805
+		//now we update the prices just for this ticket
806
+		$new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
807
+		//and we update the base price
808
+		$new_ticket = $this->_add_prices_to_ticket(array(), $new_ticket, true, $base_price, $base_price_id);
809
+		return $new_ticket;
810
+	}
811
+
812
+
813
+
814
+	/**
815
+	 * This attaches a list of given prices to a ticket.
816
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
817
+	 * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
818
+	 * price info and prices are automatically "archived" via the ticket.
819
+	 *
820
+	 * @access  private
821
+	 * @param array     $prices        Array of prices from the form.
822
+	 * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
823
+	 * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
824
+	 * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
825
+	 * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
826
+	 * @return EE_Ticket
827
+	 * @throws EE_Error
828
+	 */
829
+	protected function _add_prices_to_ticket(
830
+		$prices = array(),
831
+		EE_Ticket $ticket,
832
+		$new_prices = false,
833
+		$base_price = false,
834
+		$base_price_id = false
835
+	) {
836
+		// let's just get any current prices that may exist on the given ticket
837
+		// so we can remove any prices that got trashed in this session.
838
+		$current_prices_on_ticket = $base_price !== false
839
+			? $ticket->base_price(true)
840
+			: $ticket->price_modifiers();
841
+		$updated_prices = array();
842
+		// if $base_price ! FALSE then updating a base price.
843
+		if ($base_price !== false) {
844
+			$prices[1] = array(
845
+				'PRC_ID'     => $new_prices || $base_price_id === 1 ? null : $base_price_id,
846
+				'PRT_ID'     => 1,
847
+				'PRC_amount' => $base_price,
848
+				'PRC_name'   => $ticket->get('TKT_name'),
849
+				'PRC_desc'   => $ticket->get('TKT_description'),
850
+			);
851
+		}
852
+		//possibly need to save tkt
853
+		if (! $ticket->ID()) {
854
+			$ticket->save();
855
+		}
856
+		foreach ($prices as $row => $prc) {
857
+			$prt_id = ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null;
858
+			if (empty($prt_id)) {
859
+				continue;
860
+			} //prices MUST have a price type id.
861
+			$PRC_values = array(
862
+				'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
863
+				'PRT_ID'         => $prt_id,
864
+				'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
865
+				'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
866
+				'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
867
+				'PRC_is_default' => false,
868
+				//make sure we set PRC_is_default to false for all ticket saves from event_editor
869
+				'PRC_order'      => $row,
870
+			);
871
+			if ($new_prices || empty($PRC_values['PRC_ID'])) {
872
+				$PRC_values['PRC_ID'] = 0;
873
+				$price = EE_Registry::instance()->load_class(
874
+					'Price',
875
+					array($PRC_values),
876
+					false,
877
+					false
878
+				);
879
+			} else {
880
+				$price = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
881
+				//update this price with new values
882
+				foreach ($PRC_values as $field => $value) {
883
+					$price->set($field, $value);
884
+				}
885
+			}
886
+			$price->save();
887
+			$updated_prices[$price->ID()] = $price;
888
+			$ticket->_add_relation_to($price, 'Price');
889
+		}
890
+		//now let's remove any prices that got removed from the ticket
891
+		if (! empty ($current_prices_on_ticket)) {
892
+			$current = array_keys($current_prices_on_ticket);
893
+			$updated = array_keys($updated_prices);
894
+			$prices_to_remove = array_diff($current, $updated);
895
+			if (! empty($prices_to_remove)) {
896
+				foreach ($prices_to_remove as $prc_id) {
897
+					$p = $current_prices_on_ticket[$prc_id];
898
+					$ticket->_remove_relation_to($p, 'Price');
899
+					//delete permanently the price
900
+					$p->delete_permanently();
901
+				}
902
+			}
903
+		}
904
+		return $ticket;
905
+	}
906
+
907
+
908
+
909
+	/**
910
+	 * @param Events_Admin_Page $event_admin_obj
911
+	 * @return Events_Admin_Page
912
+	 */
913
+	public function autosave_handling( Events_Admin_Page $event_admin_obj)
914
+	{
915
+		return $event_admin_obj;
916
+		//doing nothing for the moment.
917
+		// todo when I get to this remember that I need to set the template args on the $event_admin_obj
918
+		// (use the set_template_args() method)
919
+		/**
920
+		 * need to remember to handle TICKET DEFAULT saves correctly:  I've got two input fields in the dom:
921
+		 * 1. TKT_is_default_selector (visible)
922
+		 * 2. TKT_is_default (hidden)
923
+		 * I think we'll use the TKT_is_default for recording whether the ticket displayed IS a default ticket
924
+		 * (on new event creations). Whereas the TKT_is_default_selector is for the user to indicate they want
925
+		 * this ticket to be saved as a default.
926
+		 * The tricky part is, on an initial display on create or edit (or after manually updating),
927
+		 * the TKT_is_default_selector will always be unselected and the TKT_is_default will only be true
928
+		 * if this is a create.  However, after an autosave, users will want some sort of indicator that
929
+		 * the TKT HAS been saved as a default..
930
+		 * in other words we don't want to remove the check on TKT_is_default_selector. So here's what I'm thinking.
931
+		 * On Autosave:
932
+		 * 1. If TKT_is_default is true: we create a new TKT, send back the new id and add id to related elements,
933
+		 * then set the TKT_is_default to false.
934
+		 * 2. If TKT_is_default_selector is true: we create/edit existing ticket (following conditions above as well).
935
+		 *  We do NOT create a new default ticket.  The checkbox stays selected after autosave.
936
+		 * 3. only on MANUAL update do we check for the selection and if selected create the new default ticket.
937
+		 */
938
+	}
939
+
940
+
941
+
942
+	/**
943
+	 * @throws DomainException
944
+	 * @throws EE_Error
945
+	 */
946
+	public function pricing_metabox()
947
+	{
948
+		$existing_datetime_ids = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = array();
949
+		$event = $this->_adminpage_obj->get_cpt_model_obj();
950
+		//set is_creating_event property.
951
+		$EVT_ID = $event->ID();
952
+		$this->_is_creating_event = absint($EVT_ID) === 0;
953
+		//default main template args
954
+		$main_template_args = array(
955
+			'event_datetime_help_link' => EEH_Template::get_help_tab_link(
956
+				'event_editor_event_datetimes_help_tab',
957
+				$this->_adminpage_obj->page_slug,
958
+				$this->_adminpage_obj->get_req_action(),
959
+				false,
960
+				false
961
+			),
962
+			// todo need to add a filter to the template for the help text
963
+			// in the Events_Admin_Page core file so we can add further help
964
+			'existing_datetime_ids'    => '',
965
+			'total_dtt_rows'           => 1,
966
+			'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
967
+				'add_new_dtt_info',
968
+				$this->_adminpage_obj->page_slug,
969
+				$this->_adminpage_obj->get_req_action(),
970
+				false,
971
+				false
972
+			),
973
+			//todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
974
+			'datetime_rows'            => '',
975
+			'show_tickets_container'   => '',
976
+			//$this->_adminpage_obj->get_cpt_model_obj()->ID() > 1 ? ' style="display:none;"' : '',
977
+			'ticket_rows'              => '',
978
+			'existing_ticket_ids'      => '',
979
+			'total_ticket_rows'        => 1,
980
+			'ticket_js_structure'      => '',
981
+			'ee_collapsible_status'    => ' ee-collapsible-open'
982
+			//$this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
983
+		);
984
+		$timezone = $event instanceof EE_Event ? $event->timezone_string() : null;
985
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
986
+		/**
987
+		 * 1. Start with retrieving Datetimes
988
+		 * 2. For each datetime get related tickets
989
+		 * 3. For each ticket get related prices
990
+		 */
991
+		/** @var EEM_Datetime $datetime_model */
992
+		$datetime_model = EE_Registry::instance()->load_model('Datetime', array($timezone));
993
+		$datetimes = $datetime_model->get_all_event_dates($EVT_ID);
994
+		$main_template_args['total_dtt_rows'] = count($datetimes);
995
+		/**
996
+		 * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
997
+		 * for why we are counting $datetime_row and then setting that on the Datetime object
998
+		 */
999
+		$datetime_row = 1;
1000
+		foreach ($datetimes as $datetime) {
1001
+			$DTT_ID = $datetime->get('DTT_ID');
1002
+			$datetime->set('DTT_order', $datetime_row);
1003
+			$existing_datetime_ids[] = $DTT_ID;
1004
+			//tickets attached
1005
+			$related_tickets = $datetime->ID() > 0
1006
+				? $datetime->get_many_related(
1007
+					'Ticket',
1008
+					array(
1009
+						array(
1010
+							'OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0),
1011
+						),
1012
+						'default_where_conditions' => 'none',
1013
+						'order_by'                 => array('TKT_order' => 'ASC'),
1014
+					)
1015
+				)
1016
+				: array();
1017
+			//if there are no related tickets this is likely a new event OR autodraft
1018
+			// event so we need to generate the default tickets because datetimes
1019
+			// ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1020
+			// datetime on the event.
1021
+			if (empty ($related_tickets) && count($datetimes) < 2) {
1022
+				/** @var EEM_Ticket $ticket_model */
1023
+				$ticket_model = EE_Registry::instance()->load_model('Ticket');
1024
+				$related_tickets = $ticket_model->get_all_default_tickets();
1025
+				// this should be ordered by TKT_ID, so let's grab the first default ticket
1026
+				// (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1027
+				$default_prices = EEM_Price::instance()->get_all_default_prices();
1028
+				$main_default_ticket = reset($related_tickets);
1029
+				if ($main_default_ticket instanceof EE_Ticket) {
1030
+					foreach ($default_prices as $default_price) {
1031
+						if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1032
+							continue;
1033
+						}
1034
+						$main_default_ticket->cache('Price', $default_price);
1035
+					}
1036
+				}
1037
+			}
1038
+			// we can't actually setup rows in this loop yet cause we don't know all
1039
+			// the unique tickets for this event yet (tickets are linked through all datetimes).
1040
+			// So we're going to temporarily cache some of that information.
1041
+			//loop through and setup the ticket rows and make sure the order is set.
1042
+			foreach ($related_tickets as $ticket) {
1043
+				$TKT_ID = $ticket->get('TKT_ID');
1044
+				$ticket_row = $ticket->get('TKT_row');
1045
+				//we only want unique tickets in our final display!!
1046
+				if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1047
+					$existing_ticket_ids[] = $TKT_ID;
1048
+					$all_tickets[] = $ticket;
1049
+				}
1050
+				//temporary cache of this ticket info for this datetime for later processing of datetime rows.
1051
+				$datetime_tickets[$DTT_ID][] = $ticket_row;
1052
+				//temporary cache of this datetime info for this ticket for later processing of ticket rows.
1053
+				if (
1054
+					! isset($ticket_datetimes[$TKT_ID])
1055
+					|| ! in_array($datetime_row, $ticket_datetimes[$TKT_ID], true)
1056
+				) {
1057
+					$ticket_datetimes[$TKT_ID][] = $datetime_row;
1058
+				}
1059
+			}
1060
+			$datetime_row++;
1061
+		}
1062
+		$main_template_args['total_ticket_rows'] = count($existing_ticket_ids);
1063
+		$main_template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1064
+		$main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1065
+		//sort $all_tickets by order
1066
+		usort(
1067
+			$all_tickets,
1068
+			function (EE_Ticket $a, EE_Ticket $b) {
1069
+				$a_order = (int)$a->get('TKT_order');
1070
+				$b_order = (int)$b->get('TKT_order');
1071
+				if ($a_order === $b_order) {
1072
+					return 0;
1073
+				}
1074
+				return ($a_order < $b_order) ? -1 : 1;
1075
+			}
1076
+		);
1077
+		// k NOW we have all the data we need for setting up the dtt rows
1078
+		// and ticket rows so we start our dtt loop again.
1079
+		$datetime_row = 1;
1080
+		foreach ($datetimes as $datetime) {
1081
+			$main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1082
+				$datetime_row,
1083
+				$datetime,
1084
+				$datetime_tickets,
1085
+				$all_tickets,
1086
+				false,
1087
+				$datetimes
1088
+			);
1089
+			$datetime_row++;
1090
+		}
1091
+		//then loop through all tickets for the ticket rows.
1092
+		$ticket_row = 1;
1093
+		foreach ($all_tickets as $ticket) {
1094
+			$main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1095
+				$ticket_row,
1096
+				$ticket,
1097
+				$ticket_datetimes,
1098
+				$datetimes,
1099
+				false,
1100
+				$all_tickets
1101
+			);
1102
+			$ticket_row++;
1103
+		}
1104
+		$main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1105
+		EEH_Template::display_template(
1106
+			PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1107
+			$main_template_args
1108
+		);
1109
+	}
1110
+
1111
+
1112
+
1113
+	/**
1114
+	 * @param int         $datetime_row
1115
+	 * @param EE_Datetime $datetime
1116
+	 * @param array       $datetime_tickets
1117
+	 * @param array       $all_tickets
1118
+	 * @param bool        $default
1119
+	 * @param array       $all_datetimes
1120
+	 * @return mixed
1121
+	 * @throws DomainException
1122
+	 * @throws EE_Error
1123
+	 */
1124
+	protected function _get_datetime_row(
1125
+		$datetime_row,
1126
+		EE_Datetime $datetime,
1127
+		$datetime_tickets = array(),
1128
+		$all_tickets = array(),
1129
+		$default = false,
1130
+		$all_datetimes = array()
1131
+	) {
1132
+		$dtt_display_template_args = array(
1133
+			'dtt_edit_row'             => $this->_get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes),
1134
+			'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1135
+				$datetime_row,
1136
+				$datetime,
1137
+				$datetime_tickets,
1138
+				$all_tickets,
1139
+				$default
1140
+			),
1141
+			'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1142
+		);
1143
+		return EEH_Template::display_template(
1144
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1145
+			$dtt_display_template_args,
1146
+			true
1147
+		);
1148
+	}
1149
+
1150
+
1151
+
1152
+	/**
1153
+	 * This method is used to generate a dtt fields  edit row.
1154
+	 * The same row is used to generate a row with valid DTT objects
1155
+	 * and the default row that is used as the skeleton by the js.
1156
+	 *
1157
+	 * @param int           $datetime_row  The row number for the row being generated.
1158
+	 * @param EE_Datetime   $datetime
1159
+	 * @param bool          $default       Whether a default row is being generated or not.
1160
+	 * @param EE_Datetime[] $all_datetimes This is the array of all datetimes used in the editor.
1161
+	 * @return string
1162
+	 * @throws DomainException
1163
+	 * @throws EE_Error
1164
+	 */
1165
+	protected function _get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes)
1166
+	{
1167
+		// if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1168
+		$default = ! $datetime instanceof EE_Datetime ? true : $default;
1169
+		$template_args = array(
1170
+			'dtt_row'              => $default ? 'DTTNUM' : $datetime_row,
1171
+			'event_datetimes_name' => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1172
+			'edit_dtt_expanded'    => '',
1173
+			'DTT_ID'               => $default ? '' : $datetime->ID(),
1174
+			'DTT_name'             => $default ? '' : $datetime->name(),
1175
+			'DTT_description'      => $default ? '' : $datetime->description(),
1176
+			'DTT_EVT_start'        => $default ? '' : $datetime->start_date($this->_date_time_format),
1177
+			'DTT_EVT_end'          => $default ? '' : $datetime->end_date($this->_date_time_format),
1178
+			'DTT_reg_limit'        => $default
1179
+				? ''
1180
+				: $datetime->get_pretty(
1181
+					'DTT_reg_limit',
1182
+					'input'
1183
+				),
1184
+			'DTT_order'            => $default ? 'DTTNUM' : $datetime_row,
1185
+			'dtt_sold'             => $default ? '0' : $datetime->get('DTT_sold'),
1186
+			'dtt_reserved'         => $default ? '0' : $datetime->reserved(),
1187
+			'clone_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1188
+				? ''
1189
+				: 'clone-icon ee-icon ee-icon-clone clickable',
1190
+			'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1191
+				? 'ee-lock-icon'
1192
+				: 'trash-icon dashicons dashicons-post-trash clickable',
1193
+			'reg_list_url'         => $default || ! $datetime->event() instanceof \EE_Event
1194
+				? ''
1195
+				: EE_Admin_Page::add_query_args_and_nonce(
1196
+					array('event_id' => $datetime->event()->ID(), 'datetime_id' => $datetime->ID()),
1197
+					REG_ADMIN_URL
1198
+				),
1199
+		);
1200
+		$template_args['show_trash'] = count($all_datetimes) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1201
+			? ' style="display:none"'
1202
+			: '';
1203
+		//allow filtering of template args at this point.
1204
+		$template_args = apply_filters(
1205
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1206
+			$template_args,
1207
+			$datetime_row,
1208
+			$datetime,
1209
+			$default,
1210
+			$all_datetimes,
1211
+			$this->_is_creating_event
1212
+		);
1213
+		return EEH_Template::display_template(
1214
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1215
+			$template_args,
1216
+			true
1217
+		);
1218
+	}
1219
+
1220
+
1221
+
1222
+	/**
1223
+	 * @param int         $datetime_row
1224
+	 * @param EE_Datetime $datetime
1225
+	 * @param array       $datetime_tickets
1226
+	 * @param array       $all_tickets
1227
+	 * @param bool        $default
1228
+	 * @return mixed
1229
+	 * @throws DomainException
1230
+	 * @throws EE_Error
1231
+	 */
1232
+	protected function _get_dtt_attached_tickets_row(
1233
+		$datetime_row,
1234
+		$datetime,
1235
+		$datetime_tickets = array(),
1236
+		$all_tickets = array(),
1237
+		$default
1238
+	) {
1239
+		$template_args = array(
1240
+			'dtt_row'                           => $default ? 'DTTNUM' : $datetime_row,
1241
+			'event_datetimes_name'              => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1242
+			'DTT_description'                   => $default ? '' : $datetime->description(),
1243
+			'datetime_tickets_list'             => $default ? '<li class="hidden"></li>' : '',
1244
+			'show_tickets_row'                  => ' style="display:none;"',
1245
+			'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1246
+				'add_new_ticket_via_datetime',
1247
+				$this->_adminpage_obj->page_slug,
1248
+				$this->_adminpage_obj->get_req_action(),
1249
+				false,
1250
+				false
1251
+			),
1252
+			//todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1253
+			'DTT_ID'                            => $default ? '' : $datetime->ID(),
1254
+		);
1255
+		//need to setup the list items (but only if this isn't a default skeleton setup)
1256
+		if (! $default) {
1257
+			$ticket_row = 1;
1258
+			foreach ($all_tickets as $ticket) {
1259
+				$template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1260
+					$datetime_row,
1261
+					$ticket_row,
1262
+					$datetime,
1263
+					$ticket,
1264
+					$datetime_tickets,
1265
+					$default
1266
+				);
1267
+				$ticket_row++;
1268
+			}
1269
+		}
1270
+		//filter template args at this point
1271
+		$template_args = apply_filters(
1272
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1273
+			$template_args,
1274
+			$datetime_row,
1275
+			$datetime,
1276
+			$datetime_tickets,
1277
+			$all_tickets,
1278
+			$default,
1279
+			$this->_is_creating_event
1280
+		);
1281
+		return EEH_Template::display_template(
1282
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1283
+			$template_args,
1284
+			true
1285
+		);
1286
+	}
1287
+
1288
+
1289
+
1290
+	/**
1291
+	 * @param int         $datetime_row
1292
+	 * @param int         $ticket_row
1293
+	 * @param EE_Datetime $datetime
1294
+	 * @param EE_Ticket   $ticket
1295
+	 * @param array       $datetime_tickets
1296
+	 * @param bool        $default
1297
+	 * @return mixed
1298
+	 * @throws DomainException
1299
+	 * @throws EE_Error
1300
+	 */
1301
+	protected function _get_datetime_tickets_list_item(
1302
+		$datetime_row,
1303
+		$ticket_row,
1304
+		$datetime,
1305
+		$ticket,
1306
+		$datetime_tickets = array(),
1307
+		$default
1308
+	) {
1309
+		$dtt_tkts = $datetime instanceof EE_Datetime && isset($datetime_tickets[$datetime->ID()])
1310
+			? $datetime_tickets[$datetime->ID()]
1311
+			: array();
1312
+		$display_row = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1313
+		$no_ticket = $default && empty($ticket);
1314
+		$template_args = array(
1315
+			'dtt_row'                 => $default
1316
+				? 'DTTNUM'
1317
+				: $datetime_row,
1318
+			'tkt_row'                 => $no_ticket
1319
+				? 'TICKETNUM'
1320
+				: $ticket_row,
1321
+			'datetime_ticket_checked' => in_array($display_row, $dtt_tkts, true)
1322
+				? ' checked="checked"'
1323
+				: '',
1324
+			'ticket_selected'         => in_array($display_row, $dtt_tkts, true)
1325
+				? ' ticket-selected'
1326
+				: '',
1327
+			'TKT_name'                => $no_ticket
1328
+				? 'TKTNAME'
1329
+				: $ticket->get('TKT_name'),
1330
+			'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1331
+				? ' tkt-status-' . EE_Ticket::onsale
1332
+				: ' tkt-status-' . $ticket->ticket_status(),
1333
+		);
1334
+		//filter template args
1335
+		$template_args = apply_filters(
1336
+			'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1337
+			$template_args,
1338
+			$datetime_row,
1339
+			$ticket_row,
1340
+			$datetime,
1341
+			$ticket,
1342
+			$datetime_tickets,
1343
+			$default,
1344
+			$this->_is_creating_event
1345
+		);
1346
+		return EEH_Template::display_template(
1347
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1348
+			$template_args,
1349
+			true
1350
+		);
1351
+	}
1352
+
1353
+
1354
+
1355
+	/**
1356
+	 * This generates the ticket row for tickets.
1357
+	 * This same method is used to generate both the actual rows and the js skeleton row
1358
+	 * (when default === true)
1359
+	 *
1360
+	 * @param int           $ticket_row       Represents the row number being generated.
1361
+	 * @param               $ticket
1362
+	 * @param EE_Datetime[] $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1363
+	 *                                        or empty for default
1364
+	 * @param EE_Datetime[] $all_datetimes    All Datetimes on the event or empty for default.
1365
+	 * @param bool          $default          Whether default row being generated or not.
1366
+	 * @param EE_Ticket[]   $all_tickets      This is an array of all tickets attached to the event
1367
+	 *                                        (or empty in the case of defaults)
1368
+	 * @return mixed
1369
+	 * @throws DomainException
1370
+	 * @throws EE_Error
1371
+	 */
1372
+	protected function _get_ticket_row(
1373
+		$ticket_row,
1374
+		$ticket,
1375
+		$ticket_datetimes,
1376
+		$all_datetimes,
1377
+		$default = false,
1378
+		$all_tickets = array()
1379
+	) {
1380
+		// if $ticket is not an instance of EE_Ticket then force default to true.
1381
+		$default = ! $ticket instanceof EE_Ticket ? true : $default;
1382
+		$prices = ! empty($ticket) && ! $default ? $ticket->get_many_related('Price',
1383
+			array('default_where_conditions' => 'none', 'order_by' => array('PRC_order' => 'ASC'))) : array();
1384
+		// if there is only one price (which would be the base price)
1385
+		// or NO prices and this ticket is a default ticket,
1386
+		// let's just make sure there are no cached default prices on the object.
1387
+		// This is done by not including any query_params.
1388
+		if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1389
+			$prices = $ticket->prices();
1390
+		}
1391
+		// check if we're dealing with a default ticket in which case
1392
+		// we don't want any starting_ticket_datetime_row values set
1393
+		// (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1394
+		// This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1395
+		$default_dtt = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1396
+		$tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
1397
+			? $ticket_datetimes[$ticket->ID()]
1398
+			: array();
1399
+		$ticket_subtotal = $default ? 0 : $ticket->get_ticket_subtotal();
1400
+		$base_price = $default ? null : $ticket->base_price();
1401
+		$count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1402
+		//breaking out complicated condition for ticket_status
1403
+		if ($default) {
1404
+			$ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1405
+		} else {
1406
+			$ticket_status_class = $ticket->is_default()
1407
+				? ' tkt-status-' . EE_Ticket::onsale
1408
+				: ' tkt-status-' . $ticket->ticket_status();
1409
+		}
1410
+		//breaking out complicated condition for TKT_taxable
1411
+		if ($default) {
1412
+			$TKT_taxable = '';
1413
+		} else {
1414
+			$TKT_taxable = $ticket->taxable()
1415
+				? ' checked="checked"'
1416
+				: '';
1417
+		}
1418
+		if ($default) {
1419
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1420
+		} elseif ($ticket->is_default()) {
1421
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1422
+		} else {
1423
+			$TKT_status = $ticket->ticket_status(true);
1424
+		}
1425
+		if ($default) {
1426
+			$TKT_min = '';
1427
+		} else {
1428
+			$TKT_min = $ticket->min();
1429
+			if ($TKT_min === -1 || $TKT_min === 0) {
1430
+				$TKT_min = '';
1431
+			}
1432
+		}
1433
+		$template_args = array(
1434
+			'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1435
+			'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1436
+			//on initial page load this will always be the correct order.
1437
+			'tkt_status_class'              => $ticket_status_class,
1438
+			'display_edit_tkt_row'          => ' style="display:none;"',
1439
+			'edit_tkt_expanded'             => '',
1440
+			'edit_tickets_name'             => $default ? 'TICKETNAMEATTR' : 'edit_tickets',
1441
+			'TKT_name'                      => $default ? '' : $ticket->name(),
1442
+			'TKT_start_date'                => $default
1443
+				? ''
1444
+				: $ticket->get_date('TKT_start_date', $this->_date_time_format),
1445
+			'TKT_end_date'                  => $default
1446
+				? ''
1447
+				: $ticket->get_date('TKT_end_date', $this->_date_time_format),
1448
+			'TKT_status'                    => $TKT_status,
1449
+			'TKT_price'                     => $default
1450
+				? ''
1451
+				: EEH_Template::format_currency(
1452
+					$ticket->get_ticket_total_with_taxes(),
1453
+					false,
1454
+					false
1455
+				),
1456
+			'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1457
+			'TKT_price_amount'              => $default ? 0 : $ticket_subtotal,
1458
+			'TKT_qty'                       => $default
1459
+				? ''
1460
+				: $ticket->get_pretty('TKT_qty', 'symbol'),
1461
+			'TKT_qty_for_input'             => $default
1462
+				? ''
1463
+				: $ticket->get_pretty('TKT_qty', 'input'),
1464
+			'TKT_uses'                      => $default
1465
+				? ''
1466
+				: $ticket->get_pretty('TKT_uses', 'input'),
1467
+			'TKT_min'                       => $TKT_min,
1468
+			'TKT_max'                       => $default
1469
+				? ''
1470
+				: $ticket->get_pretty('TKT_max', 'input'),
1471
+			'TKT_sold'                      => $default ? 0 : $ticket->tickets_sold('ticket'),
1472
+			'TKT_reserved'                  => $default ? 0 : $ticket->reserved(),
1473
+			'TKT_registrations'             => $default
1474
+				? 0
1475
+				: $ticket->count_registrations(
1476
+					array(
1477
+						array(
1478
+							'STS_ID' => array(
1479
+								'!=',
1480
+								EEM_Registration::status_id_incomplete,
1481
+							),
1482
+						),
1483
+					)
1484
+				),
1485
+			'TKT_ID'                        => $default ? 0 : $ticket->ID(),
1486
+			'TKT_description'               => $default ? '' : $ticket->description(),
1487
+			'TKT_is_default'                => $default ? 0 : $ticket->is_default(),
1488
+			'TKT_required'                  => $default ? 0 : $ticket->required(),
1489
+			'TKT_is_default_selector'       => '',
1490
+			'ticket_price_rows'             => '',
1491
+			'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1492
+				? ''
1493
+				: $base_price->get_pretty('PRC_amount', 'localized_float'),
1494
+			'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price ? 0 : $base_price->ID(),
1495
+			'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1496
+				? ''
1497
+				: ' style="display:none;"',
1498
+			'show_price_mod_button'         => count($prices) > 1
1499
+											   || ($default && $count_price_mods > 0)
1500
+											   || (! $default && $ticket->deleted())
1501
+				? ' style="display:none;"'
1502
+				: '',
1503
+			'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
1504
+			'ticket_datetimes_list'         => $default ? '<li class="hidden"></li>' : '',
1505
+			'starting_ticket_datetime_rows' => $default || $default_dtt ? '' : implode(',', $tkt_datetimes),
1506
+			'ticket_datetime_rows'          => $default ? '' : implode(',', $tkt_datetimes),
1507
+			'existing_ticket_price_ids'     => $default ? '' : implode(',', array_keys($prices)),
1508
+			'ticket_template_id'            => $default ? 0 : $ticket->get('TTM_ID'),
1509
+			'TKT_taxable'                   => $TKT_taxable,
1510
+			'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1511
+				? ''
1512
+				: ' style="display:none"',
1513
+			'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1514
+			'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1515
+				$ticket_subtotal,
1516
+				false,
1517
+				false
1518
+			),
1519
+			'TKT_subtotal_amount'           => $ticket_subtotal,
1520
+			'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1521
+			'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1522
+			'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1523
+				? ' ticket-archived'
1524
+				: '',
1525
+			'trash_icon'                    => $ticket instanceof EE_Ticket
1526
+											   && $ticket->deleted()
1527
+											   && ! $ticket->is_permanently_deleteable()
1528
+				? 'ee-lock-icon '
1529
+				: 'trash-icon dashicons dashicons-post-trash clickable',
1530
+			'clone_icon'                    => $ticket instanceof EE_Ticket && $ticket->deleted()
1531
+				? ''
1532
+				: 'clone-icon ee-icon ee-icon-clone clickable',
1533
+		);
1534
+		$template_args['trash_hidden'] = count($all_tickets) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1535
+			? ' style="display:none"'
1536
+			: '';
1537
+		//handle rows that should NOT be empty
1538
+		if (empty($template_args['TKT_start_date'])) {
1539
+			//if empty then the start date will be now.
1540
+			$template_args['TKT_start_date'] = date($this->_date_time_format,
1541
+				current_time('timestamp'));
1542
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1543
+		}
1544
+		if (empty($template_args['TKT_end_date'])) {
1545
+			//get the earliest datetime (if present);
1546
+			$earliest_dtt = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1547
+				? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1548
+					'Datetime',
1549
+					array('order_by' => array('DTT_EVT_start' => 'ASC'))
1550
+				)
1551
+				: null;
1552
+			if (! empty($earliest_dtt)) {
1553
+				$template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1554
+					'DTT_EVT_start',
1555
+					$this->_date_time_format
1556
+				);
1557
+			} else {
1558
+				//default so let's just use what's been set for the default date-time which is 30 days from now.
1559
+				$template_args['TKT_end_date'] = date(
1560
+					$this->_date_time_format,
1561
+					mktime(24, 0, 0, date('m'), date('d') + 29, date('Y')
1562
+					)
1563
+				);
1564
+			}
1565
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1566
+		}
1567
+		//generate ticket_datetime items
1568
+		if (! $default) {
1569
+			$datetime_row = 1;
1570
+			foreach ($all_datetimes as $datetime) {
1571
+				$template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1572
+					$datetime_row,
1573
+					$ticket_row,
1574
+					$datetime,
1575
+					$ticket,
1576
+					$ticket_datetimes,
1577
+					$default
1578
+				);
1579
+				$datetime_row++;
1580
+			}
1581
+		}
1582
+		$price_row = 1;
1583
+		foreach ($prices as $price) {
1584
+			if (! $price instanceof EE_Price)  {
1585
+				continue;
1586
+			}
1587
+			if ($price->is_base_price()) {
1588
+				$price_row++;
1589
+				continue;
1590
+			}
1591
+			$show_trash = !((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1592
+			$show_create = !(count($prices) > 1 && count($prices) !== $price_row);
1593
+			$template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1594
+				$ticket_row,
1595
+				$price_row,
1596
+				$price,
1597
+				$default,
1598
+				$ticket,
1599
+				$show_trash,
1600
+				$show_create
1601
+			);
1602
+			$price_row++;
1603
+		}
1604
+		//filter $template_args
1605
+		$template_args = apply_filters(
1606
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1607
+			$template_args,
1608
+			$ticket_row,
1609
+			$ticket,
1610
+			$ticket_datetimes,
1611
+			$all_datetimes,
1612
+			$default,
1613
+			$all_tickets,
1614
+			$this->_is_creating_event
1615
+		);
1616
+		return EEH_Template::display_template(
1617
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1618
+			$template_args,
1619
+			true
1620
+		);
1621
+	}
1622
+
1623
+
1624
+
1625
+	/**
1626
+	 * @param int            $ticket_row
1627
+	 * @param EE_Ticket|null $ticket
1628
+	 * @return string
1629
+	 * @throws DomainException
1630
+	 * @throws EE_Error
1631
+	 */
1632
+	protected function _get_tax_rows($ticket_row, $ticket)
1633
+	{
1634
+		$tax_rows = '';
1635
+		/** @var EE_Price[] $taxes */
1636
+		$taxes = empty($ticket) ? EE_Taxes::get_taxes_for_admin() : $ticket->get_ticket_taxes_for_admin();
1637
+		foreach ($taxes as $tax) {
1638
+			$tax_added = $this->_get_tax_added($tax, $ticket);
1639
+			$template_args = array(
1640
+				'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1641
+					? ''
1642
+					: ' style="display:none;"',
1643
+				'tax_id'            => $tax->ID(),
1644
+				'tkt_row'           => $ticket_row,
1645
+				'tax_label'         => $tax->get('PRC_name'),
1646
+				'tax_added'         => $tax_added,
1647
+				'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1648
+				'tax_amount'        => $tax->get('PRC_amount'),
1649
+			);
1650
+			$template_args = apply_filters(
1651
+				'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1652
+				$template_args,
1653
+				$ticket_row,
1654
+				$ticket,
1655
+				$this->_is_creating_event
1656
+			);
1657
+			$tax_rows .= EEH_Template::display_template(
1658
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1659
+				$template_args,
1660
+				true
1661
+			);
1662
+		}
1663
+		return $tax_rows;
1664
+	}
1665
+
1666
+
1667
+
1668
+	/**
1669
+	 * @param EE_Price       $tax
1670
+	 * @param EE_Ticket|null $ticket
1671
+	 * @return float|int
1672
+	 * @throws EE_Error
1673
+	 */
1674
+	protected function _get_tax_added(EE_Price $tax, $ticket)
1675
+	{
1676
+		$subtotal = empty($ticket) ? 0 : $ticket->get_ticket_subtotal();
1677
+		return $subtotal * $tax->get('PRC_amount') / 100;
1678
+	}
1679
+
1680
+
1681
+
1682
+	/**
1683
+	 * @param int            $ticket_row
1684
+	 * @param int            $price_row
1685
+	 * @param EE_Price|null  $price
1686
+	 * @param bool           $default
1687
+	 * @param EE_Ticket|null $ticket
1688
+	 * @param bool           $show_trash
1689
+	 * @param bool           $show_create
1690
+	 * @return mixed
1691
+	 * @throws DomainException
1692
+	 * @throws EE_Error
1693
+	 */
1694
+	protected function _get_ticket_price_row(
1695
+		$ticket_row,
1696
+		$price_row,
1697
+		$price,
1698
+		$default,
1699
+		$ticket,
1700
+		$show_trash = true,
1701
+		$show_create = true
1702
+	) {
1703
+		$send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1704
+		$template_args = array(
1705
+			'tkt_row'               => $default && empty($ticket)
1706
+				? 'TICKETNUM'
1707
+				: $ticket_row,
1708
+			'PRC_order'             => $default && empty($price)
1709
+				? 'PRICENUM'
1710
+				: $price_row,
1711
+			'edit_prices_name'      => $default && empty($price)
1712
+				? 'PRICENAMEATTR'
1713
+				: 'edit_prices',
1714
+			'price_type_selector'   => $default && empty($price)
1715
+				? $this->_get_base_price_template($ticket_row, $price_row, $price, $default)
1716
+				: $this->_get_price_type_selector($ticket_row, $price_row, $price, $default, $send_disabled),
1717
+			'PRC_ID'                => $default && empty($price)
1718
+				? 0
1719
+				: $price->ID(),
1720
+			'PRC_is_default'        => $default && empty($price)
1721
+				? 0
1722
+				: $price->get('PRC_is_default'),
1723
+			'PRC_name'              => $default && empty($price)
1724
+				? ''
1725
+				: $price->get('PRC_name'),
1726
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1727
+			'show_plus_or_minus'    => $default && empty($price)
1728
+				? ''
1729
+				: ' style="display:none;"',
1730
+			'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1731
+				? ' style="display:none;"'
1732
+				: '',
1733
+			'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1734
+				? ' style="display:none;"'
1735
+				: '',
1736
+			'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1737
+				? ' style="display:none"'
1738
+				: '',
1739
+			'PRC_amount'            => $default && empty($price)
1740
+				? 0
1741
+				: $price->get_pretty('PRC_amount',
1742
+					'localized_float'),
1743
+			'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1744
+				? ' style="display:none;"'
1745
+				: '',
1746
+			'show_trash_icon'       => $show_trash
1747
+				? ''
1748
+				: ' style="display:none;"',
1749
+			'show_create_button'    => $show_create
1750
+				? ''
1751
+				: ' style="display:none;"',
1752
+			'PRC_desc'              => $default && empty($price)
1753
+				? ''
1754
+				: $price->get('PRC_desc'),
1755
+			'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1756
+		);
1757
+		$template_args = apply_filters(
1758
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1759
+			$template_args,
1760
+			$ticket_row,
1761
+			$price_row,
1762
+			$price,
1763
+			$default,
1764
+			$ticket,
1765
+			$show_trash,
1766
+			$show_create,
1767
+			$this->_is_creating_event
1768
+		);
1769
+		return EEH_Template::display_template(
1770
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1771
+			$template_args,
1772
+			true
1773
+		);
1774
+	}
1775
+
1776
+
1777
+
1778
+	/**
1779
+	 * @param int      $ticket_row
1780
+	 * @param int      $price_row
1781
+	 * @param EE_Price $price
1782
+	 * @param bool     $default
1783
+	 * @param bool     $disabled
1784
+	 * @return mixed
1785
+	 * @throws DomainException
1786
+	 * @throws EE_Error
1787
+	 */
1788
+	protected function _get_price_type_selector($ticket_row, $price_row, $price, $default, $disabled = false)
1789
+	{
1790
+		if ($price->is_base_price()) {
1791
+			return $this->_get_base_price_template($ticket_row, $price_row, $price, $default);
1792
+		}
1793
+		return $this->_get_price_modifier_template($ticket_row, $price_row, $price, $default, $disabled);
1794
+	}
1795
+
1796
+
1797
+
1798
+	/**
1799
+	 * @param int      $ticket_row
1800
+	 * @param int      $price_row
1801
+	 * @param EE_Price $price
1802
+	 * @param bool     $default
1803
+	 * @return mixed
1804
+	 * @throws DomainException
1805
+	 * @throws EE_Error
1806
+	 */
1807
+	protected function _get_base_price_template($ticket_row, $price_row, $price, $default)
1808
+	{
1809
+		$template_args = array(
1810
+			'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1811
+			'PRC_order'                 => $default && empty($price) ? 'PRICENUM' : $price_row,
1812
+			'PRT_ID'                    => $default && empty($price) ? 1 : $price->get('PRT_ID'),
1813
+			'PRT_name'                  => esc_html__('Price', 'event_espresso'),
1814
+			'price_selected_operator'   => '+',
1815
+			'price_selected_is_percent' => 0,
1816
+		);
1817
+		$template_args = apply_filters(
1818
+			'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
1819
+			$template_args,
1820
+			$ticket_row,
1821
+			$price_row,
1822
+			$price,
1823
+			$default,
1824
+			$this->_is_creating_event
1825
+		);
1826
+		return EEH_Template::display_template(
1827
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1828
+			$template_args,
1829
+			true
1830
+		);
1831
+	}
1832
+
1833
+
1834
+
1835
+	/**
1836
+	 * @param int      $ticket_row
1837
+	 * @param int      $price_row
1838
+	 * @param EE_Price $price
1839
+	 * @param bool     $default
1840
+	 * @param bool     $disabled
1841
+	 * @return mixed
1842
+	 * @throws DomainException
1843
+	 * @throws EE_Error
1844
+	 */
1845
+	protected function _get_price_modifier_template(
1846
+		$ticket_row,
1847
+		$price_row,
1848
+		$price,
1849
+		$default,
1850
+		$disabled = false
1851
+	) {
1852
+		$select_name = $default && ! $price instanceof EE_Price
1853
+			? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1854
+			: 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1855
+		/** @var EEM_Price_Type $price_type_model */
1856
+		$price_type_model = EE_Registry::instance()->load_model('Price_Type');
1857
+		$price_types = $price_type_model->get_all(array(
1858
+			array(
1859
+				'OR' => array(
1860
+					'PBT_ID'  => '2',
1861
+					'PBT_ID*' => '3',
1862
+				),
1863
+			),
1864
+		));
1865
+		$all_price_types = $default && ! $price instanceof EE_Price
1866
+			? array(esc_html__('Select Modifier', 'event_espresso'))
1867
+			: array();
1868
+		$selected_price_type_id = $default && ! $price instanceof EE_Price ? 0 : $price->type();
1869
+		$price_option_spans = '';
1870
+		//setup price types for selector
1871
+		foreach ($price_types as $price_type) {
1872
+			if (! $price_type instanceof EE_Price_Type) {
1873
+				continue;
1874
+			}
1875
+			$all_price_types[$price_type->ID()] = $price_type->get('PRT_name');
1876
+			//while we're in the loop let's setup the option spans used by js
1877
+			$span_args = array(
1878
+				'PRT_ID'         => $price_type->ID(),
1879
+				'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1880
+				'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1881
+			);
1882
+			$price_option_spans .= EEH_Template::display_template(
1883
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1884
+				$span_args,
1885
+				true
1886
+			);
1887
+		}
1888
+		$select_name = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]' : $select_name;
1889
+		$select_input = new EE_Select_Input(
1890
+			$all_price_types,
1891
+			array(
1892
+				'default'               => $selected_price_type_id,
1893
+				'html_name'             => $select_name,
1894
+				'html_class'            => 'edit-price-PRT_ID',
1895
+				'html_other_attributes' => $disabled ? 'style="width:auto;" disabled' : 'style="width:auto;"',
1896
+			)
1897
+		);
1898
+		$price_selected_operator = $price instanceof EE_Price && $price->is_discount() ? '-' : '+';
1899
+		$price_selected_operator = $default && ! $price instanceof EE_Price ? '' : $price_selected_operator;
1900
+		$price_selected_is_percent = $price instanceof EE_Price && $price->is_percent() ? 1 : 0;
1901
+		$price_selected_is_percent = $default && ! $price instanceof EE_Price ? '' : $price_selected_is_percent;
1902
+		$template_args = array(
1903
+			'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1904
+			'PRC_order'                 => $default && ! $price instanceof EE_Price ? 'PRICENUM' : $price_row,
1905
+			'price_modifier_selector'   => $select_input->get_html_for_input(),
1906
+			'main_name'                 => $select_name,
1907
+			'selected_price_type_id'    => $selected_price_type_id,
1908
+			'price_option_spans'        => $price_option_spans,
1909
+			'price_selected_operator'   => $price_selected_operator,
1910
+			'price_selected_is_percent' => $price_selected_is_percent,
1911
+			'disabled'                  => $disabled,
1912
+		);
1913
+		$template_args = apply_filters(
1914
+			'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1915
+			$template_args,
1916
+			$ticket_row,
1917
+			$price_row,
1918
+			$price,
1919
+			$default,
1920
+			$disabled,
1921
+			$this->_is_creating_event
1922
+		);
1923
+		return EEH_Template::display_template(
1924
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
1925
+			$template_args,
1926
+			true
1927
+		);
1928
+	}
1929
+
1930
+
1931
+
1932
+	/**
1933
+	 * @param int              $datetime_row
1934
+	 * @param int              $ticket_row
1935
+	 * @param EE_Datetime|null $datetime
1936
+	 * @param EE_Ticket|null   $ticket
1937
+	 * @param array            $ticket_datetimes
1938
+	 * @param bool             $default
1939
+	 * @return mixed
1940
+	 * @throws DomainException
1941
+	 * @throws EE_Error
1942
+	 */
1943
+	protected function _get_ticket_datetime_list_item(
1944
+		$datetime_row,
1945
+		$ticket_row,
1946
+		$datetime,
1947
+		$ticket,
1948
+		$ticket_datetimes = array(),
1949
+		$default
1950
+	) {
1951
+		$tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
1952
+			? $ticket_datetimes[$ticket->ID()]
1953
+			: array();
1954
+		$template_args = array(
1955
+			'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
1956
+				? 'DTTNUM'
1957
+				: $datetime_row,
1958
+			'tkt_row'                  => $default
1959
+				? 'TICKETNUM'
1960
+				: $ticket_row,
1961
+			'ticket_datetime_selected' => in_array($datetime_row, $tkt_datetimes, true)
1962
+				? ' ticket-selected'
1963
+				: '',
1964
+			'ticket_datetime_checked'  => in_array($datetime_row, $tkt_datetimes, true)
1965
+				? ' checked="checked"'
1966
+				: '',
1967
+			'DTT_name'                 => $default && empty($datetime)
1968
+				? 'DTTNAME'
1969
+				: $datetime->get_dtt_display_name(true),
1970
+			'tkt_status_class'         => '',
1971
+		);
1972
+		$template_args = apply_filters(
1973
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
1974
+			$template_args,
1975
+			$datetime_row,
1976
+			$ticket_row,
1977
+			$datetime,
1978
+			$ticket,
1979
+			$ticket_datetimes,
1980
+			$default,
1981
+			$this->_is_creating_event
1982
+		);
1983
+		return EEH_Template::display_template(
1984
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
1985
+			$template_args,
1986
+			true
1987
+		);
1988
+	}
1989
+
1990
+
1991
+
1992
+	/**
1993
+	 * @param array $all_datetimes
1994
+	 * @param array $all_tickets
1995
+	 * @return mixed
1996
+	 * @throws DomainException
1997
+	 * @throws EE_Error
1998
+	 */
1999
+	protected function _get_ticket_js_structure($all_datetimes = array(), $all_tickets = array())
2000
+	{
2001
+		$template_args = array(
2002
+			'default_datetime_edit_row'                => $this->_get_dtt_edit_row(
2003
+				'DTTNUM',
2004
+				null,
2005
+				true,
2006
+				$all_datetimes
2007
+			),
2008
+			'default_ticket_row'                       => $this->_get_ticket_row(
2009
+				'TICKETNUM',
2010
+				null,
2011
+				array(),
2012
+				array(),
2013
+				true
2014
+			),
2015
+			'default_price_row'                        => $this->_get_ticket_price_row(
2016
+				'TICKETNUM',
2017
+				'PRICENUM',
2018
+				null,
2019
+				true,
2020
+				null
2021
+			),
2022
+			'default_price_rows'                       => '',
2023
+			'default_base_price_amount'                => 0,
2024
+			'default_base_price_name'                  => '',
2025
+			'default_base_price_description'           => '',
2026
+			'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2027
+				'TICKETNUM',
2028
+				'PRICENUM',
2029
+				null,
2030
+				true
2031
+			),
2032
+			'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2033
+				'DTTNUM',
2034
+				null,
2035
+				array(),
2036
+				array(),
2037
+				true
2038
+			),
2039
+			'existing_available_datetime_tickets_list' => '',
2040
+			'existing_available_ticket_datetimes_list' => '',
2041
+			'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2042
+				'DTTNUM',
2043
+				'TICKETNUM',
2044
+				null,
2045
+				null,
2046
+				array(),
2047
+				true
2048
+			),
2049
+			'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2050
+				'DTTNUM',
2051
+				'TICKETNUM',
2052
+				null,
2053
+				null,
2054
+				array(),
2055
+				true
2056
+			),
2057
+		);
2058
+		$ticket_row = 1;
2059
+		foreach ($all_tickets as $ticket) {
2060
+			$template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2061
+				'DTTNUM',
2062
+				$ticket_row,
2063
+				null,
2064
+				$ticket,
2065
+				array(),
2066
+				true
2067
+			);
2068
+			$ticket_row++;
2069
+		}
2070
+		$datetime_row = 1;
2071
+		foreach ($all_datetimes as $datetime) {
2072
+			$template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2073
+				$datetime_row,
2074
+				'TICKETNUM',
2075
+				$datetime,
2076
+				null,
2077
+				array(),
2078
+				true
2079
+			);
2080
+			$datetime_row++;
2081
+		}
2082
+		/** @var EEM_Price $price_model */
2083
+		$price_model = EE_Registry::instance()->load_model('Price');
2084
+		$default_prices = $price_model->get_all_default_prices();
2085
+		$price_row = 1;
2086
+		foreach ($default_prices as $price) {
2087
+			if (! $price instanceof EE_Price) {
2088
+				continue;
2089
+			}
2090
+			if ($price->is_base_price()) {
2091
+				$template_args['default_base_price_amount'] = $price->get_pretty(
2092
+					'PRC_amount',
2093
+					'localized_float'
2094
+				);
2095
+				$template_args['default_base_price_name'] = $price->get('PRC_name');
2096
+				$template_args['default_base_price_description'] = $price->get('PRC_desc');
2097
+				$price_row++;
2098
+				continue;
2099
+			}
2100
+			$show_trash = !((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2101
+			$show_create = !(count($default_prices) > 1 && count($default_prices) !== $price_row);
2102
+			$template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2103
+				'TICKETNUM',
2104
+				$price_row,
2105
+				$price,
2106
+				true,
2107
+				null,
2108
+				$show_trash,
2109
+				$show_create
2110
+			);
2111
+			$price_row++;
2112
+		}
2113
+		$template_args = apply_filters(
2114
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2115
+			$template_args,
2116
+			$all_datetimes,
2117
+			$all_tickets,
2118
+			$this->_is_creating_event
2119
+		);
2120
+		return EEH_Template::display_template(
2121
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2122
+			$template_args,
2123
+			true
2124
+		);
2125
+	}
2126 2126
 
2127 2127
 
2128 2128
 } //end class espresso_events_Pricing_Hooks
Please login to merge, or discard this patch.
Spacing   +62 added lines, -62 removed lines patch added patch discarded remove patch
@@ -49,7 +49,7 @@  discard block
 block discarded – undo
49 49
     {
50 50
         $this->_name = 'pricing';
51 51
         //capability check
52
-        if (! EE_Registry::instance()->CAP->current_user_can(
52
+        if ( ! EE_Registry::instance()->CAP->current_user_can(
53 53
             'ee_read_default_prices',
54 54
             'advanced_ticket_datetime_metabox'
55 55
         )) {
@@ -125,7 +125,7 @@  discard block
 block discarded – undo
125 125
         $this->_date_format_strings['time'] = isset($this->_date_format_strings['time'])
126 126
             ? $this->_date_format_strings['time']
127 127
             : null;
128
-        $this->_date_time_format = $this->_date_format_strings['date'] . ' ' . $this->_date_format_strings['time'];
128
+        $this->_date_time_format = $this->_date_format_strings['date'].' '.$this->_date_format_strings['time'];
129 129
     }
130 130
 
131 131
 
@@ -150,7 +150,7 @@  discard block
 block discarded – undo
150 150
             );
151 151
             $msg .= '</p><ul>';
152 152
             foreach ($format_validation as $error) {
153
-                $msg .= '<li>' . $error . '</li>';
153
+                $msg .= '<li>'.$error.'</li>';
154 154
             }
155 155
             $msg .= '</ul><p>';
156 156
             $msg .= sprintf(
@@ -180,11 +180,11 @@  discard block
 block discarded – undo
180 180
         $this->_scripts_styles = array(
181 181
             'registers'   => array(
182 182
                 'ee-tickets-datetimes-css' => array(
183
-                    'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
183
+                    'url'  => PRICING_ASSETS_URL.'event-tickets-datetimes.css',
184 184
                     'type' => 'css',
185 185
                 ),
186 186
                 'ee-dtt-ticket-metabox'    => array(
187
-                    'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
187
+                    'url'     => PRICING_ASSETS_URL.'ee-datetime-ticket-metabox.js',
188 188
                     'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
189 189
                 ),
190 190
             ),
@@ -208,9 +208,9 @@  discard block
 block discarded – undo
208 208
                             'event_espresso'
209 209
                         ),
210 210
                         'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
211
-                                                     . esc_html__('Cancel', 'event_espresso') . '</button>',
211
+                                                     . esc_html__('Cancel', 'event_espresso').'</button>',
212 212
                         'close_button'            => '<button class="button-secondary ee-modal-cancel">'
213
-                                                     . esc_html__('Close', 'event_espresso') . '</button>',
213
+                                                     . esc_html__('Close', 'event_espresso').'</button>',
214 214
                         'single_warning_from_tkt' => esc_html__(
215 215
                             'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
216 216
                             'event_espresso'
@@ -220,12 +220,12 @@  discard block
 block discarded – undo
220 220
                             'event_espresso'
221 221
                         ),
222 222
                         'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
223
-                                                     . esc_html__('Dismiss', 'event_espresso') . '</button>',
223
+                                                     . esc_html__('Dismiss', 'event_espresso').'</button>',
224 224
                     ),
225 225
                     'DTT_ERROR_MSG'         => array(
226 226
                         'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
227 227
                         'dismiss_button' => '<div class="save-cancel-button-container"><button class="button-secondary ee-modal-cancel">'
228
-                                            . esc_html__('Dismiss', 'event_espresso') . '</button></div>',
228
+                                            . esc_html__('Dismiss', 'event_espresso').'</button></div>',
229 229
                     ),
230 230
                     'DTT_OVERSELL_WARNING'  => array(
231 231
                         'datetime_ticket' => esc_html__(
@@ -241,7 +241,7 @@  discard block
 block discarded – undo
241 241
                         $this->_date_format_strings['date'],
242 242
                         $this->_date_format_strings['time']
243 243
                     ),
244
-                    'DTT_START_OF_WEEK'     => array('dayValue' => (int)get_option('start_of_week')),
244
+                    'DTT_START_OF_WEEK'     => array('dayValue' => (int) get_option('start_of_week')),
245 245
                 ),
246 246
             ),
247 247
         );
@@ -296,7 +296,7 @@  discard block
 block discarded – undo
296 296
         $timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
297 297
         $saved_dtt_ids = array();
298 298
         $saved_dtt_objs = array();
299
-        if (empty($data['edit_event_datetimes']) || !is_array($data['edit_event_datetimes'])) {
299
+        if (empty($data['edit_event_datetimes']) || ! is_array($data['edit_event_datetimes'])) {
300 300
             throw new InvalidArgumentException(
301 301
                 esc_html__(
302 302
                     'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
@@ -307,7 +307,7 @@  discard block
 block discarded – undo
307 307
         foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
308 308
             //trim all values to ensure any excess whitespace is removed.
309 309
             $datetime_data = array_map(
310
-                function ($datetime_data) {
310
+                function($datetime_data) {
311 311
                     return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
312 312
                 },
313 313
                 $datetime_data
@@ -337,7 +337,7 @@  discard block
 block discarded – undo
337 337
             );
338 338
             // if we have an id then let's get existing object first and then set the new values.
339 339
             // Otherwise we instantiate a new object for save.
340
-            if (! empty($datetime_data['DTT_ID'])) {
340
+            if ( ! empty($datetime_data['DTT_ID'])) {
341 341
                 $datetime = EE_Registry::instance()
342 342
                                        ->load_model('Datetime', array($timezone))
343 343
                                        ->get_one_by_ID($datetime_data['DTT_ID']);
@@ -430,7 +430,7 @@  discard block
 block discarded – undo
430 430
         $timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
431 431
         $saved_tickets = $datetimes_on_existing = array();
432 432
         $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
433
-        if(empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])){
433
+        if (empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])) {
434 434
             throw new InvalidArgumentException(
435 435
                 esc_html__(
436 436
                     'The "edit_tickets" array is invalid therefore the event can not be updated.',
@@ -448,7 +448,7 @@  discard block
 block discarded – undo
448 448
             $datetimes_removed = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
449 449
             // trim inputs to ensure any excess whitespace is removed.
450 450
             $tkt = array_map(
451
-                function ($ticket_data) {
451
+                function($ticket_data) {
452 452
                     return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
453 453
                 },
454 454
                 $tkt
@@ -457,7 +457,7 @@  discard block
 block discarded – undo
457 457
             // because we're doing calculations prior to using the models.
458 458
             // note incoming ['TKT_price'] value is already in standard notation (via js).
459 459
             $ticket_price = isset($tkt['TKT_price'])
460
-                ? round((float)$tkt['TKT_price'], 3)
460
+                ? round((float) $tkt['TKT_price'], 3)
461 461
                 : 0;
462 462
             //note incoming base price needs converted from localized value.
463 463
             $base_price = isset($tkt['TKT_base_price'])
@@ -604,7 +604,7 @@  discard block
 block discarded – undo
604 604
             //need to make sue that the TKT_price is accurate after saving the prices.
605 605
             $ticket->ensure_TKT_Price_correct();
606 606
             //handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
607
-            if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
607
+            if ( ! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
608 608
                 $update_prices = true;
609 609
                 $new_default = clone $ticket;
610 610
                 $new_default->set('TKT_ID', 0);
@@ -723,9 +723,9 @@  discard block
 block discarded – undo
723 723
         // to start we have to add the ticket to all the datetimes its supposed to be with,
724 724
         // and removing the ticket from datetimes it got removed from.
725 725
         // first let's add datetimes
726
-        if (! empty($added_datetimes) && is_array($added_datetimes)) {
726
+        if ( ! empty($added_datetimes) && is_array($added_datetimes)) {
727 727
             foreach ($added_datetimes as $row_id) {
728
-                $row_id = (int)$row_id;
728
+                $row_id = (int) $row_id;
729 729
                 if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
730 730
                     $ticket->_add_relation_to($saved_datetimes[$row_id], 'Datetime');
731 731
                     // Is this an existing ticket (has an ID) and does it have any sold?
@@ -738,9 +738,9 @@  discard block
 block discarded – undo
738 738
             }
739 739
         }
740 740
         // then remove datetimes
741
-        if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
741
+        if ( ! empty($removed_datetimes) && is_array($removed_datetimes)) {
742 742
             foreach ($removed_datetimes as $row_id) {
743
-                $row_id = (int)$row_id;
743
+                $row_id = (int) $row_id;
744 744
                 // its entirely possible that a datetime got deleted (instead of just removed from relationship.
745 745
                 // So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
746 746
                 if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
@@ -850,7 +850,7 @@  discard block
 block discarded – undo
850 850
             );
851 851
         }
852 852
         //possibly need to save tkt
853
-        if (! $ticket->ID()) {
853
+        if ( ! $ticket->ID()) {
854 854
             $ticket->save();
855 855
         }
856 856
         foreach ($prices as $row => $prc) {
@@ -888,11 +888,11 @@  discard block
 block discarded – undo
888 888
             $ticket->_add_relation_to($price, 'Price');
889 889
         }
890 890
         //now let's remove any prices that got removed from the ticket
891
-        if (! empty ($current_prices_on_ticket)) {
891
+        if ( ! empty ($current_prices_on_ticket)) {
892 892
             $current = array_keys($current_prices_on_ticket);
893 893
             $updated = array_keys($updated_prices);
894 894
             $prices_to_remove = array_diff($current, $updated);
895
-            if (! empty($prices_to_remove)) {
895
+            if ( ! empty($prices_to_remove)) {
896 896
                 foreach ($prices_to_remove as $prc_id) {
897 897
                     $p = $current_prices_on_ticket[$prc_id];
898 898
                     $ticket->_remove_relation_to($p, 'Price');
@@ -910,7 +910,7 @@  discard block
 block discarded – undo
910 910
      * @param Events_Admin_Page $event_admin_obj
911 911
      * @return Events_Admin_Page
912 912
      */
913
-    public function autosave_handling( Events_Admin_Page $event_admin_obj)
913
+    public function autosave_handling(Events_Admin_Page $event_admin_obj)
914 914
     {
915 915
         return $event_admin_obj;
916 916
         //doing nothing for the moment.
@@ -1043,7 +1043,7 @@  discard block
 block discarded – undo
1043 1043
                 $TKT_ID = $ticket->get('TKT_ID');
1044 1044
                 $ticket_row = $ticket->get('TKT_row');
1045 1045
                 //we only want unique tickets in our final display!!
1046
-                if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1046
+                if ( ! in_array($TKT_ID, $existing_ticket_ids, true)) {
1047 1047
                     $existing_ticket_ids[] = $TKT_ID;
1048 1048
                     $all_tickets[] = $ticket;
1049 1049
                 }
@@ -1065,9 +1065,9 @@  discard block
 block discarded – undo
1065 1065
         //sort $all_tickets by order
1066 1066
         usort(
1067 1067
             $all_tickets,
1068
-            function (EE_Ticket $a, EE_Ticket $b) {
1069
-                $a_order = (int)$a->get('TKT_order');
1070
-                $b_order = (int)$b->get('TKT_order');
1068
+            function(EE_Ticket $a, EE_Ticket $b) {
1069
+                $a_order = (int) $a->get('TKT_order');
1070
+                $b_order = (int) $b->get('TKT_order');
1071 1071
                 if ($a_order === $b_order) {
1072 1072
                     return 0;
1073 1073
                 }
@@ -1103,7 +1103,7 @@  discard block
 block discarded – undo
1103 1103
         }
1104 1104
         $main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1105 1105
         EEH_Template::display_template(
1106
-            PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1106
+            PRICING_TEMPLATE_PATH.'event_tickets_metabox_main.template.php',
1107 1107
             $main_template_args
1108 1108
         );
1109 1109
     }
@@ -1141,7 +1141,7 @@  discard block
 block discarded – undo
1141 1141
             'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1142 1142
         );
1143 1143
         return EEH_Template::display_template(
1144
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1144
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_row_wrapper.template.php',
1145 1145
             $dtt_display_template_args,
1146 1146
             true
1147 1147
         );
@@ -1211,7 +1211,7 @@  discard block
 block discarded – undo
1211 1211
             $this->_is_creating_event
1212 1212
         );
1213 1213
         return EEH_Template::display_template(
1214
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1214
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_edit_row.template.php',
1215 1215
             $template_args,
1216 1216
             true
1217 1217
         );
@@ -1253,7 +1253,7 @@  discard block
 block discarded – undo
1253 1253
             'DTT_ID'                            => $default ? '' : $datetime->ID(),
1254 1254
         );
1255 1255
         //need to setup the list items (but only if this isn't a default skeleton setup)
1256
-        if (! $default) {
1256
+        if ( ! $default) {
1257 1257
             $ticket_row = 1;
1258 1258
             foreach ($all_tickets as $ticket) {
1259 1259
                 $template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
@@ -1279,7 +1279,7 @@  discard block
 block discarded – undo
1279 1279
             $this->_is_creating_event
1280 1280
         );
1281 1281
         return EEH_Template::display_template(
1282
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1282
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_attached_tickets_row.template.php',
1283 1283
             $template_args,
1284 1284
             true
1285 1285
         );
@@ -1328,8 +1328,8 @@  discard block
 block discarded – undo
1328 1328
                 ? 'TKTNAME'
1329 1329
                 : $ticket->get('TKT_name'),
1330 1330
             'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1331
-                ? ' tkt-status-' . EE_Ticket::onsale
1332
-                : ' tkt-status-' . $ticket->ticket_status(),
1331
+                ? ' tkt-status-'.EE_Ticket::onsale
1332
+                : ' tkt-status-'.$ticket->ticket_status(),
1333 1333
         );
1334 1334
         //filter template args
1335 1335
         $template_args = apply_filters(
@@ -1344,7 +1344,7 @@  discard block
 block discarded – undo
1344 1344
             $this->_is_creating_event
1345 1345
         );
1346 1346
         return EEH_Template::display_template(
1347
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1347
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_dtt_tickets_list.template.php',
1348 1348
             $template_args,
1349 1349
             true
1350 1350
         );
@@ -1401,11 +1401,11 @@  discard block
 block discarded – undo
1401 1401
         $count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1402 1402
         //breaking out complicated condition for ticket_status
1403 1403
         if ($default) {
1404
-            $ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1404
+            $ticket_status_class = ' tkt-status-'.EE_Ticket::onsale;
1405 1405
         } else {
1406 1406
             $ticket_status_class = $ticket->is_default()
1407
-                ? ' tkt-status-' . EE_Ticket::onsale
1408
-                : ' tkt-status-' . $ticket->ticket_status();
1407
+                ? ' tkt-status-'.EE_Ticket::onsale
1408
+                : ' tkt-status-'.$ticket->ticket_status();
1409 1409
         }
1410 1410
         //breaking out complicated condition for TKT_taxable
1411 1411
         if ($default) {
@@ -1497,7 +1497,7 @@  discard block
 block discarded – undo
1497 1497
                 : ' style="display:none;"',
1498 1498
             'show_price_mod_button'         => count($prices) > 1
1499 1499
                                                || ($default && $count_price_mods > 0)
1500
-                                               || (! $default && $ticket->deleted())
1500
+                                               || ( ! $default && $ticket->deleted())
1501 1501
                 ? ' style="display:none;"'
1502 1502
                 : '',
1503 1503
             'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
@@ -1539,7 +1539,7 @@  discard block
 block discarded – undo
1539 1539
             //if empty then the start date will be now.
1540 1540
             $template_args['TKT_start_date'] = date($this->_date_time_format,
1541 1541
                 current_time('timestamp'));
1542
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1542
+            $template_args['tkt_status_class'] = ' tkt-status-'.EE_Ticket::onsale;
1543 1543
         }
1544 1544
         if (empty($template_args['TKT_end_date'])) {
1545 1545
             //get the earliest datetime (if present);
@@ -1549,7 +1549,7 @@  discard block
 block discarded – undo
1549 1549
                     array('order_by' => array('DTT_EVT_start' => 'ASC'))
1550 1550
                 )
1551 1551
                 : null;
1552
-            if (! empty($earliest_dtt)) {
1552
+            if ( ! empty($earliest_dtt)) {
1553 1553
                 $template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1554 1554
                     'DTT_EVT_start',
1555 1555
                     $this->_date_time_format
@@ -1562,10 +1562,10 @@  discard block
 block discarded – undo
1562 1562
                     )
1563 1563
                 );
1564 1564
             }
1565
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1565
+            $template_args['tkt_status_class'] = ' tkt-status-'.EE_Ticket::onsale;
1566 1566
         }
1567 1567
         //generate ticket_datetime items
1568
-        if (! $default) {
1568
+        if ( ! $default) {
1569 1569
             $datetime_row = 1;
1570 1570
             foreach ($all_datetimes as $datetime) {
1571 1571
                 $template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
@@ -1581,15 +1581,15 @@  discard block
 block discarded – undo
1581 1581
         }
1582 1582
         $price_row = 1;
1583 1583
         foreach ($prices as $price) {
1584
-            if (! $price instanceof EE_Price)  {
1584
+            if ( ! $price instanceof EE_Price) {
1585 1585
                 continue;
1586 1586
             }
1587 1587
             if ($price->is_base_price()) {
1588 1588
                 $price_row++;
1589 1589
                 continue;
1590 1590
             }
1591
-            $show_trash = !((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1592
-            $show_create = !(count($prices) > 1 && count($prices) !== $price_row);
1591
+            $show_trash = ! ((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1592
+            $show_create = ! (count($prices) > 1 && count($prices) !== $price_row);
1593 1593
             $template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1594 1594
                 $ticket_row,
1595 1595
                 $price_row,
@@ -1614,7 +1614,7 @@  discard block
 block discarded – undo
1614 1614
             $this->_is_creating_event
1615 1615
         );
1616 1616
         return EEH_Template::display_template(
1617
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1617
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_row.template.php',
1618 1618
             $template_args,
1619 1619
             true
1620 1620
         );
@@ -1655,7 +1655,7 @@  discard block
 block discarded – undo
1655 1655
                 $this->_is_creating_event
1656 1656
             );
1657 1657
             $tax_rows .= EEH_Template::display_template(
1658
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1658
+                PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_tax_row.template.php',
1659 1659
                 $template_args,
1660 1660
                 true
1661 1661
             );
@@ -1767,7 +1767,7 @@  discard block
 block discarded – undo
1767 1767
             $this->_is_creating_event
1768 1768
         );
1769 1769
         return EEH_Template::display_template(
1770
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1770
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_price_row.template.php',
1771 1771
             $template_args,
1772 1772
             true
1773 1773
         );
@@ -1824,7 +1824,7 @@  discard block
 block discarded – undo
1824 1824
             $this->_is_creating_event
1825 1825
         );
1826 1826
         return EEH_Template::display_template(
1827
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1827
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_type_base.template.php',
1828 1828
             $template_args,
1829 1829
             true
1830 1830
         );
@@ -1851,7 +1851,7 @@  discard block
 block discarded – undo
1851 1851
     ) {
1852 1852
         $select_name = $default && ! $price instanceof EE_Price
1853 1853
             ? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1854
-            : 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1854
+            : 'edit_prices['.$ticket_row.']['.$price_row.'][PRT_ID]';
1855 1855
         /** @var EEM_Price_Type $price_type_model */
1856 1856
         $price_type_model = EE_Registry::instance()->load_model('Price_Type');
1857 1857
         $price_types = $price_type_model->get_all(array(
@@ -1869,7 +1869,7 @@  discard block
 block discarded – undo
1869 1869
         $price_option_spans = '';
1870 1870
         //setup price types for selector
1871 1871
         foreach ($price_types as $price_type) {
1872
-            if (! $price_type instanceof EE_Price_Type) {
1872
+            if ( ! $price_type instanceof EE_Price_Type) {
1873 1873
                 continue;
1874 1874
             }
1875 1875
             $all_price_types[$price_type->ID()] = $price_type->get('PRT_name');
@@ -1880,12 +1880,12 @@  discard block
 block discarded – undo
1880 1880
                 'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1881 1881
             );
1882 1882
             $price_option_spans .= EEH_Template::display_template(
1883
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1883
+                PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_option_span.template.php',
1884 1884
                 $span_args,
1885 1885
                 true
1886 1886
             );
1887 1887
         }
1888
-        $select_name = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]' : $select_name;
1888
+        $select_name = $disabled ? 'archive_price['.$ticket_row.']['.$price_row.'][PRT_ID]' : $select_name;
1889 1889
         $select_input = new EE_Select_Input(
1890 1890
             $all_price_types,
1891 1891
             array(
@@ -1921,7 +1921,7 @@  discard block
 block discarded – undo
1921 1921
             $this->_is_creating_event
1922 1922
         );
1923 1923
         return EEH_Template::display_template(
1924
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
1924
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_modifier_selector.template.php',
1925 1925
             $template_args,
1926 1926
             true
1927 1927
         );
@@ -1981,7 +1981,7 @@  discard block
 block discarded – undo
1981 1981
             $this->_is_creating_event
1982 1982
         );
1983 1983
         return EEH_Template::display_template(
1984
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
1984
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_datetimes_list_item.template.php',
1985 1985
             $template_args,
1986 1986
             true
1987 1987
         );
@@ -2084,7 +2084,7 @@  discard block
 block discarded – undo
2084 2084
         $default_prices = $price_model->get_all_default_prices();
2085 2085
         $price_row = 1;
2086 2086
         foreach ($default_prices as $price) {
2087
-            if (! $price instanceof EE_Price) {
2087
+            if ( ! $price instanceof EE_Price) {
2088 2088
                 continue;
2089 2089
             }
2090 2090
             if ($price->is_base_price()) {
@@ -2097,8 +2097,8 @@  discard block
 block discarded – undo
2097 2097
                 $price_row++;
2098 2098
                 continue;
2099 2099
             }
2100
-            $show_trash = !((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2101
-            $show_create = !(count($default_prices) > 1 && count($default_prices) !== $price_row);
2100
+            $show_trash = ! ((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2101
+            $show_create = ! (count($default_prices) > 1 && count($default_prices) !== $price_row);
2102 2102
             $template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2103 2103
                 'TICKETNUM',
2104 2104
                 $price_row,
@@ -2118,7 +2118,7 @@  discard block
 block discarded – undo
2118 2118
             $this->_is_creating_event
2119 2119
         );
2120 2120
         return EEH_Template::display_template(
2121
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2121
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_js_structure.template.php',
2122 2122
             $template_args,
2123 2123
             true
2124 2124
         );
Please login to merge, or discard this patch.
admin/extend/messages/espresso_events_Messages_Hooks_Extend.class.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -98,7 +98,7 @@
 block discarded – undo
98 98
      *
99 99
      * @param  EE_Event $event EE event object
100 100
      * @param  array    $data  The request data from the form
101
-     * @return bool success or fail
101
+     * @return integer success or fail
102 102
      * @throws EE_Error
103 103
      */
104 104
     public function attach_evt_message_templates($event, $data)
Please login to merge, or discard this patch.
Indentation   +267 added lines, -267 removed lines patch added patch discarded remove patch
@@ -14,276 +14,276 @@
 block discarded – undo
14 14
  */
15 15
 class espresso_events_Messages_Hooks_Extend extends espresso_events_Messages_Hooks
16 16
 {
17
-    /**
18
-     * espresso_events_Messages_Hooks_Extend constructor.
19
-     *
20
-     * @param \EE_Admin_Page $admin_page
21
-     */
22
-    public function __construct(EE_Admin_Page $admin_page)
23
-    {
24
-        /**
25
-         * Add cap restriction ... metaboxes should not show if user does not have the ability to edit_custom_messages
26
-         */
27
-        if (! EE_Registry::instance()->CAP->current_user_can(
28
-            'ee_edit_messages',
29
-            'messages_events_editor_metabox'
30
-        )) {
31
-            return;
32
-        }
33
-        add_filter(
34
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
35
-            array($this, 'caf_updates'),
36
-            10
37
-        );
38
-        add_action(
39
-            'AHEE__Extend_Events_Admin_Page___duplicate_event__after',
40
-            array($this, 'duplicate_custom_message_settings'),
41
-            10,
42
-            2
43
-        );
44
-        parent::__construct($admin_page);
45
-    }
46
-
47
-
48
-    /**
49
-     * extending the properties set in espresso_events_Messages_Hooks
50
-     *
51
-     * @access protected
52
-     * @return void
53
-     */
54
-    protected function _extend_properties()
55
-    {
56
-        define('EE_MSGS_EXTEND_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'messages/assets/');
57
-        $this->_ajax_func = array(
58
-            'ee_msgs_create_new_custom' => 'create_new_custom',
59
-        );
60
-        $this->_metaboxes = array(
61
-            0 => array(
62
-                'page_route' => array('edit', 'create_new'),
63
-                'func'       => 'messages_metabox',
64
-                'label'      => esc_html__('Notifications', 'event_espresso'),
65
-                'priority'   => 'high',
66
-            ),
67
-        );
68
-
69
-        //see explanation for layout in EE_Admin_Hooks
70
-        $this->_scripts_styles = array(
71
-            'registers' => array(
72
-                'events_msg_admin'     => array(
73
-                    'url'     => EE_MSGS_EXTEND_ASSETS_URL . 'events_messages_admin.js',
74
-                    'depends' => array('ee-dialog', 'ee-parse-uri', 'ee-serialize-full-array'),
75
-                ),
76
-                'events_msg_admin_css' => array(
77
-                    'url'  => EE_MSGS_EXTEND_ASSETS_URL . 'ee_msg_events_admin.css',
78
-                    'type' => 'css',
79
-                ),
80
-            ),
81
-            'enqueues'  => array(
82
-                'events_msg_admin'     => array('edit', 'create_new'),
83
-                'events_msg_admin_css' => array('edit', 'create_new'),
84
-            ),
85
-        );
86
-    }
87
-
88
-
89
-    public function caf_updates($update_callbacks)
90
-    {
91
-        $update_callbacks[] = array($this, 'attach_evt_message_templates');
92
-        return $update_callbacks;
93
-    }
94
-
95
-
96
-    /**
97
-     * Handles attaching Message Templates to the Event on save.
98
-     *
99
-     * @param  EE_Event $event EE event object
100
-     * @param  array    $data  The request data from the form
101
-     * @return bool success or fail
102
-     * @throws EE_Error
103
-     */
104
-    public function attach_evt_message_templates($event, $data)
105
-    {
106
-        //first we remove all existing relations on the Event for message types.
107
-        $event->_remove_relations('Message_Template_Group');
108
-        //now let's just loop through the selected templates and add relations!
109
-        if (isset($data['event_message_templates_relation'])) {
110
-            foreach ($data['event_message_templates_relation'] as $grp_ID) {
111
-                $event->_add_relation_to($grp_ID, 'Message_Template_Group');
112
-            }
113
-        }
114
-        //now save
115
-        return $event->save();
116
-    }
117
-
118
-
119
-    /**
120
-     * @param $event
121
-     * @param $callback_args
122
-     * @return string
123
-     * @throws \EE_Error
124
-     */
125
-    public function messages_metabox($event, $callback_args)
126
-    {
127
-        //let's get the active messengers (b/c messenger objects have the active message templates)
128
-        //convert 'evt_id' to 'EVT_ID'
129
-        $this->_req_data['EVT_ID'] = isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null;
130
-        $this->_req_data['EVT_ID'] = isset($this->_req_data['post']) && empty($this->_req_data['EVT_ID'])
131
-            ? $this->_req_data['post']
132
-            : $this->_req_data['EVT_ID'];
133
-
134
-        $this->_req_data['EVT_ID'] = empty($this->_req_data['EVT_ID']) && isset($this->_req_data['evt_id'])
135
-            ? $this->_req_data['evt_id']
136
-            : $this->_req_data['EVT_ID'];
137
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
138
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
139
-        $active_messengers        = $message_resource_manager->active_messengers();
140
-        $tabs                     = array();
141
-
142
-        //empty messengers?
143
-        //Note message types will always have at least one available because every messenger has a default message type
144
-        // associated with it (payment) if no other message types are selected.
145
-        if (empty($active_messengers)) {
146
-            $msg_activate_url = EE_Admin_Page::add_query_args_and_nonce(
147
-                array('action' => 'settings'),
148
-                EE_MSG_ADMIN_URL
149
-            );
150
-            $error_msg        = sprintf(
151
-                esc_html__(
152
-                    'There are no active messengers. So no notifications will go out for %1$sany%2$s events.  You will want to %3$sActivate a Messenger%4$s.',
153
-                    'event_espresso'
154
-                ),
155
-                '<strong>',
156
-                '</strong>',
157
-                '<a href="' . $msg_activate_url . '">',
158
-                '</a>'
159
-            );
160
-            $error_content    = '<div class="error"><p>' . $error_msg . '</p></div>';
161
-            $internal_content = '<div id="messages-error"><p>' . $error_msg . '</p></div>';
162
-
163
-            echo $error_content;
164
-            echo $internal_content;
165
-            return '';
166
-        }
167
-
168
-        $event_id = isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null;
169
-        //get content for active messengers
170
-        foreach ($active_messengers as $name => $messenger) {
171
-            //first check if there are any active message types for this messenger.
172
-            $active_mts = $message_resource_manager->get_active_message_types_for_messenger($name);
173
-            if (empty($active_mts)) {
174
-                continue;
175
-            }
176
-
177
-            $tab_content = $messenger->get_messenger_admin_page_content(
178
-                'events',
179
-                'edit',
180
-                array('event' => $event_id)
181
-            );
182
-
183
-            if (! empty($tab_content)) {
184
-                $tabs[$name] = $tab_content;
185
-            }
186
-        }
187
-
188
-
189
-        //we want this to be tabbed content so let's use the EEH_Tabbed_Content::display helper.
190
-        $tabbed_content = EEH_Tabbed_Content::display($tabs);
191
-        if ($tabbed_content instanceof WP_Error) {
192
-            $tabbed_content = $tabbed_content->get_error_message();
193
-        }
194
-
195
-        $notices = '
17
+	/**
18
+	 * espresso_events_Messages_Hooks_Extend constructor.
19
+	 *
20
+	 * @param \EE_Admin_Page $admin_page
21
+	 */
22
+	public function __construct(EE_Admin_Page $admin_page)
23
+	{
24
+		/**
25
+		 * Add cap restriction ... metaboxes should not show if user does not have the ability to edit_custom_messages
26
+		 */
27
+		if (! EE_Registry::instance()->CAP->current_user_can(
28
+			'ee_edit_messages',
29
+			'messages_events_editor_metabox'
30
+		)) {
31
+			return;
32
+		}
33
+		add_filter(
34
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
35
+			array($this, 'caf_updates'),
36
+			10
37
+		);
38
+		add_action(
39
+			'AHEE__Extend_Events_Admin_Page___duplicate_event__after',
40
+			array($this, 'duplicate_custom_message_settings'),
41
+			10,
42
+			2
43
+		);
44
+		parent::__construct($admin_page);
45
+	}
46
+
47
+
48
+	/**
49
+	 * extending the properties set in espresso_events_Messages_Hooks
50
+	 *
51
+	 * @access protected
52
+	 * @return void
53
+	 */
54
+	protected function _extend_properties()
55
+	{
56
+		define('EE_MSGS_EXTEND_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'messages/assets/');
57
+		$this->_ajax_func = array(
58
+			'ee_msgs_create_new_custom' => 'create_new_custom',
59
+		);
60
+		$this->_metaboxes = array(
61
+			0 => array(
62
+				'page_route' => array('edit', 'create_new'),
63
+				'func'       => 'messages_metabox',
64
+				'label'      => esc_html__('Notifications', 'event_espresso'),
65
+				'priority'   => 'high',
66
+			),
67
+		);
68
+
69
+		//see explanation for layout in EE_Admin_Hooks
70
+		$this->_scripts_styles = array(
71
+			'registers' => array(
72
+				'events_msg_admin'     => array(
73
+					'url'     => EE_MSGS_EXTEND_ASSETS_URL . 'events_messages_admin.js',
74
+					'depends' => array('ee-dialog', 'ee-parse-uri', 'ee-serialize-full-array'),
75
+				),
76
+				'events_msg_admin_css' => array(
77
+					'url'  => EE_MSGS_EXTEND_ASSETS_URL . 'ee_msg_events_admin.css',
78
+					'type' => 'css',
79
+				),
80
+			),
81
+			'enqueues'  => array(
82
+				'events_msg_admin'     => array('edit', 'create_new'),
83
+				'events_msg_admin_css' => array('edit', 'create_new'),
84
+			),
85
+		);
86
+	}
87
+
88
+
89
+	public function caf_updates($update_callbacks)
90
+	{
91
+		$update_callbacks[] = array($this, 'attach_evt_message_templates');
92
+		return $update_callbacks;
93
+	}
94
+
95
+
96
+	/**
97
+	 * Handles attaching Message Templates to the Event on save.
98
+	 *
99
+	 * @param  EE_Event $event EE event object
100
+	 * @param  array    $data  The request data from the form
101
+	 * @return bool success or fail
102
+	 * @throws EE_Error
103
+	 */
104
+	public function attach_evt_message_templates($event, $data)
105
+	{
106
+		//first we remove all existing relations on the Event for message types.
107
+		$event->_remove_relations('Message_Template_Group');
108
+		//now let's just loop through the selected templates and add relations!
109
+		if (isset($data['event_message_templates_relation'])) {
110
+			foreach ($data['event_message_templates_relation'] as $grp_ID) {
111
+				$event->_add_relation_to($grp_ID, 'Message_Template_Group');
112
+			}
113
+		}
114
+		//now save
115
+		return $event->save();
116
+	}
117
+
118
+
119
+	/**
120
+	 * @param $event
121
+	 * @param $callback_args
122
+	 * @return string
123
+	 * @throws \EE_Error
124
+	 */
125
+	public function messages_metabox($event, $callback_args)
126
+	{
127
+		//let's get the active messengers (b/c messenger objects have the active message templates)
128
+		//convert 'evt_id' to 'EVT_ID'
129
+		$this->_req_data['EVT_ID'] = isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null;
130
+		$this->_req_data['EVT_ID'] = isset($this->_req_data['post']) && empty($this->_req_data['EVT_ID'])
131
+			? $this->_req_data['post']
132
+			: $this->_req_data['EVT_ID'];
133
+
134
+		$this->_req_data['EVT_ID'] = empty($this->_req_data['EVT_ID']) && isset($this->_req_data['evt_id'])
135
+			? $this->_req_data['evt_id']
136
+			: $this->_req_data['EVT_ID'];
137
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
138
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
139
+		$active_messengers        = $message_resource_manager->active_messengers();
140
+		$tabs                     = array();
141
+
142
+		//empty messengers?
143
+		//Note message types will always have at least one available because every messenger has a default message type
144
+		// associated with it (payment) if no other message types are selected.
145
+		if (empty($active_messengers)) {
146
+			$msg_activate_url = EE_Admin_Page::add_query_args_and_nonce(
147
+				array('action' => 'settings'),
148
+				EE_MSG_ADMIN_URL
149
+			);
150
+			$error_msg        = sprintf(
151
+				esc_html__(
152
+					'There are no active messengers. So no notifications will go out for %1$sany%2$s events.  You will want to %3$sActivate a Messenger%4$s.',
153
+					'event_espresso'
154
+				),
155
+				'<strong>',
156
+				'</strong>',
157
+				'<a href="' . $msg_activate_url . '">',
158
+				'</a>'
159
+			);
160
+			$error_content    = '<div class="error"><p>' . $error_msg . '</p></div>';
161
+			$internal_content = '<div id="messages-error"><p>' . $error_msg . '</p></div>';
162
+
163
+			echo $error_content;
164
+			echo $internal_content;
165
+			return '';
166
+		}
167
+
168
+		$event_id = isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null;
169
+		//get content for active messengers
170
+		foreach ($active_messengers as $name => $messenger) {
171
+			//first check if there are any active message types for this messenger.
172
+			$active_mts = $message_resource_manager->get_active_message_types_for_messenger($name);
173
+			if (empty($active_mts)) {
174
+				continue;
175
+			}
176
+
177
+			$tab_content = $messenger->get_messenger_admin_page_content(
178
+				'events',
179
+				'edit',
180
+				array('event' => $event_id)
181
+			);
182
+
183
+			if (! empty($tab_content)) {
184
+				$tabs[$name] = $tab_content;
185
+			}
186
+		}
187
+
188
+
189
+		//we want this to be tabbed content so let's use the EEH_Tabbed_Content::display helper.
190
+		$tabbed_content = EEH_Tabbed_Content::display($tabs);
191
+		if ($tabbed_content instanceof WP_Error) {
192
+			$tabbed_content = $tabbed_content->get_error_message();
193
+		}
194
+
195
+		$notices = '
196 196
 	<div id="espresso-ajax-loading" class="ajax-loader-grey">
197 197
 		<span class="ee-spinner ee-spin"></span><span class="hidden">'
198
-        . esc_html__('loading...', 'event_espresso')
199
-        . '</span>
198
+		. esc_html__('loading...', 'event_espresso')
199
+		. '</span>
200 200
 	</div>
201 201
 	<div class="ee-notices"></div>';
202 202
 
203
-        if (defined('DOING_AJAX')) {
204
-            return $tabbed_content;
205
-        }
206
-
207
-        do_action('AHEE__espresso_events_Messages_Hooks_Extend__messages_metabox__before_content');
208
-        echo $notices . '<div class="messages-tabs-content">' . $tabbed_content . '</div>';
209
-        do_action('AHEE__espresso_events_Messages_Hooks_Extend__messages_metabox__after_content');
210
-    }
211
-
212
-
213
-    /**
214
-     * Ajax callback for ee_msgs_create_new_custom ajax request.
215
-     * Takes incoming GRP_ID and name and description values from ajax request
216
-     * to create a new custom template based off of the incoming GRP_ID.
217
-     *
218
-     * @access public
219
-     * @return string either an html string will be returned or a success message
220
-     * @throws EE_Error
221
-     */
222
-    public function create_new_custom()
223
-    {
224
-        if (! EE_Registry::instance()->CAP->current_user_can('ee_edit_messages', 'create_new_custom_ajax')) {
225
-            wp_die(__('You don\'t have privileges to do this action', 'event_espresso'));
226
-        }
227
-
228
-        //let's clean up the _POST global a bit for downstream usage of name and description.
229
-        $_POST['templateName']        = ! empty($this->_req_data['custom_template_args']['MTP_name'])
230
-            ? $this->_req_data['custom_template_args']['MTP_name']
231
-            : '';
232
-        $_POST['templateDescription'] = ! empty($this->_req_data['custom_template_args']['MTP_description'])
233
-            ? $this->_req_data['custom_template_args']['MTP_description']
234
-            : '';
235
-
236
-
237
-        // set EE_Admin_Page object (see method details in EE_Admin_Hooks parent
238
-        $this->_set_page_object();
239
-
240
-        // is this a template switch if so EE_Admin_Page child needs this object
241
-        $this->_page_object->set_hook_object($this);
242
-
243
-        $this->_page_object->add_message_template(
244
-            $this->_req_data['messageType'],
245
-            $this->_req_data['messenger'],
246
-            $this->_req_data['group_ID']
247
-        );
248
-    }
249
-
250
-
251
-    public function create_new_admin_footer()
252
-    {
253
-        $this->edit_admin_footer();
254
-    }
255
-
256
-
257
-    /**
258
-     * This is the dynamic method for this class
259
-     * that will end up hooking into the 'admin_footer' hook on the 'edit_event' route in the events page.
260
-     *
261
-     * @return string
262
-     * @throws DomainException
263
-     */
264
-    public function edit_admin_footer()
265
-    {
266
-        EEH_Template::display_template(
267
-            EE_CORE_CAF_ADMIN_EXTEND . 'messages/templates/create_custom_template_form.template.php'
268
-        );
269
-    }
270
-
271
-
272
-    /**
273
-     * Callback for AHEE__Extend_Events_Admin_Page___duplicate_event__after hook used to ensure new events duplicate
274
-     * the assigned custom message templates.
275
-     *
276
-     * @param EE_Event $new_event
277
-     * @param EE_Event $original_event
278
-     * @throws EE_Error
279
-     */
280
-    public function duplicate_custom_message_settings(EE_Event $new_event, EE_Event $original_event)
281
-    {
282
-        $message_template_groups = $original_event->get_many_related('Message_Template_Group');
283
-        foreach ($message_template_groups as $message_template_group) {
284
-            $new_event->_add_relation_to($message_template_group, 'Message_Template_Group');
285
-        }
286
-        //save new event
287
-        $new_event->save();
288
-    }
203
+		if (defined('DOING_AJAX')) {
204
+			return $tabbed_content;
205
+		}
206
+
207
+		do_action('AHEE__espresso_events_Messages_Hooks_Extend__messages_metabox__before_content');
208
+		echo $notices . '<div class="messages-tabs-content">' . $tabbed_content . '</div>';
209
+		do_action('AHEE__espresso_events_Messages_Hooks_Extend__messages_metabox__after_content');
210
+	}
211
+
212
+
213
+	/**
214
+	 * Ajax callback for ee_msgs_create_new_custom ajax request.
215
+	 * Takes incoming GRP_ID and name and description values from ajax request
216
+	 * to create a new custom template based off of the incoming GRP_ID.
217
+	 *
218
+	 * @access public
219
+	 * @return string either an html string will be returned or a success message
220
+	 * @throws EE_Error
221
+	 */
222
+	public function create_new_custom()
223
+	{
224
+		if (! EE_Registry::instance()->CAP->current_user_can('ee_edit_messages', 'create_new_custom_ajax')) {
225
+			wp_die(__('You don\'t have privileges to do this action', 'event_espresso'));
226
+		}
227
+
228
+		//let's clean up the _POST global a bit for downstream usage of name and description.
229
+		$_POST['templateName']        = ! empty($this->_req_data['custom_template_args']['MTP_name'])
230
+			? $this->_req_data['custom_template_args']['MTP_name']
231
+			: '';
232
+		$_POST['templateDescription'] = ! empty($this->_req_data['custom_template_args']['MTP_description'])
233
+			? $this->_req_data['custom_template_args']['MTP_description']
234
+			: '';
235
+
236
+
237
+		// set EE_Admin_Page object (see method details in EE_Admin_Hooks parent
238
+		$this->_set_page_object();
239
+
240
+		// is this a template switch if so EE_Admin_Page child needs this object
241
+		$this->_page_object->set_hook_object($this);
242
+
243
+		$this->_page_object->add_message_template(
244
+			$this->_req_data['messageType'],
245
+			$this->_req_data['messenger'],
246
+			$this->_req_data['group_ID']
247
+		);
248
+	}
249
+
250
+
251
+	public function create_new_admin_footer()
252
+	{
253
+		$this->edit_admin_footer();
254
+	}
255
+
256
+
257
+	/**
258
+	 * This is the dynamic method for this class
259
+	 * that will end up hooking into the 'admin_footer' hook on the 'edit_event' route in the events page.
260
+	 *
261
+	 * @return string
262
+	 * @throws DomainException
263
+	 */
264
+	public function edit_admin_footer()
265
+	{
266
+		EEH_Template::display_template(
267
+			EE_CORE_CAF_ADMIN_EXTEND . 'messages/templates/create_custom_template_form.template.php'
268
+		);
269
+	}
270
+
271
+
272
+	/**
273
+	 * Callback for AHEE__Extend_Events_Admin_Page___duplicate_event__after hook used to ensure new events duplicate
274
+	 * the assigned custom message templates.
275
+	 *
276
+	 * @param EE_Event $new_event
277
+	 * @param EE_Event $original_event
278
+	 * @throws EE_Error
279
+	 */
280
+	public function duplicate_custom_message_settings(EE_Event $new_event, EE_Event $original_event)
281
+	{
282
+		$message_template_groups = $original_event->get_many_related('Message_Template_Group');
283
+		foreach ($message_template_groups as $message_template_group) {
284
+			$new_event->_add_relation_to($message_template_group, 'Message_Template_Group');
285
+		}
286
+		//save new event
287
+		$new_event->save();
288
+	}
289 289
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -24,7 +24,7 @@  discard block
 block discarded – undo
24 24
         /**
25 25
          * Add cap restriction ... metaboxes should not show if user does not have the ability to edit_custom_messages
26 26
          */
27
-        if (! EE_Registry::instance()->CAP->current_user_can(
27
+        if ( ! EE_Registry::instance()->CAP->current_user_can(
28 28
             'ee_edit_messages',
29 29
             'messages_events_editor_metabox'
30 30
         )) {
@@ -53,7 +53,7 @@  discard block
 block discarded – undo
53 53
      */
54 54
     protected function _extend_properties()
55 55
     {
56
-        define('EE_MSGS_EXTEND_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'messages/assets/');
56
+        define('EE_MSGS_EXTEND_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL.'messages/assets/');
57 57
         $this->_ajax_func = array(
58 58
             'ee_msgs_create_new_custom' => 'create_new_custom',
59 59
         );
@@ -70,11 +70,11 @@  discard block
 block discarded – undo
70 70
         $this->_scripts_styles = array(
71 71
             'registers' => array(
72 72
                 'events_msg_admin'     => array(
73
-                    'url'     => EE_MSGS_EXTEND_ASSETS_URL . 'events_messages_admin.js',
73
+                    'url'     => EE_MSGS_EXTEND_ASSETS_URL.'events_messages_admin.js',
74 74
                     'depends' => array('ee-dialog', 'ee-parse-uri', 'ee-serialize-full-array'),
75 75
                 ),
76 76
                 'events_msg_admin_css' => array(
77
-                    'url'  => EE_MSGS_EXTEND_ASSETS_URL . 'ee_msg_events_admin.css',
77
+                    'url'  => EE_MSGS_EXTEND_ASSETS_URL.'ee_msg_events_admin.css',
78 78
                     'type' => 'css',
79 79
                 ),
80 80
             ),
@@ -147,18 +147,18 @@  discard block
 block discarded – undo
147 147
                 array('action' => 'settings'),
148 148
                 EE_MSG_ADMIN_URL
149 149
             );
150
-            $error_msg        = sprintf(
150
+            $error_msg = sprintf(
151 151
                 esc_html__(
152 152
                     'There are no active messengers. So no notifications will go out for %1$sany%2$s events.  You will want to %3$sActivate a Messenger%4$s.',
153 153
                     'event_espresso'
154 154
                 ),
155 155
                 '<strong>',
156 156
                 '</strong>',
157
-                '<a href="' . $msg_activate_url . '">',
157
+                '<a href="'.$msg_activate_url.'">',
158 158
                 '</a>'
159 159
             );
160
-            $error_content    = '<div class="error"><p>' . $error_msg . '</p></div>';
161
-            $internal_content = '<div id="messages-error"><p>' . $error_msg . '</p></div>';
160
+            $error_content    = '<div class="error"><p>'.$error_msg.'</p></div>';
161
+            $internal_content = '<div id="messages-error"><p>'.$error_msg.'</p></div>';
162 162
 
163 163
             echo $error_content;
164 164
             echo $internal_content;
@@ -180,7 +180,7 @@  discard block
 block discarded – undo
180 180
                 array('event' => $event_id)
181 181
             );
182 182
 
183
-            if (! empty($tab_content)) {
183
+            if ( ! empty($tab_content)) {
184 184
                 $tabs[$name] = $tab_content;
185 185
             }
186 186
         }
@@ -205,7 +205,7 @@  discard block
 block discarded – undo
205 205
         }
206 206
 
207 207
         do_action('AHEE__espresso_events_Messages_Hooks_Extend__messages_metabox__before_content');
208
-        echo $notices . '<div class="messages-tabs-content">' . $tabbed_content . '</div>';
208
+        echo $notices.'<div class="messages-tabs-content">'.$tabbed_content.'</div>';
209 209
         do_action('AHEE__espresso_events_Messages_Hooks_Extend__messages_metabox__after_content');
210 210
     }
211 211
 
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
      */
222 222
     public function create_new_custom()
223 223
     {
224
-        if (! EE_Registry::instance()->CAP->current_user_can('ee_edit_messages', 'create_new_custom_ajax')) {
224
+        if ( ! EE_Registry::instance()->CAP->current_user_can('ee_edit_messages', 'create_new_custom_ajax')) {
225 225
             wp_die(__('You don\'t have privileges to do this action', 'event_espresso'));
226 226
         }
227 227
 
@@ -264,7 +264,7 @@  discard block
 block discarded – undo
264 264
     public function edit_admin_footer()
265 265
     {
266 266
         EEH_Template::display_template(
267
-            EE_CORE_CAF_ADMIN_EXTEND . 'messages/templates/create_custom_template_form.template.php'
267
+            EE_CORE_CAF_ADMIN_EXTEND.'messages/templates/create_custom_template_form.template.php'
268 268
         );
269 269
     }
270 270
 
Please login to merge, or discard this patch.
core/EE_Dependency_Map.core.php 2 patches
Indentation   +732 added lines, -732 removed lines patch added patch discarded remove patch
@@ -4,7 +4,7 @@  discard block
 block discarded – undo
4 4
 use EventEspresso\core\services\loaders\LoaderInterface;
5 5
 
6 6
 if (! defined('EVENT_ESPRESSO_VERSION')) {
7
-    exit('No direct script access allowed');
7
+	exit('No direct script access allowed');
8 8
 }
9 9
 
10 10
 
@@ -21,737 +21,737 @@  discard block
 block discarded – undo
21 21
 class EE_Dependency_Map
22 22
 {
23 23
 
24
-    /**
25
-     * This means that the requested class dependency is not present in the dependency map
26
-     */
27
-    const not_registered = 0;
28
-
29
-    /**
30
-     * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
31
-     */
32
-    const load_new_object = 1;
33
-
34
-    /**
35
-     * This instructs class loaders to return a previously instantiated and cached object for the requested class.
36
-     * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
37
-     */
38
-    const load_from_cache = 2;
39
-
40
-    /**
41
-     * When registering a dependency,
42
-     * this indicates to keep any existing dependencies that already exist,
43
-     * and simply discard any new dependencies declared in the incoming data
44
-     */
45
-    const KEEP_EXISTING_DEPENDENCIES = 0;
46
-
47
-    /**
48
-     * When registering a dependency,
49
-     * this indicates to overwrite any existing dependencies that already exist using the incoming data
50
-     */
51
-    const OVERWRITE_DEPENDENCIES = 1;
52
-
53
-
54
-
55
-    /**
56
-     * @type EE_Dependency_Map $_instance
57
-     */
58
-    protected static $_instance;
59
-
60
-    /**
61
-     * @type EE_Request $request
62
-     */
63
-    protected $_request;
64
-
65
-    /**
66
-     * @type EE_Response $response
67
-     */
68
-    protected $_response;
69
-
70
-    /**
71
-     * @type LoaderInterface $loader
72
-     */
73
-    protected $loader;
74
-
75
-    /**
76
-     * @type array $_dependency_map
77
-     */
78
-    protected $_dependency_map = array();
79
-
80
-    /**
81
-     * @type array $_class_loaders
82
-     */
83
-    protected $_class_loaders = array();
84
-
85
-    /**
86
-     * @type array $_aliases
87
-     */
88
-    protected $_aliases = array();
89
-
90
-
91
-
92
-    /**
93
-     * EE_Dependency_Map constructor.
94
-     *
95
-     * @param EE_Request  $request
96
-     * @param EE_Response $response
97
-     */
98
-    protected function __construct(EE_Request $request, EE_Response $response)
99
-    {
100
-        $this->_request = $request;
101
-        $this->_response = $response;
102
-        add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
103
-        do_action('EE_Dependency_Map____construct');
104
-    }
105
-
106
-
107
-
108
-    /**
109
-     * @throws InvalidDataTypeException
110
-     * @throws InvalidInterfaceException
111
-     * @throws InvalidArgumentException
112
-     */
113
-    public function initialize()
114
-    {
115
-        $this->_register_core_dependencies();
116
-        $this->_register_core_class_loaders();
117
-        $this->_register_core_aliases();
118
-    }
119
-
120
-
121
-
122
-    /**
123
-     * @singleton method used to instantiate class object
124
-     * @access    public
125
-     * @param EE_Request  $request
126
-     * @param EE_Response $response
127
-     * @return EE_Dependency_Map
128
-     */
129
-    public static function instance(EE_Request $request = null, EE_Response $response = null)
130
-    {
131
-        // check if class object is instantiated, and instantiated properly
132
-        if (! self::$_instance instanceof EE_Dependency_Map) {
133
-            self::$_instance = new EE_Dependency_Map($request, $response);
134
-        }
135
-        return self::$_instance;
136
-    }
137
-
138
-
139
-
140
-    /**
141
-     * @param LoaderInterface $loader
142
-     */
143
-    public function setLoader(LoaderInterface $loader)
144
-    {
145
-        $this->loader = $loader;
146
-    }
147
-
148
-
149
-
150
-    /**
151
-     * @param string $class
152
-     * @param array  $dependencies
153
-     * @param int    $overwrite
154
-     * @return bool
155
-     */
156
-    public static function register_dependencies(
157
-        $class,
158
-        array $dependencies,
159
-        $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
160
-    ) {
161
-        return self::$_instance->registerDependencies($class, $dependencies, $overwrite);
162
-    }
163
-
164
-
165
-
166
-    /**
167
-     * Assigns an array of class names and corresponding load sources (new or cached)
168
-     * to the class specified by the first parameter.
169
-     * IMPORTANT !!!
170
-     * The order of elements in the incoming $dependencies array MUST match
171
-     * the order of the constructor parameters for the class in question.
172
-     * This is especially important when overriding any existing dependencies that are registered.
173
-     * the third parameter controls whether any duplicate dependencies are overwritten or not.
174
-     *
175
-     * @param string $class
176
-     * @param array  $dependencies
177
-     * @param int    $overwrite
178
-     * @return bool
179
-     */
180
-    public function registerDependencies(
181
-        $class,
182
-        array $dependencies,
183
-        $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
184
-    ) {
185
-        $class = trim($class, '\\');
186
-        $registered = false;
187
-        if (empty(self::$_instance->_dependency_map[ $class ])) {
188
-            self::$_instance->_dependency_map[ $class ] = array();
189
-        }
190
-        // we need to make sure that any aliases used when registering a dependency
191
-        // get resolved to the correct class name
192
-        foreach ((array)$dependencies as $dependency => $load_source) {
193
-            $alias = self::$_instance->get_alias($dependency);
194
-            if (
195
-                $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
196
-                || ! isset(self::$_instance->_dependency_map[ $class ][ $alias ])
197
-            ) {
198
-                unset($dependencies[$dependency]);
199
-                $dependencies[$alias] = $load_source;
200
-                $registered = true;
201
-            }
202
-        }
203
-        // now add our two lists of dependencies together.
204
-        // using Union (+=) favours the arrays in precedence from left to right,
205
-        // so $dependencies is NOT overwritten because it is listed first
206
-        // ie: with A = B + C, entries in B take precedence over duplicate entries in C
207
-        // Union is way faster than array_merge() but should be used with caution...
208
-        // especially with numerically indexed arrays
209
-        $dependencies += self::$_instance->_dependency_map[ $class ];
210
-        // now we need to ensure that the resulting dependencies
211
-        // array only has the entries that are required for the class
212
-        // so first count how many dependencies were originally registered for the class
213
-        $dependency_count = count(self::$_instance->_dependency_map[ $class ]);
214
-        // if that count is non-zero (meaning dependencies were already registered)
215
-        self::$_instance->_dependency_map[ $class ] = $dependency_count
216
-            // then truncate the  final array to match that count
217
-            ? array_slice($dependencies, 0, $dependency_count)
218
-            // otherwise just take the incoming array because nothing previously existed
219
-            : $dependencies;
220
-        return $registered;
221
-    }
222
-
223
-
224
-
225
-    /**
226
-     * @param string $class_name
227
-     * @param string $loader
228
-     * @return bool
229
-     * @throws DomainException
230
-     */
231
-    public static function register_class_loader($class_name, $loader = 'load_core')
232
-    {
233
-        if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
234
-            throw new DomainException(
235
-                esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
236
-            );
237
-        }
238
-        // check that loader is callable or method starts with "load_" and exists in EE_Registry
239
-        if (
240
-            ! is_callable($loader)
241
-            && (
242
-                strpos($loader, 'load_') !== 0
243
-                || ! method_exists('EE_Registry', $loader)
244
-            )
245
-        ) {
246
-            throw new DomainException(
247
-                sprintf(
248
-                    esc_html__(
249
-                        '"%1$s" is not a valid loader method on EE_Registry.',
250
-                        'event_espresso'
251
-                    ),
252
-                    $loader
253
-                )
254
-            );
255
-        }
256
-        $class_name = self::$_instance->get_alias($class_name);
257
-        if (! isset(self::$_instance->_class_loaders[$class_name])) {
258
-            self::$_instance->_class_loaders[$class_name] = $loader;
259
-            return true;
260
-        }
261
-        return false;
262
-    }
263
-
264
-
265
-
266
-    /**
267
-     * @return array
268
-     */
269
-    public function dependency_map()
270
-    {
271
-        return $this->_dependency_map;
272
-    }
273
-
274
-
275
-
276
-    /**
277
-     * returns TRUE if dependency map contains a listing for the provided class name
278
-     *
279
-     * @param string $class_name
280
-     * @return boolean
281
-     */
282
-    public function has($class_name = '')
283
-    {
284
-        return isset($this->_dependency_map[$class_name]) ? true : false;
285
-    }
286
-
287
-
288
-
289
-    /**
290
-     * returns TRUE if dependency map contains a listing for the provided class name AND dependency
291
-     *
292
-     * @param string $class_name
293
-     * @param string $dependency
294
-     * @return bool
295
-     */
296
-    public function has_dependency_for_class($class_name = '', $dependency = '')
297
-    {
298
-        $dependency = $this->get_alias($dependency);
299
-        return isset($this->_dependency_map[$class_name], $this->_dependency_map[$class_name][$dependency])
300
-            ? true
301
-            : false;
302
-    }
303
-
304
-
305
-
306
-    /**
307
-     * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
308
-     *
309
-     * @param string $class_name
310
-     * @param string $dependency
311
-     * @return int
312
-     */
313
-    public function loading_strategy_for_class_dependency($class_name = '', $dependency = '')
314
-    {
315
-        $dependency = $this->get_alias($dependency);
316
-        return $this->has_dependency_for_class($class_name, $dependency)
317
-            ? $this->_dependency_map[$class_name][$dependency]
318
-            : EE_Dependency_Map::not_registered;
319
-    }
320
-
321
-
322
-
323
-    /**
324
-     * @param string $class_name
325
-     * @return string | Closure
326
-     */
327
-    public function class_loader($class_name)
328
-    {
329
-        $class_name = $this->get_alias($class_name);
330
-        return isset($this->_class_loaders[$class_name]) ? $this->_class_loaders[$class_name] : '';
331
-    }
332
-
333
-
334
-
335
-    /**
336
-     * @return array
337
-     */
338
-    public function class_loaders()
339
-    {
340
-        return $this->_class_loaders;
341
-    }
342
-
343
-
344
-
345
-    /**
346
-     * adds an alias for a classname
347
-     *
348
-     * @param string $class_name the class name that should be used (concrete class to replace interface)
349
-     * @param string $alias      the class name that would be type hinted for (abstract parent or interface)
350
-     * @param string $for_class  the class that has the dependency (is type hinting for the interface)
351
-     */
352
-    public function add_alias($class_name, $alias, $for_class = '')
353
-    {
354
-        if ($for_class !== '') {
355
-            if (! isset($this->_aliases[$for_class])) {
356
-                $this->_aliases[$for_class] = array();
357
-            }
358
-            $this->_aliases[$for_class][$class_name] = $alias;
359
-        }
360
-        $this->_aliases[$class_name] = $alias;
361
-    }
362
-
363
-
364
-
365
-    /**
366
-     * returns TRUE if the provided class name has an alias
367
-     *
368
-     * @param string $class_name
369
-     * @param string $for_class
370
-     * @return bool
371
-     */
372
-    public function has_alias($class_name = '', $for_class = '')
373
-    {
374
-        return isset($this->_aliases[$for_class], $this->_aliases[$for_class][$class_name])
375
-               || (
376
-                   isset($this->_aliases[$class_name])
377
-                   && ! is_array($this->_aliases[$class_name])
378
-               );
379
-    }
380
-
381
-
382
-
383
-    /**
384
-     * returns alias for class name if one exists, otherwise returns the original classname
385
-     * functions recursively, so that multiple aliases can be used to drill down to a classname
386
-     *  for example:
387
-     *      if the following two entries were added to the _aliases array:
388
-     *          array(
389
-     *              'interface_alias'           => 'some\namespace\interface'
390
-     *              'some\namespace\interface'  => 'some\namespace\classname'
391
-     *          )
392
-     *      then one could use EE_Registry::instance()->create( 'interface_alias' )
393
-     *      to load an instance of 'some\namespace\classname'
394
-     *
395
-     * @param string $class_name
396
-     * @param string $for_class
397
-     * @return string
398
-     */
399
-    public function get_alias($class_name = '', $for_class = '')
400
-    {
401
-        if (! $this->has_alias($class_name, $for_class)) {
402
-            return $class_name;
403
-        }
404
-        if ($for_class !== '' && isset($this->_aliases[ $for_class ][ $class_name ])) {
405
-            return $this->get_alias($this->_aliases[$for_class][$class_name], $for_class);
406
-        }
407
-        return $this->get_alias($this->_aliases[$class_name]);
408
-    }
409
-
410
-
411
-
412
-    /**
413
-     * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
414
-     * if one exists, or whether a new object should be generated every time the requested class is loaded.
415
-     * This is done by using the following class constants:
416
-     *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
417
-     *        EE_Dependency_Map::load_new_object - generates a new object every time
418
-     */
419
-    protected function _register_core_dependencies()
420
-    {
421
-        $this->_dependency_map = array(
422
-            'EE_Request_Handler'                                                                                          => array(
423
-                'EE_Request' => EE_Dependency_Map::load_from_cache,
424
-            ),
425
-            'EE_System'                                                                                                   => array(
426
-                'EE_Registry' => EE_Dependency_Map::load_from_cache,
427
-            ),
428
-            'EE_Session'                                                                                                  => array(
429
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
430
-                'EE_Encryption'                                           => EE_Dependency_Map::load_from_cache,
431
-            ),
432
-            'EE_Cart'                                                                                                     => array(
433
-                'EE_Session' => EE_Dependency_Map::load_from_cache,
434
-            ),
435
-            'EE_Front_Controller'                                                                                         => array(
436
-                'EE_Registry'              => EE_Dependency_Map::load_from_cache,
437
-                'EE_Request_Handler'       => EE_Dependency_Map::load_from_cache,
438
-                'EE_Module_Request_Router' => EE_Dependency_Map::load_from_cache,
439
-            ),
440
-            'EE_Messenger_Collection_Loader'                                                                              => array(
441
-                'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
442
-            ),
443
-            'EE_Message_Type_Collection_Loader'                                                                           => array(
444
-                'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
445
-            ),
446
-            'EE_Message_Resource_Manager'                                                                                 => array(
447
-                'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
448
-                'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
449
-                'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
450
-            ),
451
-            'EE_Message_Factory'                                                                                          => array(
452
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
453
-            ),
454
-            'EE_messages'                                                                                                 => array(
455
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
456
-            ),
457
-            'EE_Messages_Generator'                                                                                       => array(
458
-                'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
459
-                'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
460
-                'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
461
-                'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
462
-            ),
463
-            'EE_Messages_Processor'                                                                                       => array(
464
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
465
-            ),
466
-            'EE_Messages_Queue'                                                                                           => array(
467
-                'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
468
-            ),
469
-            'EE_Messages_Template_Defaults'                                                                               => array(
470
-                'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
471
-                'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
472
-            ),
473
-            'EE_Message_To_Generate_From_Request'                                                                         => array(
474
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
475
-                'EE_Request_Handler'          => EE_Dependency_Map::load_from_cache,
476
-            ),
477
-            'EventEspresso\core\services\commands\CommandBus'                                                             => array(
478
-                'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
479
-            ),
480
-            'EventEspresso\services\commands\CommandHandler'                                                              => array(
481
-                'EE_Registry'         => EE_Dependency_Map::load_from_cache,
482
-                'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
483
-            ),
484
-            'EventEspresso\core\services\commands\CommandHandlerManager'                                                  => array(
485
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
486
-            ),
487
-            'EventEspresso\core\services\commands\CompositeCommandHandler'                                                => array(
488
-                'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
489
-                'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
490
-            ),
491
-            'EventEspresso\core\services\commands\CommandFactory'                                                         => array(
492
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
493
-            ),
494
-            'EventEspresso\core\services\commands\middleware\CapChecker'                                                  => array(
495
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
496
-            ),
497
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                         => array(
498
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
499
-            ),
500
-            'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                     => array(
501
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
502
-            ),
503
-            'EventEspresso\core\services\commands\registration\CreateRegistrationCommandHandler'                          => array(
504
-                'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
505
-            ),
506
-            'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => array(
507
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
508
-            ),
509
-            'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => array(
510
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
511
-            ),
512
-            'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => array(
513
-                'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
514
-            ),
515
-            'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => array(
516
-                'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
517
-            ),
518
-            'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => array(
519
-                'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
520
-            ),
521
-            'EventEspresso\core\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => array(
522
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
523
-            ),
524
-            'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                   => array(
525
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
526
-            ),
527
-            'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler'                                  => array(
528
-                'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
529
-            ),
530
-            'EventEspresso\core\services\database\TableManager'                                                           => array(
531
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
532
-            ),
533
-            'EE_Data_Migration_Class_Base'                                                                                => array(
534
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
535
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
536
-            ),
537
-            'EE_DMS_Core_4_1_0'                                                                                           => array(
538
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
539
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
540
-            ),
541
-            'EE_DMS_Core_4_2_0'                                                                                           => array(
542
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
543
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
544
-            ),
545
-            'EE_DMS_Core_4_3_0'                                                                                           => array(
546
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
547
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
548
-            ),
549
-            'EE_DMS_Core_4_4_0'                                                                                           => array(
550
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
551
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
552
-            ),
553
-            'EE_DMS_Core_4_5_0'                                                                                           => array(
554
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
555
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
556
-            ),
557
-            'EE_DMS_Core_4_6_0'                                                                                           => array(
558
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
559
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
560
-            ),
561
-            'EE_DMS_Core_4_7_0'                                                                                           => array(
562
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
563
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
564
-            ),
565
-            'EE_DMS_Core_4_8_0'                                                                                           => array(
566
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
567
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
568
-            ),
569
-            'EE_DMS_Core_4_9_0'                                                                                           => array(
570
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
571
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
572
-            ),
573
-            'EventEspresso\core\services\assets\Registry'                                                                 => array(
574
-                'EE_Template_Config' => EE_Dependency_Map::load_from_cache,
575
-                'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
576
-            ),
577
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                             => array(
578
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
579
-            ),
580
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                              => array(
581
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
582
-            ),
583
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                        => array(
584
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
585
-            ),
586
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                => array(
587
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
588
-            ),
589
-            'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                              => array(
590
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
591
-            ),
592
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                        => array(
593
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
594
-            ),
595
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                               => array(
596
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
597
-            ),
598
-            'EventEspresso\core\services\cache\BasicCacheManager'                                                         => array(
599
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
600
-            ),
601
-            'EventEspresso\core\services\cache\PostRelatedCacheManager'                                                   => array(
602
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
603
-            ),
604
-        );
605
-    }
606
-
607
-
608
-
609
-    /**
610
-     * Registers how core classes are loaded.
611
-     * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
612
-     *        'EE_Request_Handler' => 'load_core'
613
-     *        'EE_Messages_Queue'  => 'load_lib'
614
-     *        'EEH_Debug_Tools'    => 'load_helper'
615
-     * or, if greater control is required, by providing a custom closure. For example:
616
-     *        'Some_Class' => function () {
617
-     *            return new Some_Class();
618
-     *        },
619
-     * This is required for instantiating dependencies
620
-     * where an interface has been type hinted in a class constructor. For example:
621
-     *        'Required_Interface' => function () {
622
-     *            return new A_Class_That_Implements_Required_Interface();
623
-     *        },
624
-     */
625
-    protected function _register_core_class_loaders()
626
-    {
627
-        //for PHP5.3 compat, we need to register any properties called here in a variable because `$this` cannot
628
-        //be used in a closure.
629
-        $request = &$this->_request;
630
-        $response = &$this->_response;
631
-        $loader = &$this->loader;
632
-        $this->_class_loaders = array(
633
-            //load_core
634
-            'EE_Capabilities'                      => 'load_core',
635
-            'EE_Encryption'                        => 'load_core',
636
-            'EE_Front_Controller'                  => 'load_core',
637
-            'EE_Module_Request_Router'             => 'load_core',
638
-            'EE_Registry'                          => 'load_core',
639
-            'EE_Request'                           => function () use (&$request) {
640
-                return $request;
641
-            },
642
-            'EE_Response'                          => function () use (&$response) {
643
-                return $response;
644
-            },
645
-            'EE_Request_Handler'                   => 'load_core',
646
-            'EE_Session'                           => 'load_core',
647
-            //load_lib
648
-            'EE_Message_Resource_Manager'          => 'load_lib',
649
-            'EE_Message_Type_Collection'           => 'load_lib',
650
-            'EE_Message_Type_Collection_Loader'    => 'load_lib',
651
-            'EE_Messenger_Collection'              => 'load_lib',
652
-            'EE_Messenger_Collection_Loader'       => 'load_lib',
653
-            'EE_Messages_Processor'                => 'load_lib',
654
-            'EE_Message_Repository'                => 'load_lib',
655
-            'EE_Messages_Queue'                    => 'load_lib',
656
-            'EE_Messages_Data_Handler_Collection'  => 'load_lib',
657
-            'EE_Message_Template_Group_Collection' => 'load_lib',
658
-            'EE_Messages_Generator'                => function () {
659
-                return EE_Registry::instance()->load_lib(
660
-                    'Messages_Generator',
661
-                    array(),
662
-                    false,
663
-                    false
664
-                );
665
-            },
666
-            'EE_Messages_Template_Defaults'        => function ($arguments = array()) {
667
-                return EE_Registry::instance()->load_lib(
668
-                    'Messages_Template_Defaults',
669
-                    $arguments,
670
-                    false,
671
-                    false
672
-                );
673
-            },
674
-            //load_model
675
-            'EEM_Attendee'                         => 'load_model',
676
-            'EEM_Message_Template_Group'           => 'load_model',
677
-            'EEM_Message_Template'                 => 'load_model',
678
-            //load_helper
679
-            'EEH_Parse_Shortcodes'                 => function () {
680
-                if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
681
-                    return new EEH_Parse_Shortcodes();
682
-                }
683
-                return null;
684
-            },
685
-            'EE_Template_Config'                   => function () {
686
-                return EE_Config::instance()->template_settings;
687
-            },
688
-            'EE_Currency_Config'                   => function () {
689
-                return EE_Config::instance()->currency;
690
-            },
691
-            'EventEspresso\core\services\loaders\Loader' => function () use (&$loader) {
692
-                return $loader;
693
-            },
694
-        );
695
-    }
696
-
697
-
698
-
699
-    /**
700
-     * can be used for supplying alternate names for classes,
701
-     * or for connecting interface names to instantiable classes
702
-     */
703
-    protected function _register_core_aliases()
704
-    {
705
-        $this->_aliases = array(
706
-            'CommandBusInterface'                                                 => 'EventEspresso\core\services\commands\CommandBusInterface',
707
-            'EventEspresso\core\services\commands\CommandBusInterface'            => 'EventEspresso\core\services\commands\CommandBus',
708
-            'CommandHandlerManagerInterface'                                      => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
709
-            'EventEspresso\core\services\commands\CommandHandlerManagerInterface' => 'EventEspresso\core\services\commands\CommandHandlerManager',
710
-            'CapChecker'                                                          => 'EventEspresso\core\services\commands\middleware\CapChecker',
711
-            'AddActionHook'                                                       => 'EventEspresso\core\services\commands\middleware\AddActionHook',
712
-            'CapabilitiesChecker'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
713
-            'CapabilitiesCheckerInterface'                                        => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
714
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
715
-            'CreateRegistrationService'                                           => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
716
-            'CreateRegCodeCommandHandler'                                         => 'EventEspresso\core\services\commands\registration\CreateRegCodeCommand',
717
-            'CreateRegUrlLinkCommandHandler'                                      => 'EventEspresso\core\services\commands\registration\CreateRegUrlLinkCommand',
718
-            'CreateRegistrationCommandHandler'                                    => 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
719
-            'CopyRegistrationDetailsCommandHandler'                               => 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommand',
720
-            'CopyRegistrationPaymentsCommandHandler'                              => 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommand',
721
-            'CancelRegistrationAndTicketLineItemCommandHandler'                   => 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
722
-            'UpdateRegistrationAndTransactionAfterChangeCommandHandler'           => 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
723
-            'CreateTicketLineItemCommandHandler'                                  => 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommand',
724
-            'TableManager'                                                        => 'EventEspresso\core\services\database\TableManager',
725
-            'TableAnalysis'                                                       => 'EventEspresso\core\services\database\TableAnalysis',
726
-            'CreateTransactionCommandHandler'                                     => 'EventEspresso\core\services\commands\transaction\CreateTransactionCommandHandler',
727
-            'CreateAttendeeCommandHandler'                                        => 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler',
728
-            'EspressoShortcode'                                                   => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
729
-            'ShortcodeInterface'                                                  => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
730
-            'EventEspresso\core\services\shortcodes\ShortcodeInterface'           => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
731
-            'EventEspresso\core\services\cache\CacheStorageInterface'             => 'EventEspresso\core\services\cache\TransientCacheStorage',
732
-            'LoaderInterface'                                                     => 'EventEspresso\core\services\loaders\LoaderInterface',
733
-            'EventEspresso\core\services\loaders\LoaderInterface'                 => 'EventEspresso\core\services\loaders\Loader',
734
-            'CommandFactoryInterface'                                             => 'EventEspresso\core\services\commands\CommandFactoryInterface',
735
-            'EventEspresso\core\services\commands\CommandFactoryInterface'        => 'EventEspresso\core\services\commands\CommandFactory',
736
-            'EventEspresso\core\domain\services\session\SessionIdentifierInterface' => 'EE_Session',
737
-            'NoticeConverterInterface'                                            => 'EventEspresso\core\services\notices\NoticeConverterInterface',
738
-            'EventEspresso\core\services\notices\NoticeConverterInterface'        => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
739
-            'NoticesContainerInterface'                                            => 'EventEspresso\core\services\notices\NoticesContainerInterface',
740
-            'EventEspresso\core\services\notices\NoticesContainerInterface'        => 'EventEspresso\core\services\notices\NoticesContainer',
741
-        );
742
-    }
743
-
744
-
745
-
746
-    /**
747
-     * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
748
-     * request Primarily used by unit tests.
749
-     */
750
-    public function reset()
751
-    {
752
-        $this->_register_core_class_loaders();
753
-        $this->_register_core_dependencies();
754
-    }
24
+	/**
25
+	 * This means that the requested class dependency is not present in the dependency map
26
+	 */
27
+	const not_registered = 0;
28
+
29
+	/**
30
+	 * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
31
+	 */
32
+	const load_new_object = 1;
33
+
34
+	/**
35
+	 * This instructs class loaders to return a previously instantiated and cached object for the requested class.
36
+	 * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
37
+	 */
38
+	const load_from_cache = 2;
39
+
40
+	/**
41
+	 * When registering a dependency,
42
+	 * this indicates to keep any existing dependencies that already exist,
43
+	 * and simply discard any new dependencies declared in the incoming data
44
+	 */
45
+	const KEEP_EXISTING_DEPENDENCIES = 0;
46
+
47
+	/**
48
+	 * When registering a dependency,
49
+	 * this indicates to overwrite any existing dependencies that already exist using the incoming data
50
+	 */
51
+	const OVERWRITE_DEPENDENCIES = 1;
52
+
53
+
54
+
55
+	/**
56
+	 * @type EE_Dependency_Map $_instance
57
+	 */
58
+	protected static $_instance;
59
+
60
+	/**
61
+	 * @type EE_Request $request
62
+	 */
63
+	protected $_request;
64
+
65
+	/**
66
+	 * @type EE_Response $response
67
+	 */
68
+	protected $_response;
69
+
70
+	/**
71
+	 * @type LoaderInterface $loader
72
+	 */
73
+	protected $loader;
74
+
75
+	/**
76
+	 * @type array $_dependency_map
77
+	 */
78
+	protected $_dependency_map = array();
79
+
80
+	/**
81
+	 * @type array $_class_loaders
82
+	 */
83
+	protected $_class_loaders = array();
84
+
85
+	/**
86
+	 * @type array $_aliases
87
+	 */
88
+	protected $_aliases = array();
89
+
90
+
91
+
92
+	/**
93
+	 * EE_Dependency_Map constructor.
94
+	 *
95
+	 * @param EE_Request  $request
96
+	 * @param EE_Response $response
97
+	 */
98
+	protected function __construct(EE_Request $request, EE_Response $response)
99
+	{
100
+		$this->_request = $request;
101
+		$this->_response = $response;
102
+		add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
103
+		do_action('EE_Dependency_Map____construct');
104
+	}
105
+
106
+
107
+
108
+	/**
109
+	 * @throws InvalidDataTypeException
110
+	 * @throws InvalidInterfaceException
111
+	 * @throws InvalidArgumentException
112
+	 */
113
+	public function initialize()
114
+	{
115
+		$this->_register_core_dependencies();
116
+		$this->_register_core_class_loaders();
117
+		$this->_register_core_aliases();
118
+	}
119
+
120
+
121
+
122
+	/**
123
+	 * @singleton method used to instantiate class object
124
+	 * @access    public
125
+	 * @param EE_Request  $request
126
+	 * @param EE_Response $response
127
+	 * @return EE_Dependency_Map
128
+	 */
129
+	public static function instance(EE_Request $request = null, EE_Response $response = null)
130
+	{
131
+		// check if class object is instantiated, and instantiated properly
132
+		if (! self::$_instance instanceof EE_Dependency_Map) {
133
+			self::$_instance = new EE_Dependency_Map($request, $response);
134
+		}
135
+		return self::$_instance;
136
+	}
137
+
138
+
139
+
140
+	/**
141
+	 * @param LoaderInterface $loader
142
+	 */
143
+	public function setLoader(LoaderInterface $loader)
144
+	{
145
+		$this->loader = $loader;
146
+	}
147
+
148
+
149
+
150
+	/**
151
+	 * @param string $class
152
+	 * @param array  $dependencies
153
+	 * @param int    $overwrite
154
+	 * @return bool
155
+	 */
156
+	public static function register_dependencies(
157
+		$class,
158
+		array $dependencies,
159
+		$overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
160
+	) {
161
+		return self::$_instance->registerDependencies($class, $dependencies, $overwrite);
162
+	}
163
+
164
+
165
+
166
+	/**
167
+	 * Assigns an array of class names and corresponding load sources (new or cached)
168
+	 * to the class specified by the first parameter.
169
+	 * IMPORTANT !!!
170
+	 * The order of elements in the incoming $dependencies array MUST match
171
+	 * the order of the constructor parameters for the class in question.
172
+	 * This is especially important when overriding any existing dependencies that are registered.
173
+	 * the third parameter controls whether any duplicate dependencies are overwritten or not.
174
+	 *
175
+	 * @param string $class
176
+	 * @param array  $dependencies
177
+	 * @param int    $overwrite
178
+	 * @return bool
179
+	 */
180
+	public function registerDependencies(
181
+		$class,
182
+		array $dependencies,
183
+		$overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
184
+	) {
185
+		$class = trim($class, '\\');
186
+		$registered = false;
187
+		if (empty(self::$_instance->_dependency_map[ $class ])) {
188
+			self::$_instance->_dependency_map[ $class ] = array();
189
+		}
190
+		// we need to make sure that any aliases used when registering a dependency
191
+		// get resolved to the correct class name
192
+		foreach ((array)$dependencies as $dependency => $load_source) {
193
+			$alias = self::$_instance->get_alias($dependency);
194
+			if (
195
+				$overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
196
+				|| ! isset(self::$_instance->_dependency_map[ $class ][ $alias ])
197
+			) {
198
+				unset($dependencies[$dependency]);
199
+				$dependencies[$alias] = $load_source;
200
+				$registered = true;
201
+			}
202
+		}
203
+		// now add our two lists of dependencies together.
204
+		// using Union (+=) favours the arrays in precedence from left to right,
205
+		// so $dependencies is NOT overwritten because it is listed first
206
+		// ie: with A = B + C, entries in B take precedence over duplicate entries in C
207
+		// Union is way faster than array_merge() but should be used with caution...
208
+		// especially with numerically indexed arrays
209
+		$dependencies += self::$_instance->_dependency_map[ $class ];
210
+		// now we need to ensure that the resulting dependencies
211
+		// array only has the entries that are required for the class
212
+		// so first count how many dependencies were originally registered for the class
213
+		$dependency_count = count(self::$_instance->_dependency_map[ $class ]);
214
+		// if that count is non-zero (meaning dependencies were already registered)
215
+		self::$_instance->_dependency_map[ $class ] = $dependency_count
216
+			// then truncate the  final array to match that count
217
+			? array_slice($dependencies, 0, $dependency_count)
218
+			// otherwise just take the incoming array because nothing previously existed
219
+			: $dependencies;
220
+		return $registered;
221
+	}
222
+
223
+
224
+
225
+	/**
226
+	 * @param string $class_name
227
+	 * @param string $loader
228
+	 * @return bool
229
+	 * @throws DomainException
230
+	 */
231
+	public static function register_class_loader($class_name, $loader = 'load_core')
232
+	{
233
+		if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
234
+			throw new DomainException(
235
+				esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
236
+			);
237
+		}
238
+		// check that loader is callable or method starts with "load_" and exists in EE_Registry
239
+		if (
240
+			! is_callable($loader)
241
+			&& (
242
+				strpos($loader, 'load_') !== 0
243
+				|| ! method_exists('EE_Registry', $loader)
244
+			)
245
+		) {
246
+			throw new DomainException(
247
+				sprintf(
248
+					esc_html__(
249
+						'"%1$s" is not a valid loader method on EE_Registry.',
250
+						'event_espresso'
251
+					),
252
+					$loader
253
+				)
254
+			);
255
+		}
256
+		$class_name = self::$_instance->get_alias($class_name);
257
+		if (! isset(self::$_instance->_class_loaders[$class_name])) {
258
+			self::$_instance->_class_loaders[$class_name] = $loader;
259
+			return true;
260
+		}
261
+		return false;
262
+	}
263
+
264
+
265
+
266
+	/**
267
+	 * @return array
268
+	 */
269
+	public function dependency_map()
270
+	{
271
+		return $this->_dependency_map;
272
+	}
273
+
274
+
275
+
276
+	/**
277
+	 * returns TRUE if dependency map contains a listing for the provided class name
278
+	 *
279
+	 * @param string $class_name
280
+	 * @return boolean
281
+	 */
282
+	public function has($class_name = '')
283
+	{
284
+		return isset($this->_dependency_map[$class_name]) ? true : false;
285
+	}
286
+
287
+
288
+
289
+	/**
290
+	 * returns TRUE if dependency map contains a listing for the provided class name AND dependency
291
+	 *
292
+	 * @param string $class_name
293
+	 * @param string $dependency
294
+	 * @return bool
295
+	 */
296
+	public function has_dependency_for_class($class_name = '', $dependency = '')
297
+	{
298
+		$dependency = $this->get_alias($dependency);
299
+		return isset($this->_dependency_map[$class_name], $this->_dependency_map[$class_name][$dependency])
300
+			? true
301
+			: false;
302
+	}
303
+
304
+
305
+
306
+	/**
307
+	 * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
308
+	 *
309
+	 * @param string $class_name
310
+	 * @param string $dependency
311
+	 * @return int
312
+	 */
313
+	public function loading_strategy_for_class_dependency($class_name = '', $dependency = '')
314
+	{
315
+		$dependency = $this->get_alias($dependency);
316
+		return $this->has_dependency_for_class($class_name, $dependency)
317
+			? $this->_dependency_map[$class_name][$dependency]
318
+			: EE_Dependency_Map::not_registered;
319
+	}
320
+
321
+
322
+
323
+	/**
324
+	 * @param string $class_name
325
+	 * @return string | Closure
326
+	 */
327
+	public function class_loader($class_name)
328
+	{
329
+		$class_name = $this->get_alias($class_name);
330
+		return isset($this->_class_loaders[$class_name]) ? $this->_class_loaders[$class_name] : '';
331
+	}
332
+
333
+
334
+
335
+	/**
336
+	 * @return array
337
+	 */
338
+	public function class_loaders()
339
+	{
340
+		return $this->_class_loaders;
341
+	}
342
+
343
+
344
+
345
+	/**
346
+	 * adds an alias for a classname
347
+	 *
348
+	 * @param string $class_name the class name that should be used (concrete class to replace interface)
349
+	 * @param string $alias      the class name that would be type hinted for (abstract parent or interface)
350
+	 * @param string $for_class  the class that has the dependency (is type hinting for the interface)
351
+	 */
352
+	public function add_alias($class_name, $alias, $for_class = '')
353
+	{
354
+		if ($for_class !== '') {
355
+			if (! isset($this->_aliases[$for_class])) {
356
+				$this->_aliases[$for_class] = array();
357
+			}
358
+			$this->_aliases[$for_class][$class_name] = $alias;
359
+		}
360
+		$this->_aliases[$class_name] = $alias;
361
+	}
362
+
363
+
364
+
365
+	/**
366
+	 * returns TRUE if the provided class name has an alias
367
+	 *
368
+	 * @param string $class_name
369
+	 * @param string $for_class
370
+	 * @return bool
371
+	 */
372
+	public function has_alias($class_name = '', $for_class = '')
373
+	{
374
+		return isset($this->_aliases[$for_class], $this->_aliases[$for_class][$class_name])
375
+			   || (
376
+				   isset($this->_aliases[$class_name])
377
+				   && ! is_array($this->_aliases[$class_name])
378
+			   );
379
+	}
380
+
381
+
382
+
383
+	/**
384
+	 * returns alias for class name if one exists, otherwise returns the original classname
385
+	 * functions recursively, so that multiple aliases can be used to drill down to a classname
386
+	 *  for example:
387
+	 *      if the following two entries were added to the _aliases array:
388
+	 *          array(
389
+	 *              'interface_alias'           => 'some\namespace\interface'
390
+	 *              'some\namespace\interface'  => 'some\namespace\classname'
391
+	 *          )
392
+	 *      then one could use EE_Registry::instance()->create( 'interface_alias' )
393
+	 *      to load an instance of 'some\namespace\classname'
394
+	 *
395
+	 * @param string $class_name
396
+	 * @param string $for_class
397
+	 * @return string
398
+	 */
399
+	public function get_alias($class_name = '', $for_class = '')
400
+	{
401
+		if (! $this->has_alias($class_name, $for_class)) {
402
+			return $class_name;
403
+		}
404
+		if ($for_class !== '' && isset($this->_aliases[ $for_class ][ $class_name ])) {
405
+			return $this->get_alias($this->_aliases[$for_class][$class_name], $for_class);
406
+		}
407
+		return $this->get_alias($this->_aliases[$class_name]);
408
+	}
409
+
410
+
411
+
412
+	/**
413
+	 * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
414
+	 * if one exists, or whether a new object should be generated every time the requested class is loaded.
415
+	 * This is done by using the following class constants:
416
+	 *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
417
+	 *        EE_Dependency_Map::load_new_object - generates a new object every time
418
+	 */
419
+	protected function _register_core_dependencies()
420
+	{
421
+		$this->_dependency_map = array(
422
+			'EE_Request_Handler'                                                                                          => array(
423
+				'EE_Request' => EE_Dependency_Map::load_from_cache,
424
+			),
425
+			'EE_System'                                                                                                   => array(
426
+				'EE_Registry' => EE_Dependency_Map::load_from_cache,
427
+			),
428
+			'EE_Session'                                                                                                  => array(
429
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
430
+				'EE_Encryption'                                           => EE_Dependency_Map::load_from_cache,
431
+			),
432
+			'EE_Cart'                                                                                                     => array(
433
+				'EE_Session' => EE_Dependency_Map::load_from_cache,
434
+			),
435
+			'EE_Front_Controller'                                                                                         => array(
436
+				'EE_Registry'              => EE_Dependency_Map::load_from_cache,
437
+				'EE_Request_Handler'       => EE_Dependency_Map::load_from_cache,
438
+				'EE_Module_Request_Router' => EE_Dependency_Map::load_from_cache,
439
+			),
440
+			'EE_Messenger_Collection_Loader'                                                                              => array(
441
+				'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
442
+			),
443
+			'EE_Message_Type_Collection_Loader'                                                                           => array(
444
+				'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
445
+			),
446
+			'EE_Message_Resource_Manager'                                                                                 => array(
447
+				'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
448
+				'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
449
+				'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
450
+			),
451
+			'EE_Message_Factory'                                                                                          => array(
452
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
453
+			),
454
+			'EE_messages'                                                                                                 => array(
455
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
456
+			),
457
+			'EE_Messages_Generator'                                                                                       => array(
458
+				'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
459
+				'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
460
+				'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
461
+				'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
462
+			),
463
+			'EE_Messages_Processor'                                                                                       => array(
464
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
465
+			),
466
+			'EE_Messages_Queue'                                                                                           => array(
467
+				'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
468
+			),
469
+			'EE_Messages_Template_Defaults'                                                                               => array(
470
+				'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
471
+				'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
472
+			),
473
+			'EE_Message_To_Generate_From_Request'                                                                         => array(
474
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
475
+				'EE_Request_Handler'          => EE_Dependency_Map::load_from_cache,
476
+			),
477
+			'EventEspresso\core\services\commands\CommandBus'                                                             => array(
478
+				'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
479
+			),
480
+			'EventEspresso\services\commands\CommandHandler'                                                              => array(
481
+				'EE_Registry'         => EE_Dependency_Map::load_from_cache,
482
+				'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
483
+			),
484
+			'EventEspresso\core\services\commands\CommandHandlerManager'                                                  => array(
485
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
486
+			),
487
+			'EventEspresso\core\services\commands\CompositeCommandHandler'                                                => array(
488
+				'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
489
+				'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
490
+			),
491
+			'EventEspresso\core\services\commands\CommandFactory'                                                         => array(
492
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
493
+			),
494
+			'EventEspresso\core\services\commands\middleware\CapChecker'                                                  => array(
495
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
496
+			),
497
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                         => array(
498
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
499
+			),
500
+			'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                     => array(
501
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
502
+			),
503
+			'EventEspresso\core\services\commands\registration\CreateRegistrationCommandHandler'                          => array(
504
+				'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
505
+			),
506
+			'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => array(
507
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
508
+			),
509
+			'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => array(
510
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
511
+			),
512
+			'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => array(
513
+				'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
514
+			),
515
+			'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => array(
516
+				'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
517
+			),
518
+			'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => array(
519
+				'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
520
+			),
521
+			'EventEspresso\core\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => array(
522
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
523
+			),
524
+			'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                   => array(
525
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
526
+			),
527
+			'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler'                                  => array(
528
+				'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
529
+			),
530
+			'EventEspresso\core\services\database\TableManager'                                                           => array(
531
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
532
+			),
533
+			'EE_Data_Migration_Class_Base'                                                                                => array(
534
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
535
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
536
+			),
537
+			'EE_DMS_Core_4_1_0'                                                                                           => array(
538
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
539
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
540
+			),
541
+			'EE_DMS_Core_4_2_0'                                                                                           => array(
542
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
543
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
544
+			),
545
+			'EE_DMS_Core_4_3_0'                                                                                           => array(
546
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
547
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
548
+			),
549
+			'EE_DMS_Core_4_4_0'                                                                                           => array(
550
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
551
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
552
+			),
553
+			'EE_DMS_Core_4_5_0'                                                                                           => array(
554
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
555
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
556
+			),
557
+			'EE_DMS_Core_4_6_0'                                                                                           => array(
558
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
559
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
560
+			),
561
+			'EE_DMS_Core_4_7_0'                                                                                           => array(
562
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
563
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
564
+			),
565
+			'EE_DMS_Core_4_8_0'                                                                                           => array(
566
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
567
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
568
+			),
569
+			'EE_DMS_Core_4_9_0'                                                                                           => array(
570
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
571
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
572
+			),
573
+			'EventEspresso\core\services\assets\Registry'                                                                 => array(
574
+				'EE_Template_Config' => EE_Dependency_Map::load_from_cache,
575
+				'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
576
+			),
577
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                             => array(
578
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
579
+			),
580
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                              => array(
581
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
582
+			),
583
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                        => array(
584
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
585
+			),
586
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                => array(
587
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
588
+			),
589
+			'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                              => array(
590
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
591
+			),
592
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                        => array(
593
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
594
+			),
595
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                               => array(
596
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
597
+			),
598
+			'EventEspresso\core\services\cache\BasicCacheManager'                                                         => array(
599
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
600
+			),
601
+			'EventEspresso\core\services\cache\PostRelatedCacheManager'                                                   => array(
602
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
603
+			),
604
+		);
605
+	}
606
+
607
+
608
+
609
+	/**
610
+	 * Registers how core classes are loaded.
611
+	 * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
612
+	 *        'EE_Request_Handler' => 'load_core'
613
+	 *        'EE_Messages_Queue'  => 'load_lib'
614
+	 *        'EEH_Debug_Tools'    => 'load_helper'
615
+	 * or, if greater control is required, by providing a custom closure. For example:
616
+	 *        'Some_Class' => function () {
617
+	 *            return new Some_Class();
618
+	 *        },
619
+	 * This is required for instantiating dependencies
620
+	 * where an interface has been type hinted in a class constructor. For example:
621
+	 *        'Required_Interface' => function () {
622
+	 *            return new A_Class_That_Implements_Required_Interface();
623
+	 *        },
624
+	 */
625
+	protected function _register_core_class_loaders()
626
+	{
627
+		//for PHP5.3 compat, we need to register any properties called here in a variable because `$this` cannot
628
+		//be used in a closure.
629
+		$request = &$this->_request;
630
+		$response = &$this->_response;
631
+		$loader = &$this->loader;
632
+		$this->_class_loaders = array(
633
+			//load_core
634
+			'EE_Capabilities'                      => 'load_core',
635
+			'EE_Encryption'                        => 'load_core',
636
+			'EE_Front_Controller'                  => 'load_core',
637
+			'EE_Module_Request_Router'             => 'load_core',
638
+			'EE_Registry'                          => 'load_core',
639
+			'EE_Request'                           => function () use (&$request) {
640
+				return $request;
641
+			},
642
+			'EE_Response'                          => function () use (&$response) {
643
+				return $response;
644
+			},
645
+			'EE_Request_Handler'                   => 'load_core',
646
+			'EE_Session'                           => 'load_core',
647
+			//load_lib
648
+			'EE_Message_Resource_Manager'          => 'load_lib',
649
+			'EE_Message_Type_Collection'           => 'load_lib',
650
+			'EE_Message_Type_Collection_Loader'    => 'load_lib',
651
+			'EE_Messenger_Collection'              => 'load_lib',
652
+			'EE_Messenger_Collection_Loader'       => 'load_lib',
653
+			'EE_Messages_Processor'                => 'load_lib',
654
+			'EE_Message_Repository'                => 'load_lib',
655
+			'EE_Messages_Queue'                    => 'load_lib',
656
+			'EE_Messages_Data_Handler_Collection'  => 'load_lib',
657
+			'EE_Message_Template_Group_Collection' => 'load_lib',
658
+			'EE_Messages_Generator'                => function () {
659
+				return EE_Registry::instance()->load_lib(
660
+					'Messages_Generator',
661
+					array(),
662
+					false,
663
+					false
664
+				);
665
+			},
666
+			'EE_Messages_Template_Defaults'        => function ($arguments = array()) {
667
+				return EE_Registry::instance()->load_lib(
668
+					'Messages_Template_Defaults',
669
+					$arguments,
670
+					false,
671
+					false
672
+				);
673
+			},
674
+			//load_model
675
+			'EEM_Attendee'                         => 'load_model',
676
+			'EEM_Message_Template_Group'           => 'load_model',
677
+			'EEM_Message_Template'                 => 'load_model',
678
+			//load_helper
679
+			'EEH_Parse_Shortcodes'                 => function () {
680
+				if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
681
+					return new EEH_Parse_Shortcodes();
682
+				}
683
+				return null;
684
+			},
685
+			'EE_Template_Config'                   => function () {
686
+				return EE_Config::instance()->template_settings;
687
+			},
688
+			'EE_Currency_Config'                   => function () {
689
+				return EE_Config::instance()->currency;
690
+			},
691
+			'EventEspresso\core\services\loaders\Loader' => function () use (&$loader) {
692
+				return $loader;
693
+			},
694
+		);
695
+	}
696
+
697
+
698
+
699
+	/**
700
+	 * can be used for supplying alternate names for classes,
701
+	 * or for connecting interface names to instantiable classes
702
+	 */
703
+	protected function _register_core_aliases()
704
+	{
705
+		$this->_aliases = array(
706
+			'CommandBusInterface'                                                 => 'EventEspresso\core\services\commands\CommandBusInterface',
707
+			'EventEspresso\core\services\commands\CommandBusInterface'            => 'EventEspresso\core\services\commands\CommandBus',
708
+			'CommandHandlerManagerInterface'                                      => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
709
+			'EventEspresso\core\services\commands\CommandHandlerManagerInterface' => 'EventEspresso\core\services\commands\CommandHandlerManager',
710
+			'CapChecker'                                                          => 'EventEspresso\core\services\commands\middleware\CapChecker',
711
+			'AddActionHook'                                                       => 'EventEspresso\core\services\commands\middleware\AddActionHook',
712
+			'CapabilitiesChecker'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
713
+			'CapabilitiesCheckerInterface'                                        => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
714
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
715
+			'CreateRegistrationService'                                           => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
716
+			'CreateRegCodeCommandHandler'                                         => 'EventEspresso\core\services\commands\registration\CreateRegCodeCommand',
717
+			'CreateRegUrlLinkCommandHandler'                                      => 'EventEspresso\core\services\commands\registration\CreateRegUrlLinkCommand',
718
+			'CreateRegistrationCommandHandler'                                    => 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
719
+			'CopyRegistrationDetailsCommandHandler'                               => 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommand',
720
+			'CopyRegistrationPaymentsCommandHandler'                              => 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommand',
721
+			'CancelRegistrationAndTicketLineItemCommandHandler'                   => 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
722
+			'UpdateRegistrationAndTransactionAfterChangeCommandHandler'           => 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
723
+			'CreateTicketLineItemCommandHandler'                                  => 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommand',
724
+			'TableManager'                                                        => 'EventEspresso\core\services\database\TableManager',
725
+			'TableAnalysis'                                                       => 'EventEspresso\core\services\database\TableAnalysis',
726
+			'CreateTransactionCommandHandler'                                     => 'EventEspresso\core\services\commands\transaction\CreateTransactionCommandHandler',
727
+			'CreateAttendeeCommandHandler'                                        => 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler',
728
+			'EspressoShortcode'                                                   => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
729
+			'ShortcodeInterface'                                                  => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
730
+			'EventEspresso\core\services\shortcodes\ShortcodeInterface'           => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
731
+			'EventEspresso\core\services\cache\CacheStorageInterface'             => 'EventEspresso\core\services\cache\TransientCacheStorage',
732
+			'LoaderInterface'                                                     => 'EventEspresso\core\services\loaders\LoaderInterface',
733
+			'EventEspresso\core\services\loaders\LoaderInterface'                 => 'EventEspresso\core\services\loaders\Loader',
734
+			'CommandFactoryInterface'                                             => 'EventEspresso\core\services\commands\CommandFactoryInterface',
735
+			'EventEspresso\core\services\commands\CommandFactoryInterface'        => 'EventEspresso\core\services\commands\CommandFactory',
736
+			'EventEspresso\core\domain\services\session\SessionIdentifierInterface' => 'EE_Session',
737
+			'NoticeConverterInterface'                                            => 'EventEspresso\core\services\notices\NoticeConverterInterface',
738
+			'EventEspresso\core\services\notices\NoticeConverterInterface'        => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
739
+			'NoticesContainerInterface'                                            => 'EventEspresso\core\services\notices\NoticesContainerInterface',
740
+			'EventEspresso\core\services\notices\NoticesContainerInterface'        => 'EventEspresso\core\services\notices\NoticesContainer',
741
+		);
742
+	}
743
+
744
+
745
+
746
+	/**
747
+	 * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
748
+	 * request Primarily used by unit tests.
749
+	 */
750
+	public function reset()
751
+	{
752
+		$this->_register_core_class_loaders();
753
+		$this->_register_core_dependencies();
754
+	}
755 755
 
756 756
 
757 757
 }
Please login to merge, or discard this patch.
Spacing   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -3,7 +3,7 @@  discard block
 block discarded – undo
3 3
 use EventEspresso\core\exceptions\InvalidInterfaceException;
4 4
 use EventEspresso\core\services\loaders\LoaderInterface;
5 5
 
6
-if (! defined('EVENT_ESPRESSO_VERSION')) {
6
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
7 7
     exit('No direct script access allowed');
8 8
 }
9 9
 
@@ -129,7 +129,7 @@  discard block
 block discarded – undo
129 129
     public static function instance(EE_Request $request = null, EE_Response $response = null)
130 130
     {
131 131
         // check if class object is instantiated, and instantiated properly
132
-        if (! self::$_instance instanceof EE_Dependency_Map) {
132
+        if ( ! self::$_instance instanceof EE_Dependency_Map) {
133 133
             self::$_instance = new EE_Dependency_Map($request, $response);
134 134
         }
135 135
         return self::$_instance;
@@ -184,16 +184,16 @@  discard block
 block discarded – undo
184 184
     ) {
185 185
         $class = trim($class, '\\');
186 186
         $registered = false;
187
-        if (empty(self::$_instance->_dependency_map[ $class ])) {
188
-            self::$_instance->_dependency_map[ $class ] = array();
187
+        if (empty(self::$_instance->_dependency_map[$class])) {
188
+            self::$_instance->_dependency_map[$class] = array();
189 189
         }
190 190
         // we need to make sure that any aliases used when registering a dependency
191 191
         // get resolved to the correct class name
192
-        foreach ((array)$dependencies as $dependency => $load_source) {
192
+        foreach ((array) $dependencies as $dependency => $load_source) {
193 193
             $alias = self::$_instance->get_alias($dependency);
194 194
             if (
195 195
                 $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
196
-                || ! isset(self::$_instance->_dependency_map[ $class ][ $alias ])
196
+                || ! isset(self::$_instance->_dependency_map[$class][$alias])
197 197
             ) {
198 198
                 unset($dependencies[$dependency]);
199 199
                 $dependencies[$alias] = $load_source;
@@ -206,13 +206,13 @@  discard block
 block discarded – undo
206 206
         // ie: with A = B + C, entries in B take precedence over duplicate entries in C
207 207
         // Union is way faster than array_merge() but should be used with caution...
208 208
         // especially with numerically indexed arrays
209
-        $dependencies += self::$_instance->_dependency_map[ $class ];
209
+        $dependencies += self::$_instance->_dependency_map[$class];
210 210
         // now we need to ensure that the resulting dependencies
211 211
         // array only has the entries that are required for the class
212 212
         // so first count how many dependencies were originally registered for the class
213
-        $dependency_count = count(self::$_instance->_dependency_map[ $class ]);
213
+        $dependency_count = count(self::$_instance->_dependency_map[$class]);
214 214
         // if that count is non-zero (meaning dependencies were already registered)
215
-        self::$_instance->_dependency_map[ $class ] = $dependency_count
215
+        self::$_instance->_dependency_map[$class] = $dependency_count
216 216
             // then truncate the  final array to match that count
217 217
             ? array_slice($dependencies, 0, $dependency_count)
218 218
             // otherwise just take the incoming array because nothing previously existed
@@ -230,7 +230,7 @@  discard block
 block discarded – undo
230 230
      */
231 231
     public static function register_class_loader($class_name, $loader = 'load_core')
232 232
     {
233
-        if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
233
+        if ( ! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
234 234
             throw new DomainException(
235 235
                 esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
236 236
             );
@@ -254,7 +254,7 @@  discard block
 block discarded – undo
254 254
             );
255 255
         }
256 256
         $class_name = self::$_instance->get_alias($class_name);
257
-        if (! isset(self::$_instance->_class_loaders[$class_name])) {
257
+        if ( ! isset(self::$_instance->_class_loaders[$class_name])) {
258 258
             self::$_instance->_class_loaders[$class_name] = $loader;
259 259
             return true;
260 260
         }
@@ -352,7 +352,7 @@  discard block
 block discarded – undo
352 352
     public function add_alias($class_name, $alias, $for_class = '')
353 353
     {
354 354
         if ($for_class !== '') {
355
-            if (! isset($this->_aliases[$for_class])) {
355
+            if ( ! isset($this->_aliases[$for_class])) {
356 356
                 $this->_aliases[$for_class] = array();
357 357
             }
358 358
             $this->_aliases[$for_class][$class_name] = $alias;
@@ -398,10 +398,10 @@  discard block
 block discarded – undo
398 398
      */
399 399
     public function get_alias($class_name = '', $for_class = '')
400 400
     {
401
-        if (! $this->has_alias($class_name, $for_class)) {
401
+        if ( ! $this->has_alias($class_name, $for_class)) {
402 402
             return $class_name;
403 403
         }
404
-        if ($for_class !== '' && isset($this->_aliases[ $for_class ][ $class_name ])) {
404
+        if ($for_class !== '' && isset($this->_aliases[$for_class][$class_name])) {
405 405
             return $this->get_alias($this->_aliases[$for_class][$class_name], $for_class);
406 406
         }
407 407
         return $this->get_alias($this->_aliases[$class_name]);
@@ -636,10 +636,10 @@  discard block
 block discarded – undo
636 636
             'EE_Front_Controller'                  => 'load_core',
637 637
             'EE_Module_Request_Router'             => 'load_core',
638 638
             'EE_Registry'                          => 'load_core',
639
-            'EE_Request'                           => function () use (&$request) {
639
+            'EE_Request'                           => function() use (&$request) {
640 640
                 return $request;
641 641
             },
642
-            'EE_Response'                          => function () use (&$response) {
642
+            'EE_Response'                          => function() use (&$response) {
643 643
                 return $response;
644 644
             },
645 645
             'EE_Request_Handler'                   => 'load_core',
@@ -655,7 +655,7 @@  discard block
 block discarded – undo
655 655
             'EE_Messages_Queue'                    => 'load_lib',
656 656
             'EE_Messages_Data_Handler_Collection'  => 'load_lib',
657 657
             'EE_Message_Template_Group_Collection' => 'load_lib',
658
-            'EE_Messages_Generator'                => function () {
658
+            'EE_Messages_Generator'                => function() {
659 659
                 return EE_Registry::instance()->load_lib(
660 660
                     'Messages_Generator',
661 661
                     array(),
@@ -663,7 +663,7 @@  discard block
 block discarded – undo
663 663
                     false
664 664
                 );
665 665
             },
666
-            'EE_Messages_Template_Defaults'        => function ($arguments = array()) {
666
+            'EE_Messages_Template_Defaults'        => function($arguments = array()) {
667 667
                 return EE_Registry::instance()->load_lib(
668 668
                     'Messages_Template_Defaults',
669 669
                     $arguments,
@@ -676,19 +676,19 @@  discard block
 block discarded – undo
676 676
             'EEM_Message_Template_Group'           => 'load_model',
677 677
             'EEM_Message_Template'                 => 'load_model',
678 678
             //load_helper
679
-            'EEH_Parse_Shortcodes'                 => function () {
679
+            'EEH_Parse_Shortcodes'                 => function() {
680 680
                 if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
681 681
                     return new EEH_Parse_Shortcodes();
682 682
                 }
683 683
                 return null;
684 684
             },
685
-            'EE_Template_Config'                   => function () {
685
+            'EE_Template_Config'                   => function() {
686 686
                 return EE_Config::instance()->template_settings;
687 687
             },
688
-            'EE_Currency_Config'                   => function () {
688
+            'EE_Currency_Config'                   => function() {
689 689
                 return EE_Config::instance()->currency;
690 690
             },
691
-            'EventEspresso\core\services\loaders\Loader' => function () use (&$loader) {
691
+            'EventEspresso\core\services\loaders\Loader' => function() use (&$loader) {
692 692
                 return $loader;
693 693
             },
694 694
         );
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_CPT.core.php 2 patches
Indentation   +1417 added lines, -1417 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {
2
-    exit('No direct script access allowed');
2
+	exit('No direct script access allowed');
3 3
 }
4 4
 
5 5
 /**
@@ -24,470 +24,470 @@  discard block
 block discarded – undo
24 24
 {
25 25
 
26 26
 
27
-    /**
28
-     * This gets set in _setup_cpt
29
-     * It will contain the object for the custom post type.
30
-     *
31
-     * @var EE_CPT_Base
32
-     */
33
-    protected $_cpt_object;
34
-
35
-
36
-
37
-    /**
38
-     * a boolean flag to set whether the current route is a cpt route or not.
39
-     *
40
-     * @var bool
41
-     */
42
-    protected $_cpt_route = false;
43
-
44
-
45
-
46
-    /**
47
-     * This property allows cpt classes to define multiple routes as cpt routes.
48
-     * //in this array we define what the custom post type for this route is.
49
-     * array(
50
-     * 'route_name' => 'custom_post_type_slug'
51
-     * )
52
-     *
53
-     * @var array
54
-     */
55
-    protected $_cpt_routes = array();
56
-
27
+	/**
28
+	 * This gets set in _setup_cpt
29
+	 * It will contain the object for the custom post type.
30
+	 *
31
+	 * @var EE_CPT_Base
32
+	 */
33
+	protected $_cpt_object;
34
+
35
+
36
+
37
+	/**
38
+	 * a boolean flag to set whether the current route is a cpt route or not.
39
+	 *
40
+	 * @var bool
41
+	 */
42
+	protected $_cpt_route = false;
43
+
44
+
45
+
46
+	/**
47
+	 * This property allows cpt classes to define multiple routes as cpt routes.
48
+	 * //in this array we define what the custom post type for this route is.
49
+	 * array(
50
+	 * 'route_name' => 'custom_post_type_slug'
51
+	 * )
52
+	 *
53
+	 * @var array
54
+	 */
55
+	protected $_cpt_routes = array();
56
+
57 57
 
58 58
 
59
-    /**
60
-     * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
61
-     * in this format:
62
-     * array(
63
-     * 'post_type_slug' => 'edit_route'
64
-     * )
65
-     *
66
-     * @var array
67
-     */
68
-    protected $_cpt_edit_routes = array();
69
-
70
-
71
-
72
-    /**
73
-     * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will
74
-     * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the
75
-     * _cpt_model_names property should be in the following format: array(
76
-     * 'route_defined_by_action_param' => 'Model_Name')
77
-     *
78
-     * @var array $_cpt_model_names
79
-     */
80
-    protected $_cpt_model_names = array();
81
-
82
-
83
-    /**
84
-     * @var EE_CPT_Base
85
-     */
86
-    protected $_cpt_model_obj = false;
87
-
88
-
89
-
90
-    /**
91
-     * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
92
-     * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
93
-     * the _register_autosave_containers() method so that we don't override any other containers already registered.
94
-     * Registration of containers should be done before load_page_dependencies() is run.
95
-     *
96
-     * @var array()
97
-     */
98
-    protected $_autosave_containers = array();
99
-    protected $_autosave_fields = array();
100
-
101
-    /**
102
-     * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
103
-     * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
104
-     *
105
-     * @var array
106
-     */
107
-    protected $_pagenow_map;
108
-
109
-
110
-
111
-    /**
112
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
113
-     * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
114
-     * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
115
-     * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
116
-     * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
117
-     *
118
-     * @access protected
119
-     * @abstract
120
-     * @param  string $post_id The ID of the cpt that was saved (so you can link relationally)
121
-     * @param  EE_CPT_Base $post    The post object of the cpt that was saved.
122
-     * @return void
123
-     */
124
-    abstract protected function _insert_update_cpt_item($post_id, $post);
125
-
126
-
127
-
128
-    /**
129
-     * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed.
130
-     *
131
-     * @abstract
132
-     * @access public
133
-     * @param  string $post_id The ID of the cpt that was trashed
134
-     * @return void
135
-     */
136
-    abstract public function trash_cpt_item($post_id);
137
-
138
-
139
-
140
-    /**
141
-     * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
142
-     *
143
-     * @param  string $post_id theID of the cpt that was untrashed
144
-     * @return void
145
-     */
146
-    abstract public function restore_cpt_item($post_id);
147
-
148
-
149
-
150
-    /**
151
-     * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
152
-     * from the db
153
-     *
154
-     * @param  string $post_id the ID of the cpt that was deleted
155
-     * @return void
156
-     */
157
-    abstract public function delete_cpt_item($post_id);
158
-
159
-
160
-
161
-    /**
162
-     * Just utilizing the method EE_Admin exposes for doing things before page setup.
163
-     *
164
-     * @access protected
165
-     * @return void
166
-     */
167
-    protected function _before_page_setup()
168
-    {
169
-        $page = isset($this->_req_data['page']) ? $this->_req_data['page'] : $this->page_slug;
170
-        $this->_cpt_routes = array_merge(array(
171
-            'create_new' => $this->page_slug,
172
-            'edit'       => $this->page_slug,
173
-            'trash'      => $this->page_slug,
174
-        ), $this->_cpt_routes);
175
-        //let's see if the current route has a value for cpt_object_slug if it does we use that instead of the page
176
-        $this->_cpt_object = isset($this->_req_data['action']) && isset($this->_cpt_routes[$this->_req_data['action']])
177
-            ? get_post_type_object($this->_cpt_routes[$this->_req_data['action']])
178
-            : get_post_type_object($page);
179
-        //tweak pagenow for page loading.
180
-        if ( ! $this->_pagenow_map) {
181
-            $this->_pagenow_map = array(
182
-                'create_new' => 'post-new.php',
183
-                'edit'       => 'post.php',
184
-                'trash'      => 'post.php',
185
-            );
186
-        }
187
-        add_action('current_screen', array($this, 'modify_pagenow'));
188
-        //TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
189
-        //get current page from autosave
190
-        $current_page = isset($this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page'])
191
-            ? $this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page']
192
-            : null;
193
-        $this->_current_page = isset($this->_req_data['current_page'])
194
-            ? $this->_req_data['current_page']
195
-            : $current_page;
196
-        //autosave... make sure its only for the correct page
197
-        //if ( ! empty($this->_current_page) && $this->_current_page == $this->page_slug) {
198
-            //setup autosave ajax hook
199
-            //add_action('wp_ajax_ee-autosave', array( $this, 'do_extra_autosave_stuff' ), 10 ); //TODO reactivate when 4.2 autosave is implemented
200
-        //}
201
-    }
202
-
203
-
204
-
205
-    /**
206
-     * Simply ensure that we simulate the correct post route for cpt screens
207
-     *
208
-     * @param WP_Screen $current_screen
209
-     * @return void
210
-     */
211
-    public function modify_pagenow($current_screen)
212
-    {
213
-        global $pagenow, $hook_suffix;
214
-        //possibly reset pagenow.
215
-        if ( ! empty($this->_req_data['page'])
216
-             && $this->_req_data['page'] == $this->page_slug
217
-             && ! empty($this->_req_data['action'])
218
-             && isset($this->_pagenow_map[$this->_req_data['action']])
219
-        ) {
220
-            $pagenow = $this->_pagenow_map[$this->_req_data['action']];
221
-            $hook_suffix = $pagenow;
222
-        }
223
-    }
224
-
225
-
226
-
227
-    /**
228
-     * This method is used to register additional autosave containers to the _autosave_containers property.
229
-     *
230
-     * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
231
-     *       automatically register the id for the post metabox as a container.
232
-     * @param  array $ids an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
233
-     *                    you would send along the id of a metabox container.
234
-     * @return void
235
-     */
236
-    protected function _register_autosave_containers($ids)
237
-    {
238
-        $this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids);
239
-    }
240
-
241
-
242
-
243
-    /**
244
-     * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
245
-     * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
246
-     */
247
-    protected function _set_autosave_containers()
248
-    {
249
-        global $wp_meta_boxes;
250
-        $containers = array();
251
-        if (empty($wp_meta_boxes)) {
252
-            return;
253
-        }
254
-        $current_metaboxes = isset($wp_meta_boxes[$this->page_slug]) ? $wp_meta_boxes[$this->page_slug] : array();
255
-        foreach ($current_metaboxes as $box_context) {
256
-            foreach ($box_context as $box_details) {
257
-                foreach ($box_details as $box) {
258
-                    if (
259
-                        is_array($box['callback'])
260
-                        && (
261
-                            $box['callback'][0] instanceof EE_Admin_Page
262
-                            || $box['callback'][0] instanceof EE_Admin_Hooks
263
-                        )
264
-                    ) {
265
-                        $containers[] = $box['id'];
266
-                    }
267
-                }
268
-            }
269
-        }
270
-        $this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
271
-        //add hidden inputs container
272
-        $this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
273
-    }
274
-
275
-
276
-
277
-    protected function _load_autosave_scripts_styles()
278
-    {
279
-        /*wp_register_script('cpt-autosave', EE_ADMIN_URL . 'assets/ee-cpt-autosave.js', array('ee-serialize-full-array', 'event_editor_js'), EVENT_ESPRESSO_VERSION, TRUE );
59
+	/**
60
+	 * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
61
+	 * in this format:
62
+	 * array(
63
+	 * 'post_type_slug' => 'edit_route'
64
+	 * )
65
+	 *
66
+	 * @var array
67
+	 */
68
+	protected $_cpt_edit_routes = array();
69
+
70
+
71
+
72
+	/**
73
+	 * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will
74
+	 * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the
75
+	 * _cpt_model_names property should be in the following format: array(
76
+	 * 'route_defined_by_action_param' => 'Model_Name')
77
+	 *
78
+	 * @var array $_cpt_model_names
79
+	 */
80
+	protected $_cpt_model_names = array();
81
+
82
+
83
+	/**
84
+	 * @var EE_CPT_Base
85
+	 */
86
+	protected $_cpt_model_obj = false;
87
+
88
+
89
+
90
+	/**
91
+	 * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
92
+	 * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
93
+	 * the _register_autosave_containers() method so that we don't override any other containers already registered.
94
+	 * Registration of containers should be done before load_page_dependencies() is run.
95
+	 *
96
+	 * @var array()
97
+	 */
98
+	protected $_autosave_containers = array();
99
+	protected $_autosave_fields = array();
100
+
101
+	/**
102
+	 * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
103
+	 * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
104
+	 *
105
+	 * @var array
106
+	 */
107
+	protected $_pagenow_map;
108
+
109
+
110
+
111
+	/**
112
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
113
+	 * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
114
+	 * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
115
+	 * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
116
+	 * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
117
+	 *
118
+	 * @access protected
119
+	 * @abstract
120
+	 * @param  string $post_id The ID of the cpt that was saved (so you can link relationally)
121
+	 * @param  EE_CPT_Base $post    The post object of the cpt that was saved.
122
+	 * @return void
123
+	 */
124
+	abstract protected function _insert_update_cpt_item($post_id, $post);
125
+
126
+
127
+
128
+	/**
129
+	 * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed.
130
+	 *
131
+	 * @abstract
132
+	 * @access public
133
+	 * @param  string $post_id The ID of the cpt that was trashed
134
+	 * @return void
135
+	 */
136
+	abstract public function trash_cpt_item($post_id);
137
+
138
+
139
+
140
+	/**
141
+	 * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
142
+	 *
143
+	 * @param  string $post_id theID of the cpt that was untrashed
144
+	 * @return void
145
+	 */
146
+	abstract public function restore_cpt_item($post_id);
147
+
148
+
149
+
150
+	/**
151
+	 * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
152
+	 * from the db
153
+	 *
154
+	 * @param  string $post_id the ID of the cpt that was deleted
155
+	 * @return void
156
+	 */
157
+	abstract public function delete_cpt_item($post_id);
158
+
159
+
160
+
161
+	/**
162
+	 * Just utilizing the method EE_Admin exposes for doing things before page setup.
163
+	 *
164
+	 * @access protected
165
+	 * @return void
166
+	 */
167
+	protected function _before_page_setup()
168
+	{
169
+		$page = isset($this->_req_data['page']) ? $this->_req_data['page'] : $this->page_slug;
170
+		$this->_cpt_routes = array_merge(array(
171
+			'create_new' => $this->page_slug,
172
+			'edit'       => $this->page_slug,
173
+			'trash'      => $this->page_slug,
174
+		), $this->_cpt_routes);
175
+		//let's see if the current route has a value for cpt_object_slug if it does we use that instead of the page
176
+		$this->_cpt_object = isset($this->_req_data['action']) && isset($this->_cpt_routes[$this->_req_data['action']])
177
+			? get_post_type_object($this->_cpt_routes[$this->_req_data['action']])
178
+			: get_post_type_object($page);
179
+		//tweak pagenow for page loading.
180
+		if ( ! $this->_pagenow_map) {
181
+			$this->_pagenow_map = array(
182
+				'create_new' => 'post-new.php',
183
+				'edit'       => 'post.php',
184
+				'trash'      => 'post.php',
185
+			);
186
+		}
187
+		add_action('current_screen', array($this, 'modify_pagenow'));
188
+		//TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
189
+		//get current page from autosave
190
+		$current_page = isset($this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page'])
191
+			? $this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page']
192
+			: null;
193
+		$this->_current_page = isset($this->_req_data['current_page'])
194
+			? $this->_req_data['current_page']
195
+			: $current_page;
196
+		//autosave... make sure its only for the correct page
197
+		//if ( ! empty($this->_current_page) && $this->_current_page == $this->page_slug) {
198
+			//setup autosave ajax hook
199
+			//add_action('wp_ajax_ee-autosave', array( $this, 'do_extra_autosave_stuff' ), 10 ); //TODO reactivate when 4.2 autosave is implemented
200
+		//}
201
+	}
202
+
203
+
204
+
205
+	/**
206
+	 * Simply ensure that we simulate the correct post route for cpt screens
207
+	 *
208
+	 * @param WP_Screen $current_screen
209
+	 * @return void
210
+	 */
211
+	public function modify_pagenow($current_screen)
212
+	{
213
+		global $pagenow, $hook_suffix;
214
+		//possibly reset pagenow.
215
+		if ( ! empty($this->_req_data['page'])
216
+			 && $this->_req_data['page'] == $this->page_slug
217
+			 && ! empty($this->_req_data['action'])
218
+			 && isset($this->_pagenow_map[$this->_req_data['action']])
219
+		) {
220
+			$pagenow = $this->_pagenow_map[$this->_req_data['action']];
221
+			$hook_suffix = $pagenow;
222
+		}
223
+	}
224
+
225
+
226
+
227
+	/**
228
+	 * This method is used to register additional autosave containers to the _autosave_containers property.
229
+	 *
230
+	 * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
231
+	 *       automatically register the id for the post metabox as a container.
232
+	 * @param  array $ids an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
233
+	 *                    you would send along the id of a metabox container.
234
+	 * @return void
235
+	 */
236
+	protected function _register_autosave_containers($ids)
237
+	{
238
+		$this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids);
239
+	}
240
+
241
+
242
+
243
+	/**
244
+	 * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
245
+	 * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
246
+	 */
247
+	protected function _set_autosave_containers()
248
+	{
249
+		global $wp_meta_boxes;
250
+		$containers = array();
251
+		if (empty($wp_meta_boxes)) {
252
+			return;
253
+		}
254
+		$current_metaboxes = isset($wp_meta_boxes[$this->page_slug]) ? $wp_meta_boxes[$this->page_slug] : array();
255
+		foreach ($current_metaboxes as $box_context) {
256
+			foreach ($box_context as $box_details) {
257
+				foreach ($box_details as $box) {
258
+					if (
259
+						is_array($box['callback'])
260
+						&& (
261
+							$box['callback'][0] instanceof EE_Admin_Page
262
+							|| $box['callback'][0] instanceof EE_Admin_Hooks
263
+						)
264
+					) {
265
+						$containers[] = $box['id'];
266
+					}
267
+				}
268
+			}
269
+		}
270
+		$this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
271
+		//add hidden inputs container
272
+		$this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
273
+	}
274
+
275
+
276
+
277
+	protected function _load_autosave_scripts_styles()
278
+	{
279
+		/*wp_register_script('cpt-autosave', EE_ADMIN_URL . 'assets/ee-cpt-autosave.js', array('ee-serialize-full-array', 'event_editor_js'), EVENT_ESPRESSO_VERSION, TRUE );
280 280
         wp_enqueue_script('cpt-autosave');/**/ //todo re-enable when we start doing autosave again in 4.2
281 281
 
282
-        //filter _autosave_containers
283
-        $containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
284
-            $this->_autosave_containers, $this);
285
-        $containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
286
-            $containers, $this);
287
-
288
-        wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS',
289
-            $containers); //todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
290
-
291
-        $unsaved_data_msg = array(
292
-            'eventmsg'     => sprintf(__("The changes you made to this %s will be lost if you navigate away from this page.",
293
-                'event_espresso'), $this->_cpt_object->labels->singular_name),
294
-            'inputChanged' => 0,
295
-        );
296
-        wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
297
-    }
298
-
299
-
300
-
301
-    public function load_page_dependencies()
302
-    {
303
-        try {
304
-            $this->_load_page_dependencies();
305
-        } catch (EE_Error $e) {
306
-            $e->get_error();
307
-        }
308
-    }
309
-
310
-
311
-
312
-    /**
313
-     * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
314
-     *
315
-     * @access protected
316
-     * @return void
317
-     */
318
-    protected function _load_page_dependencies()
319
-    {
320
-        //we only add stuff if this is a cpt_route!
321
-        if ( ! $this->_cpt_route) {
322
-            parent::_load_page_dependencies();
323
-            return;
324
-        }
325
-        // now let's do some automatic filters into the wp_system
326
-        // and we'll check to make sure the CHILD class
327
-        // automatically has the required methods in place.
328
-        // the following filters are for setting all the redirects
329
-        // on DEFAULT WP custom post type actions
330
-        // let's add a hidden input to the post-edit form
331
-        // so we know when we have to trigger our custom redirects!
332
-        // Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
333
-        add_action('edit_form_after_title', array($this, 'cpt_post_form_hidden_input'));
334
-        // inject our Admin page nav tabs...
335
-        // let's make sure the nav tabs are set if they aren't already
336
-        // if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
337
-        add_action('post_edit_form_tag', array($this, 'inject_nav_tabs'));
338
-        // modify the post_updated messages array
339
-        add_action('post_updated_messages', array($this, 'post_update_messages'), 10);
340
-        // add shortlink button to cpt edit screens.  We can do this as a universal thing BECAUSE,
341
-        // cpts use the same format for shortlinks as posts!
342
-        add_filter('pre_get_shortlink', array($this, 'add_shortlink_button_to_editor'), 10, 4);
343
-        // This basically allows us to change the title of the "publish" metabox area
344
-        // on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
345
-        if ( ! empty($this->_labels['publishbox'])) {
346
-            $box_label = is_array($this->_labels['publishbox'])
347
-                         && isset($this->_labels['publishbox'][$this->_req_action])
348
-                    ? $this->_labels['publishbox'][$this->_req_action]
349
-                    : $this->_labels['publishbox'];
350
-            add_meta_box(
351
-                'submitdiv',
352
-                $box_label,
353
-                'post_submit_meta_box',
354
-                $this->_cpt_routes[$this->_req_action],
355
-                'side',
356
-                'core'
357
-            );
358
-        }
359
-        //let's add page_templates metabox if this cpt added support for it.
360
-        if ($this->_supports_page_templates($this->_cpt_object->name)) {
361
-            add_meta_box(
362
-                'page_templates',
363
-                __('Page Template', 'event_espresso'),
364
-                array($this, 'page_template_meta_box'),
365
-                $this->_cpt_routes[$this->_req_action],
366
-                'side',
367
-                'default'
368
-            );
369
-        }
370
-        //this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
371
-        if (method_exists($this, 'extra_permalink_field_buttons')) {
372
-            add_filter('get_sample_permalink_html', array($this, 'extra_permalink_field_buttons'), 10, 4);
373
-        }
374
-        //add preview button
375
-        add_filter('get_sample_permalink_html', array($this, 'preview_button_html'), 5, 4);
376
-        //insert our own post_stati dropdown
377
-        add_action('post_submitbox_misc_actions', array($this, 'custom_post_stati_dropdown'), 10);
378
-        //This allows adding additional information to the publish post submitbox on the wp post edit form
379
-        if (method_exists($this, 'extra_misc_actions_publish_box')) {
380
-            add_action('post_submitbox_misc_actions', array($this, 'extra_misc_actions_publish_box'), 10);
381
-        }
382
-        // This allows for adding additional stuff after the title field on the wp post edit form.
383
-        // This is also before the wp_editor for post description field.
384
-        if (method_exists($this, 'edit_form_after_title')) {
385
-            add_action('edit_form_after_title', array($this, 'edit_form_after_title'), 10);
386
-        }
387
-        /**
388
-         * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route.
389
-         */
390
-        add_filter('clean_url', array($this, 'switch_core_wp_urls_with_ours'), 10, 3);
391
-        parent::_load_page_dependencies();
392
-        // notice we are ALSO going to load the pagenow hook set for this route
393
-        // (see _before_page_setup for the reset of the pagenow global ).
394
-        // This is for any plugins that are doing things properly
395
-        // and hooking into the load page hook for core wp cpt routes.
396
-        global $pagenow;
397
-        do_action('load-' . $pagenow);
398
-        $this->modify_current_screen();
399
-        add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30);
400
-        //we route REALLY early.
401
-        try {
402
-            $this->_route_admin_request();
403
-        } catch (EE_Error $e) {
404
-            $e->get_error();
405
-        }
406
-    }
407
-
408
-
409
-
410
-    /**
411
-     * Since we don't want users going to default core wp routes, this will check any wp urls run through the
412
-     * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
413
-     * route instead.
414
-     *
415
-     * @param string $good_protocol_url The escaped url.
416
-     * @param string $original_url      The original url.
417
-     * @param string $_context          The context sent to the esc_url method.
418
-     * @return string possibly a new url for our route.
419
-     */
420
-    public function switch_core_wp_urls_with_ours($good_protocol_url, $original_url, $_context)
421
-    {
422
-        $routes_to_match = array(
423
-            0 => array(
424
-                'edit.php?post_type=espresso_attendees',
425
-                'admin.php?page=espresso_registrations&action=contact_list',
426
-            ),
427
-            1 => array(
428
-                'edit.php?post_type=' . $this->_cpt_object->name,
429
-                'admin.php?page=' . $this->_cpt_object->name,
430
-            ),
431
-        );
432
-        foreach ($routes_to_match as $route_matches) {
433
-            if (strpos($good_protocol_url, $route_matches[0]) !== false) {
434
-                return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
435
-            }
436
-        }
437
-        return $good_protocol_url;
438
-    }
439
-
440
-
441
-
442
-    /**
443
-     * Determine whether the current cpt supports page templates or not.
444
-     *
445
-     * @since %VER%
446
-     * @param string $cpt_name The cpt slug we're checking on.
447
-     * @return bool True supported, false not.
448
-     */
449
-    private function _supports_page_templates($cpt_name)
450
-    {
451
-
452
-        $cpt_args = EE_Register_CPTs::get_CPTs();
453
-        $cpt_args = isset($cpt_args[$cpt_name]) ? $cpt_args[$cpt_name]['args'] : array();
454
-        $cpt_has_support = ! empty($cpt_args['page_templates']);
455
-
456
-        //if the installed version of WP is > 4.7 we do some additional checks.
457
-        if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
458
-            $post_templates = wp_get_theme()->get_post_templates();
459
-            //if there are $post_templates for this cpt, then we return false for this method because
460
-            //that means we aren't going to load our page template manager and leave that up to the native
461
-            //cpt template manager.
462
-            $cpt_has_support = ! isset($post_templates[$cpt_name]) ? $cpt_has_support : false;
463
-        }
464
-
465
-        return $cpt_has_support;
466
-    }
467
-
468
-
469
-    /**
470
-     * Callback for the page_templates metabox selector.
471
-     *
472
-     * @since %VER%
473
-     * @return void
474
-     */
475
-    public function page_template_meta_box()
476
-    {
477
-        global $post;
478
-        $template = '';
479
-
480
-        if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
481
-            $page_template_count = count(get_page_templates());
482
-        } else {
483
-            $page_template_count = count(get_page_templates($post));
484
-        };
485
-
486
-        if ($page_template_count) {
487
-            $page_template = get_post_meta($post->ID, '_wp_page_template', true);
488
-            $template      = ! empty($page_template) ? $page_template : '';
489
-        }
490
-        ?>
282
+		//filter _autosave_containers
283
+		$containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
284
+			$this->_autosave_containers, $this);
285
+		$containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
286
+			$containers, $this);
287
+
288
+		wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS',
289
+			$containers); //todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
290
+
291
+		$unsaved_data_msg = array(
292
+			'eventmsg'     => sprintf(__("The changes you made to this %s will be lost if you navigate away from this page.",
293
+				'event_espresso'), $this->_cpt_object->labels->singular_name),
294
+			'inputChanged' => 0,
295
+		);
296
+		wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
297
+	}
298
+
299
+
300
+
301
+	public function load_page_dependencies()
302
+	{
303
+		try {
304
+			$this->_load_page_dependencies();
305
+		} catch (EE_Error $e) {
306
+			$e->get_error();
307
+		}
308
+	}
309
+
310
+
311
+
312
+	/**
313
+	 * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
314
+	 *
315
+	 * @access protected
316
+	 * @return void
317
+	 */
318
+	protected function _load_page_dependencies()
319
+	{
320
+		//we only add stuff if this is a cpt_route!
321
+		if ( ! $this->_cpt_route) {
322
+			parent::_load_page_dependencies();
323
+			return;
324
+		}
325
+		// now let's do some automatic filters into the wp_system
326
+		// and we'll check to make sure the CHILD class
327
+		// automatically has the required methods in place.
328
+		// the following filters are for setting all the redirects
329
+		// on DEFAULT WP custom post type actions
330
+		// let's add a hidden input to the post-edit form
331
+		// so we know when we have to trigger our custom redirects!
332
+		// Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
333
+		add_action('edit_form_after_title', array($this, 'cpt_post_form_hidden_input'));
334
+		// inject our Admin page nav tabs...
335
+		// let's make sure the nav tabs are set if they aren't already
336
+		// if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
337
+		add_action('post_edit_form_tag', array($this, 'inject_nav_tabs'));
338
+		// modify the post_updated messages array
339
+		add_action('post_updated_messages', array($this, 'post_update_messages'), 10);
340
+		// add shortlink button to cpt edit screens.  We can do this as a universal thing BECAUSE,
341
+		// cpts use the same format for shortlinks as posts!
342
+		add_filter('pre_get_shortlink', array($this, 'add_shortlink_button_to_editor'), 10, 4);
343
+		// This basically allows us to change the title of the "publish" metabox area
344
+		// on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
345
+		if ( ! empty($this->_labels['publishbox'])) {
346
+			$box_label = is_array($this->_labels['publishbox'])
347
+						 && isset($this->_labels['publishbox'][$this->_req_action])
348
+					? $this->_labels['publishbox'][$this->_req_action]
349
+					: $this->_labels['publishbox'];
350
+			add_meta_box(
351
+				'submitdiv',
352
+				$box_label,
353
+				'post_submit_meta_box',
354
+				$this->_cpt_routes[$this->_req_action],
355
+				'side',
356
+				'core'
357
+			);
358
+		}
359
+		//let's add page_templates metabox if this cpt added support for it.
360
+		if ($this->_supports_page_templates($this->_cpt_object->name)) {
361
+			add_meta_box(
362
+				'page_templates',
363
+				__('Page Template', 'event_espresso'),
364
+				array($this, 'page_template_meta_box'),
365
+				$this->_cpt_routes[$this->_req_action],
366
+				'side',
367
+				'default'
368
+			);
369
+		}
370
+		//this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
371
+		if (method_exists($this, 'extra_permalink_field_buttons')) {
372
+			add_filter('get_sample_permalink_html', array($this, 'extra_permalink_field_buttons'), 10, 4);
373
+		}
374
+		//add preview button
375
+		add_filter('get_sample_permalink_html', array($this, 'preview_button_html'), 5, 4);
376
+		//insert our own post_stati dropdown
377
+		add_action('post_submitbox_misc_actions', array($this, 'custom_post_stati_dropdown'), 10);
378
+		//This allows adding additional information to the publish post submitbox on the wp post edit form
379
+		if (method_exists($this, 'extra_misc_actions_publish_box')) {
380
+			add_action('post_submitbox_misc_actions', array($this, 'extra_misc_actions_publish_box'), 10);
381
+		}
382
+		// This allows for adding additional stuff after the title field on the wp post edit form.
383
+		// This is also before the wp_editor for post description field.
384
+		if (method_exists($this, 'edit_form_after_title')) {
385
+			add_action('edit_form_after_title', array($this, 'edit_form_after_title'), 10);
386
+		}
387
+		/**
388
+		 * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route.
389
+		 */
390
+		add_filter('clean_url', array($this, 'switch_core_wp_urls_with_ours'), 10, 3);
391
+		parent::_load_page_dependencies();
392
+		// notice we are ALSO going to load the pagenow hook set for this route
393
+		// (see _before_page_setup for the reset of the pagenow global ).
394
+		// This is for any plugins that are doing things properly
395
+		// and hooking into the load page hook for core wp cpt routes.
396
+		global $pagenow;
397
+		do_action('load-' . $pagenow);
398
+		$this->modify_current_screen();
399
+		add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30);
400
+		//we route REALLY early.
401
+		try {
402
+			$this->_route_admin_request();
403
+		} catch (EE_Error $e) {
404
+			$e->get_error();
405
+		}
406
+	}
407
+
408
+
409
+
410
+	/**
411
+	 * Since we don't want users going to default core wp routes, this will check any wp urls run through the
412
+	 * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
413
+	 * route instead.
414
+	 *
415
+	 * @param string $good_protocol_url The escaped url.
416
+	 * @param string $original_url      The original url.
417
+	 * @param string $_context          The context sent to the esc_url method.
418
+	 * @return string possibly a new url for our route.
419
+	 */
420
+	public function switch_core_wp_urls_with_ours($good_protocol_url, $original_url, $_context)
421
+	{
422
+		$routes_to_match = array(
423
+			0 => array(
424
+				'edit.php?post_type=espresso_attendees',
425
+				'admin.php?page=espresso_registrations&action=contact_list',
426
+			),
427
+			1 => array(
428
+				'edit.php?post_type=' . $this->_cpt_object->name,
429
+				'admin.php?page=' . $this->_cpt_object->name,
430
+			),
431
+		);
432
+		foreach ($routes_to_match as $route_matches) {
433
+			if (strpos($good_protocol_url, $route_matches[0]) !== false) {
434
+				return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
435
+			}
436
+		}
437
+		return $good_protocol_url;
438
+	}
439
+
440
+
441
+
442
+	/**
443
+	 * Determine whether the current cpt supports page templates or not.
444
+	 *
445
+	 * @since %VER%
446
+	 * @param string $cpt_name The cpt slug we're checking on.
447
+	 * @return bool True supported, false not.
448
+	 */
449
+	private function _supports_page_templates($cpt_name)
450
+	{
451
+
452
+		$cpt_args = EE_Register_CPTs::get_CPTs();
453
+		$cpt_args = isset($cpt_args[$cpt_name]) ? $cpt_args[$cpt_name]['args'] : array();
454
+		$cpt_has_support = ! empty($cpt_args['page_templates']);
455
+
456
+		//if the installed version of WP is > 4.7 we do some additional checks.
457
+		if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
458
+			$post_templates = wp_get_theme()->get_post_templates();
459
+			//if there are $post_templates for this cpt, then we return false for this method because
460
+			//that means we aren't going to load our page template manager and leave that up to the native
461
+			//cpt template manager.
462
+			$cpt_has_support = ! isset($post_templates[$cpt_name]) ? $cpt_has_support : false;
463
+		}
464
+
465
+		return $cpt_has_support;
466
+	}
467
+
468
+
469
+	/**
470
+	 * Callback for the page_templates metabox selector.
471
+	 *
472
+	 * @since %VER%
473
+	 * @return void
474
+	 */
475
+	public function page_template_meta_box()
476
+	{
477
+		global $post;
478
+		$template = '';
479
+
480
+		if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
481
+			$page_template_count = count(get_page_templates());
482
+		} else {
483
+			$page_template_count = count(get_page_templates($post));
484
+		};
485
+
486
+		if ($page_template_count) {
487
+			$page_template = get_post_meta($post->ID, '_wp_page_template', true);
488
+			$template      = ! empty($page_template) ? $page_template : '';
489
+		}
490
+		?>
491 491
         <p><strong><?php _e('Template') ?></strong></p>
492 492
         <label class="screen-reader-text" for="page_template"><?php _e('Page Template') ?></label><select
493 493
             name="page_template" id="page_template">
@@ -495,450 +495,450 @@  discard block
 block discarded – undo
495 495
         <?php page_template_dropdown($template); ?>
496 496
     </select>
497 497
         <?php
498
-    }
499
-
500
-
501
-
502
-    /**
503
-     * if this post is a draft or scheduled post then we provide a preview button for user to click
504
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
505
-     *
506
-     * @param  string $return    the current html
507
-     * @param  int    $id        the post id for the page
508
-     * @param  string $new_title What the title is
509
-     * @param  string $new_slug  what the slug is
510
-     * @return string            The new html string for the permalink area
511
-     */
512
-    public function preview_button_html($return, $id, $new_title, $new_slug)
513
-    {
514
-        $post = get_post($id);
515
-        if ('publish' !== get_post_status($post)) {
516
-            //include shims for the `get_preview_post_link` function
517
-            require_once( EE_CORE . 'wordpress-shims.php' );
518
-            $return .= '<span_id="view-post-btn"><a target="_blank" href="'
519
-                       . get_preview_post_link($id)
520
-                       . '" class="button button-small">'
521
-                       . __('Preview', 'event_espresso')
522
-                       . '</a></span>'
523
-                       . "\n";
524
-        }
525
-        return $return;
526
-    }
527
-
528
-
529
-
530
-    /**
531
-     * add our custom post stati dropdown on the wp post page for this cpt
532
-     *
533
-     * @return void
534
-     */
535
-    public function custom_post_stati_dropdown()
536
-    {
537
-
538
-        $statuses         = $this->_cpt_model_obj->get_custom_post_statuses();
539
-        $cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
540
-            ? $statuses[$this->_cpt_model_obj->status()]
541
-            : '';
542
-        $template_args    = array(
543
-            'cur_status'            => $this->_cpt_model_obj->status(),
544
-            'statuses'              => $statuses,
545
-            'cur_status_label'      => $cur_status_label,
546
-            'localized_status_save' => sprintf(__('Save %s', 'event_espresso'), $cur_status_label),
547
-        );
548
-        //we'll add a trash post status (WP doesn't add one for some reason)
549
-        if ($this->_cpt_model_obj->status() === 'trash') {
550
-            $template_args['cur_status_label'] = __('Trashed', 'event_espresso');
551
-            $statuses['trash']                 = __('Trashed', 'event_espresso');
552
-            $template_args['statuses']         = $statuses;
553
-        }
554
-
555
-        $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
556
-        EEH_Template::display_template($template, $template_args);
557
-    }
558
-
559
-
560
-
561
-    public function setup_autosave_hooks()
562
-    {
563
-        $this->_set_autosave_containers();
564
-        $this->_load_autosave_scripts_styles();
565
-    }
566
-
567
-
568
-
569
-    /**
570
-     * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a $_POST object (available
571
-     * in $this->_req_data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
572
-     * for the nonce in here, but then this method looks for two things:
573
-     * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
574
-     * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
575
-     * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
576
-     * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
577
-     * template args.
578
-     *    1. $template_args['error'] = IF there is an error you can add the message in here.
579
-     *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
580
-     *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
581
-     *    $this->_template_args['data']['items'] = array(
582
-     *        'event-datetime-ids' => '1,2,3';
583
-     *    );
584
-     *    Keep in mind the following things:
585
-     *    - "where" index is for the input with the id as that string.
586
-     *    - "what" index is what will be used for the value of that input.
587
-     *
588
-     * @return void
589
-     */
590
-    public function do_extra_autosave_stuff()
591
-    {
592
-        //next let's check for the autosave nonce (we'll use _verify_nonce )
593
-        $nonce = isset($this->_req_data['autosavenonce'])
594
-                ? $this->_req_data['autosavenonce']
595
-                : null;
596
-        $this->_verify_nonce($nonce, 'autosave');
597
-        //make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
598
-        if ( ! defined('DOING_AUTOSAVE')) {
599
-            define('DOING_AUTOSAVE', true);
600
-        }
601
-        //if we made it here then the nonce checked out.  Let's run our methods and actions
602
-        $autosave = "_ee_autosave_{$this->_current_view}";
603
-        if (method_exists($this, $autosave)) {
604
-            $this->$autosave();
605
-        } else {
606
-            $this->_template_args['success'] = true;
607
-        }
608
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
609
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
610
-        //now let's return json
611
-        $this->_return_json();
612
-    }
613
-
614
-
615
-
616
-    /**
617
-     * This takes care of setting up default routes and pages that utilize the core WP admin pages.
618
-     * Child classes can override the defaults (in cases for adding metaboxes etc.)
619
-     * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
620
-     *
621
-     * @access protected
622
-     * @throws EE_Error
623
-     * @return void
624
-     */
625
-    protected function _extend_page_config_for_cpt()
626
-    {
627
-        //before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
628
-        if (isset($this->_req_data['page']) && $this->_req_data['page'] !== $this->page_slug) {
629
-            return;
630
-        }
631
-        //set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
632
-        if ( ! empty($this->_cpt_object)) {
633
-            $this->_page_routes = array_merge(array(
634
-                'create_new' => '_create_new_cpt_item',
635
-                'edit'       => '_edit_cpt_item',
636
-            ), $this->_page_routes);
637
-            $this->_page_config = array_merge(array(
638
-                'create_new' => array(
639
-                    'nav'           => array(
640
-                        'label' => $this->_cpt_object->labels->add_new_item,
641
-                        'order' => 5,
642
-                    ),
643
-                    'require_nonce' => false,
644
-                ),
645
-                'edit'       => array(
646
-                    'nav'           => array(
647
-                        'label'      => $this->_cpt_object->labels->edit_item,
648
-                        'order'      => 5,
649
-                        'persistent' => false,
650
-                        'url'        => '',
651
-                    ),
652
-                    'require_nonce' => false,
653
-                ),
654
-            ),
655
-                $this->_page_config
656
-            );
657
-        }
658
-        //load the next section only if this is a matching cpt route as set in the cpt routes array.
659
-        if ( ! isset($this->_cpt_routes[$this->_req_action])) {
660
-            return;
661
-        }
662
-        $this->_cpt_route = isset($this->_cpt_routes[$this->_req_action]) ? true : false;
663
-        //add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
664
-        if (empty($this->_cpt_object)) {
665
-            $msg = sprintf(__('This page has been set as being related to a registered custom post type, however, the custom post type object could not be retrieved. There are two possible reasons for this:  1. The "%s" does not match a registered post type. or 2. The custom post type is not registered for the "%s" action as indexed in the "$_cpt_routes" property on this class (%s).'),
666
-                $this->page_slug, $this->_req_action, get_class($this));
667
-            throw new EE_Error($msg);
668
-        }
669
-        if ($this->_cpt_route) {
670
-            $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
671
-            $this->_set_model_object($id);
672
-        }
673
-    }
674
-
675
-
676
-
677
-    /**
678
-     * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
679
-     *
680
-     * @access protected
681
-     * @param int  $id The id to retrieve the model object for. If empty we set a default object.
682
-     * @param bool $ignore_route_check
683
-     * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
684
-     * @throws EE_Error
685
-     */
686
-    protected function _set_model_object($id = null, $ignore_route_check = false, $req_type = '')
687
-    {
688
-        $model = null;
689
-        if (
690
-            empty($this->_cpt_model_names)
691
-            || (
692
-                ! $ignore_route_check
693
-                && ! isset($this->_cpt_routes[$this->_req_action])
694
-            ) || (
695
-                $this->_cpt_model_obj instanceof EE_CPT_Base
696
-                && $this->_cpt_model_obj->ID() === $id
697
-            )
698
-        ) {
699
-            //get out cuz we either don't have a model name OR the object has already been set and it has the same id as what has been sent.
700
-            return;
701
-        }
702
-        //if ignore_route_check is true, then get the model name via EE_Register_CPTs
703
-        if ($ignore_route_check) {
704
-            $model_names = EE_Register_CPTs::get_cpt_model_names();
705
-            $post_type   = get_post_type($id);
706
-            if (isset($model_names[$post_type])) {
707
-                $model = EE_Registry::instance()->load_model($model_names[$post_type]);
708
-            }
709
-        } else {
710
-            $model = EE_Registry::instance()->load_model($this->_cpt_model_names[$this->_req_action]);
711
-        }
712
-        if ($model instanceof EEM_Base) {
713
-            $this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
714
-        }
715
-        do_action(
716
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
717
-            $this->_cpt_model_obj,
718
-            $req_type
719
-        );
720
-    }
721
-
722
-
723
-
724
-    /**
725
-     * admin_init_global
726
-     * This runs all the code that we want executed within the WP admin_init hook.
727
-     * This method executes for ALL EE Admin pages.
728
-     *
729
-     * @access public
730
-     * @return void
731
-     */
732
-    public function admin_init_global()
733
-    {
734
-        $post = isset($this->_req_data['post']) ? get_post($this->_req_data['post']) : null;
735
-        //its possible this is a new save so let's catch that instead
736
-        $post = isset($this->_req_data['post_ID']) ? get_post($this->_req_data['post_ID']) : $post;
737
-        $post_type = $post ? $post->post_type : false;
738
-        $current_route = isset($this->_req_data['current_route'])
739
-            ? $this->_req_data['current_route']
740
-            : 'shouldneverwork';
741
-        $route_to_check = $post_type && isset($this->_cpt_routes[$current_route])
742
-            ? $this->_cpt_routes[$current_route]
743
-            : '';
744
-        add_filter('get_delete_post_link', array($this, 'modify_delete_post_link'), 10, 3);
745
-        add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 3);
746
-        if ($post_type === $route_to_check) {
747
-            add_filter('redirect_post_location', array($this, 'cpt_post_location_redirect'), 10, 2);
748
-        }
749
-        //now let's filter redirect if we're on a revision page and the revision is for an event CPT.
750
-        $revision = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
751
-        if ( ! empty($revision)) {
752
-            $action = isset($this->_req_data['action']) ? $this->_req_data['action'] : null;
753
-            //doing a restore?
754
-            if ( ! empty($action) && $action === 'restore') {
755
-                //get post for revision
756
-                $rev_post = get_post($revision);
757
-                $rev_parent = get_post($rev_post->post_parent);
758
-                //only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
759
-                if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
760
-                    add_filter('wp_redirect', array($this, 'revision_redirect'), 10, 2);
761
-                    //restores of revisions
762
-                    add_action('wp_restore_post_revision', array($this, 'restore_revision'), 10, 2);
763
-                }
764
-            }
765
-        }
766
-        //NOTE we ONLY want to run these hooks if we're on the right class for the given post type.  Otherwise we could see some really freaky things happen!
767
-        if ($post_type && $post_type === $route_to_check) {
768
-            //$post_id, $post
769
-            add_action('save_post', array($this, 'insert_update'), 10, 3);
770
-            //$post_id
771
-            add_action('trashed_post', array($this, 'before_trash_cpt_item'), 10);
772
-            add_action('trashed_post', array($this, 'dont_permanently_delete_ee_cpts'), 10);
773
-            add_action('untrashed_post', array($this, 'before_restore_cpt_item'), 10);
774
-            add_action('after_delete_post', array($this, 'before_delete_cpt_item'), 10);
775
-        }
776
-    }
777
-
778
-
779
-
780
-    /**
781
-     * Callback for the WordPress trashed_post hook.
782
-     * Execute some basic checks before calling the trash_cpt_item declared in the child class.
783
-     *
784
-     * @param int $post_id
785
-     * @throws \EE_Error
786
-     */
787
-    public function before_trash_cpt_item($post_id)
788
-    {
789
-        $this->_set_model_object($post_id, true, 'trash');
790
-        //if our cpt object isn't existent then get out immediately.
791
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
792
-            return;
793
-        }
794
-        $this->trash_cpt_item($post_id);
795
-    }
796
-
797
-
798
-
799
-    /**
800
-     * Callback for the WordPress untrashed_post hook.
801
-     * Execute some basic checks before calling the restore_cpt_method in the child class.
802
-     *
803
-     * @param $post_id
804
-     * @throws \EE_Error
805
-     */
806
-    public function before_restore_cpt_item($post_id)
807
-    {
808
-        $this->_set_model_object($post_id, true, 'restore');
809
-        //if our cpt object isn't existent then get out immediately.
810
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
811
-            return;
812
-        }
813
-        $this->restore_cpt_item($post_id);
814
-    }
815
-
816
-
817
-
818
-    /**
819
-     * Callback for the WordPress after_delete_post hook.
820
-     * Execute some basic checks before calling the delete_cpt_item method in the child class.
821
-     *
822
-     * @param $post_id
823
-     * @throws \EE_Error
824
-     */
825
-    public function before_delete_cpt_item($post_id)
826
-    {
827
-        $this->_set_model_object($post_id, true, 'delete');
828
-        //if our cpt object isn't existent then get out immediately.
829
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
830
-            return;
831
-        }
832
-        $this->delete_cpt_item($post_id);
833
-    }
834
-
835
-
836
-
837
-    /**
838
-     * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
839
-     * accordingly.
840
-     *
841
-     * @access public
842
-     * @throws EE_Error
843
-     * @return void
844
-     */
845
-    public function verify_cpt_object()
846
-    {
847
-        $label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
848
-        // verify event object
849
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
850
-            throw new EE_Error(sprintf(__('Something has gone wrong with the page load because we are unable to set up the object for the %1$s.  This usually happens when the given id for the page route is NOT for the correct custom post type for this page',
851
-                    'event_espresso'), $label));
852
-        }
853
-        //if auto-draft then throw an error
854
-        if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
855
-            EE_Error::overwrite_errors();
856
-            EE_Error::add_error(sprintf(__('This %1$s was saved without a title, description, or excerpt which means that none of the extra details you added were saved properly.  All autodrafts will show up in the "draft" view of your event list table.  You can delete them from there. Please click the "Add %1$s" button to refresh and restart.'),
857
-                    $label), __FILE__, __FUNCTION__, __LINE__);
858
-        }
859
-    }
860
-
861
-
862
-
863
-    /**
864
-     * admin_footer_scripts_global
865
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
866
-     * will apply on ALL EE_Admin pages.
867
-     *
868
-     * @access public
869
-     * @return void
870
-     */
871
-    public function admin_footer_scripts_global()
872
-    {
873
-        $this->_add_admin_page_ajax_loading_img();
874
-        $this->_add_admin_page_overlay();
875
-    }
876
-
877
-
878
-
879
-    /**
880
-     * add in any global scripts for cpt routes
881
-     *
882
-     * @return void
883
-     */
884
-    public function load_global_scripts_styles()
885
-    {
886
-        parent::load_global_scripts_styles();
887
-        if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
888
-            //setup custom post status object for localize script but only if we've got a cpt object
889
-            $statuses = $this->_cpt_model_obj->get_custom_post_statuses();
890
-            if ( ! empty($statuses)) {
891
-                //get ALL statuses!
892
-                $statuses = $this->_cpt_model_obj->get_all_post_statuses();
893
-                //setup object
894
-                $ee_cpt_statuses = array();
895
-                foreach ($statuses as $status => $label) {
896
-                    $ee_cpt_statuses[$status] = array(
897
-                        'label'      => $label,
898
-                        'save_label' => sprintf(__('Save as %s', 'event_espresso'), $label),
899
-                    );
900
-                }
901
-                wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
902
-            }
903
-        }
904
-    }
905
-
906
-
907
-
908
-    /**
909
-     * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
910
-     * insert/updates
911
-     *
912
-     * @param  int     $post_id ID of post being updated
913
-     * @param  WP_Post $post    Post object from WP
914
-     * @param  bool    $update  Whether this is an update or a new save.
915
-     * @return void
916
-     * @throws \EE_Error
917
-     */
918
-    public function insert_update($post_id, $post, $update)
919
-    {
920
-        //make sure that if this is a revision OR trash action that we don't do any updates!
921
-        if (
922
-            isset($this->_req_data['action'])
923
-            && (
924
-                $this->_req_data['action'] === 'restore'
925
-                || $this->_req_data['action'] === 'trash'
926
-            )
927
-        ) {
928
-            return;
929
-        }
930
-        $this->_set_model_object($post_id, true, 'insert_update');
931
-        //if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit.
932
-        if ($update
933
-            && (
934
-                ! $this->_cpt_model_obj instanceof EE_CPT_Base
935
-                || $this->_cpt_model_obj->ID() !== $post_id
936
-            )
937
-        ) {
938
-            return;
939
-        }
940
-        //check for autosave and update our req_data property accordingly.
941
-        /*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
498
+	}
499
+
500
+
501
+
502
+	/**
503
+	 * if this post is a draft or scheduled post then we provide a preview button for user to click
504
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
505
+	 *
506
+	 * @param  string $return    the current html
507
+	 * @param  int    $id        the post id for the page
508
+	 * @param  string $new_title What the title is
509
+	 * @param  string $new_slug  what the slug is
510
+	 * @return string            The new html string for the permalink area
511
+	 */
512
+	public function preview_button_html($return, $id, $new_title, $new_slug)
513
+	{
514
+		$post = get_post($id);
515
+		if ('publish' !== get_post_status($post)) {
516
+			//include shims for the `get_preview_post_link` function
517
+			require_once( EE_CORE . 'wordpress-shims.php' );
518
+			$return .= '<span_id="view-post-btn"><a target="_blank" href="'
519
+					   . get_preview_post_link($id)
520
+					   . '" class="button button-small">'
521
+					   . __('Preview', 'event_espresso')
522
+					   . '</a></span>'
523
+					   . "\n";
524
+		}
525
+		return $return;
526
+	}
527
+
528
+
529
+
530
+	/**
531
+	 * add our custom post stati dropdown on the wp post page for this cpt
532
+	 *
533
+	 * @return void
534
+	 */
535
+	public function custom_post_stati_dropdown()
536
+	{
537
+
538
+		$statuses         = $this->_cpt_model_obj->get_custom_post_statuses();
539
+		$cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
540
+			? $statuses[$this->_cpt_model_obj->status()]
541
+			: '';
542
+		$template_args    = array(
543
+			'cur_status'            => $this->_cpt_model_obj->status(),
544
+			'statuses'              => $statuses,
545
+			'cur_status_label'      => $cur_status_label,
546
+			'localized_status_save' => sprintf(__('Save %s', 'event_espresso'), $cur_status_label),
547
+		);
548
+		//we'll add a trash post status (WP doesn't add one for some reason)
549
+		if ($this->_cpt_model_obj->status() === 'trash') {
550
+			$template_args['cur_status_label'] = __('Trashed', 'event_espresso');
551
+			$statuses['trash']                 = __('Trashed', 'event_espresso');
552
+			$template_args['statuses']         = $statuses;
553
+		}
554
+
555
+		$template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
556
+		EEH_Template::display_template($template, $template_args);
557
+	}
558
+
559
+
560
+
561
+	public function setup_autosave_hooks()
562
+	{
563
+		$this->_set_autosave_containers();
564
+		$this->_load_autosave_scripts_styles();
565
+	}
566
+
567
+
568
+
569
+	/**
570
+	 * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a $_POST object (available
571
+	 * in $this->_req_data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
572
+	 * for the nonce in here, but then this method looks for two things:
573
+	 * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
574
+	 * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
575
+	 * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
576
+	 * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
577
+	 * template args.
578
+	 *    1. $template_args['error'] = IF there is an error you can add the message in here.
579
+	 *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
580
+	 *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
581
+	 *    $this->_template_args['data']['items'] = array(
582
+	 *        'event-datetime-ids' => '1,2,3';
583
+	 *    );
584
+	 *    Keep in mind the following things:
585
+	 *    - "where" index is for the input with the id as that string.
586
+	 *    - "what" index is what will be used for the value of that input.
587
+	 *
588
+	 * @return void
589
+	 */
590
+	public function do_extra_autosave_stuff()
591
+	{
592
+		//next let's check for the autosave nonce (we'll use _verify_nonce )
593
+		$nonce = isset($this->_req_data['autosavenonce'])
594
+				? $this->_req_data['autosavenonce']
595
+				: null;
596
+		$this->_verify_nonce($nonce, 'autosave');
597
+		//make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
598
+		if ( ! defined('DOING_AUTOSAVE')) {
599
+			define('DOING_AUTOSAVE', true);
600
+		}
601
+		//if we made it here then the nonce checked out.  Let's run our methods and actions
602
+		$autosave = "_ee_autosave_{$this->_current_view}";
603
+		if (method_exists($this, $autosave)) {
604
+			$this->$autosave();
605
+		} else {
606
+			$this->_template_args['success'] = true;
607
+		}
608
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
609
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
610
+		//now let's return json
611
+		$this->_return_json();
612
+	}
613
+
614
+
615
+
616
+	/**
617
+	 * This takes care of setting up default routes and pages that utilize the core WP admin pages.
618
+	 * Child classes can override the defaults (in cases for adding metaboxes etc.)
619
+	 * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
620
+	 *
621
+	 * @access protected
622
+	 * @throws EE_Error
623
+	 * @return void
624
+	 */
625
+	protected function _extend_page_config_for_cpt()
626
+	{
627
+		//before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
628
+		if (isset($this->_req_data['page']) && $this->_req_data['page'] !== $this->page_slug) {
629
+			return;
630
+		}
631
+		//set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
632
+		if ( ! empty($this->_cpt_object)) {
633
+			$this->_page_routes = array_merge(array(
634
+				'create_new' => '_create_new_cpt_item',
635
+				'edit'       => '_edit_cpt_item',
636
+			), $this->_page_routes);
637
+			$this->_page_config = array_merge(array(
638
+				'create_new' => array(
639
+					'nav'           => array(
640
+						'label' => $this->_cpt_object->labels->add_new_item,
641
+						'order' => 5,
642
+					),
643
+					'require_nonce' => false,
644
+				),
645
+				'edit'       => array(
646
+					'nav'           => array(
647
+						'label'      => $this->_cpt_object->labels->edit_item,
648
+						'order'      => 5,
649
+						'persistent' => false,
650
+						'url'        => '',
651
+					),
652
+					'require_nonce' => false,
653
+				),
654
+			),
655
+				$this->_page_config
656
+			);
657
+		}
658
+		//load the next section only if this is a matching cpt route as set in the cpt routes array.
659
+		if ( ! isset($this->_cpt_routes[$this->_req_action])) {
660
+			return;
661
+		}
662
+		$this->_cpt_route = isset($this->_cpt_routes[$this->_req_action]) ? true : false;
663
+		//add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
664
+		if (empty($this->_cpt_object)) {
665
+			$msg = sprintf(__('This page has been set as being related to a registered custom post type, however, the custom post type object could not be retrieved. There are two possible reasons for this:  1. The "%s" does not match a registered post type. or 2. The custom post type is not registered for the "%s" action as indexed in the "$_cpt_routes" property on this class (%s).'),
666
+				$this->page_slug, $this->_req_action, get_class($this));
667
+			throw new EE_Error($msg);
668
+		}
669
+		if ($this->_cpt_route) {
670
+			$id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
671
+			$this->_set_model_object($id);
672
+		}
673
+	}
674
+
675
+
676
+
677
+	/**
678
+	 * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
679
+	 *
680
+	 * @access protected
681
+	 * @param int  $id The id to retrieve the model object for. If empty we set a default object.
682
+	 * @param bool $ignore_route_check
683
+	 * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
684
+	 * @throws EE_Error
685
+	 */
686
+	protected function _set_model_object($id = null, $ignore_route_check = false, $req_type = '')
687
+	{
688
+		$model = null;
689
+		if (
690
+			empty($this->_cpt_model_names)
691
+			|| (
692
+				! $ignore_route_check
693
+				&& ! isset($this->_cpt_routes[$this->_req_action])
694
+			) || (
695
+				$this->_cpt_model_obj instanceof EE_CPT_Base
696
+				&& $this->_cpt_model_obj->ID() === $id
697
+			)
698
+		) {
699
+			//get out cuz we either don't have a model name OR the object has already been set and it has the same id as what has been sent.
700
+			return;
701
+		}
702
+		//if ignore_route_check is true, then get the model name via EE_Register_CPTs
703
+		if ($ignore_route_check) {
704
+			$model_names = EE_Register_CPTs::get_cpt_model_names();
705
+			$post_type   = get_post_type($id);
706
+			if (isset($model_names[$post_type])) {
707
+				$model = EE_Registry::instance()->load_model($model_names[$post_type]);
708
+			}
709
+		} else {
710
+			$model = EE_Registry::instance()->load_model($this->_cpt_model_names[$this->_req_action]);
711
+		}
712
+		if ($model instanceof EEM_Base) {
713
+			$this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
714
+		}
715
+		do_action(
716
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
717
+			$this->_cpt_model_obj,
718
+			$req_type
719
+		);
720
+	}
721
+
722
+
723
+
724
+	/**
725
+	 * admin_init_global
726
+	 * This runs all the code that we want executed within the WP admin_init hook.
727
+	 * This method executes for ALL EE Admin pages.
728
+	 *
729
+	 * @access public
730
+	 * @return void
731
+	 */
732
+	public function admin_init_global()
733
+	{
734
+		$post = isset($this->_req_data['post']) ? get_post($this->_req_data['post']) : null;
735
+		//its possible this is a new save so let's catch that instead
736
+		$post = isset($this->_req_data['post_ID']) ? get_post($this->_req_data['post_ID']) : $post;
737
+		$post_type = $post ? $post->post_type : false;
738
+		$current_route = isset($this->_req_data['current_route'])
739
+			? $this->_req_data['current_route']
740
+			: 'shouldneverwork';
741
+		$route_to_check = $post_type && isset($this->_cpt_routes[$current_route])
742
+			? $this->_cpt_routes[$current_route]
743
+			: '';
744
+		add_filter('get_delete_post_link', array($this, 'modify_delete_post_link'), 10, 3);
745
+		add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 3);
746
+		if ($post_type === $route_to_check) {
747
+			add_filter('redirect_post_location', array($this, 'cpt_post_location_redirect'), 10, 2);
748
+		}
749
+		//now let's filter redirect if we're on a revision page and the revision is for an event CPT.
750
+		$revision = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
751
+		if ( ! empty($revision)) {
752
+			$action = isset($this->_req_data['action']) ? $this->_req_data['action'] : null;
753
+			//doing a restore?
754
+			if ( ! empty($action) && $action === 'restore') {
755
+				//get post for revision
756
+				$rev_post = get_post($revision);
757
+				$rev_parent = get_post($rev_post->post_parent);
758
+				//only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
759
+				if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
760
+					add_filter('wp_redirect', array($this, 'revision_redirect'), 10, 2);
761
+					//restores of revisions
762
+					add_action('wp_restore_post_revision', array($this, 'restore_revision'), 10, 2);
763
+				}
764
+			}
765
+		}
766
+		//NOTE we ONLY want to run these hooks if we're on the right class for the given post type.  Otherwise we could see some really freaky things happen!
767
+		if ($post_type && $post_type === $route_to_check) {
768
+			//$post_id, $post
769
+			add_action('save_post', array($this, 'insert_update'), 10, 3);
770
+			//$post_id
771
+			add_action('trashed_post', array($this, 'before_trash_cpt_item'), 10);
772
+			add_action('trashed_post', array($this, 'dont_permanently_delete_ee_cpts'), 10);
773
+			add_action('untrashed_post', array($this, 'before_restore_cpt_item'), 10);
774
+			add_action('after_delete_post', array($this, 'before_delete_cpt_item'), 10);
775
+		}
776
+	}
777
+
778
+
779
+
780
+	/**
781
+	 * Callback for the WordPress trashed_post hook.
782
+	 * Execute some basic checks before calling the trash_cpt_item declared in the child class.
783
+	 *
784
+	 * @param int $post_id
785
+	 * @throws \EE_Error
786
+	 */
787
+	public function before_trash_cpt_item($post_id)
788
+	{
789
+		$this->_set_model_object($post_id, true, 'trash');
790
+		//if our cpt object isn't existent then get out immediately.
791
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
792
+			return;
793
+		}
794
+		$this->trash_cpt_item($post_id);
795
+	}
796
+
797
+
798
+
799
+	/**
800
+	 * Callback for the WordPress untrashed_post hook.
801
+	 * Execute some basic checks before calling the restore_cpt_method in the child class.
802
+	 *
803
+	 * @param $post_id
804
+	 * @throws \EE_Error
805
+	 */
806
+	public function before_restore_cpt_item($post_id)
807
+	{
808
+		$this->_set_model_object($post_id, true, 'restore');
809
+		//if our cpt object isn't existent then get out immediately.
810
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
811
+			return;
812
+		}
813
+		$this->restore_cpt_item($post_id);
814
+	}
815
+
816
+
817
+
818
+	/**
819
+	 * Callback for the WordPress after_delete_post hook.
820
+	 * Execute some basic checks before calling the delete_cpt_item method in the child class.
821
+	 *
822
+	 * @param $post_id
823
+	 * @throws \EE_Error
824
+	 */
825
+	public function before_delete_cpt_item($post_id)
826
+	{
827
+		$this->_set_model_object($post_id, true, 'delete');
828
+		//if our cpt object isn't existent then get out immediately.
829
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
830
+			return;
831
+		}
832
+		$this->delete_cpt_item($post_id);
833
+	}
834
+
835
+
836
+
837
+	/**
838
+	 * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
839
+	 * accordingly.
840
+	 *
841
+	 * @access public
842
+	 * @throws EE_Error
843
+	 * @return void
844
+	 */
845
+	public function verify_cpt_object()
846
+	{
847
+		$label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
848
+		// verify event object
849
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
850
+			throw new EE_Error(sprintf(__('Something has gone wrong with the page load because we are unable to set up the object for the %1$s.  This usually happens when the given id for the page route is NOT for the correct custom post type for this page',
851
+					'event_espresso'), $label));
852
+		}
853
+		//if auto-draft then throw an error
854
+		if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
855
+			EE_Error::overwrite_errors();
856
+			EE_Error::add_error(sprintf(__('This %1$s was saved without a title, description, or excerpt which means that none of the extra details you added were saved properly.  All autodrafts will show up in the "draft" view of your event list table.  You can delete them from there. Please click the "Add %1$s" button to refresh and restart.'),
857
+					$label), __FILE__, __FUNCTION__, __LINE__);
858
+		}
859
+	}
860
+
861
+
862
+
863
+	/**
864
+	 * admin_footer_scripts_global
865
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
866
+	 * will apply on ALL EE_Admin pages.
867
+	 *
868
+	 * @access public
869
+	 * @return void
870
+	 */
871
+	public function admin_footer_scripts_global()
872
+	{
873
+		$this->_add_admin_page_ajax_loading_img();
874
+		$this->_add_admin_page_overlay();
875
+	}
876
+
877
+
878
+
879
+	/**
880
+	 * add in any global scripts for cpt routes
881
+	 *
882
+	 * @return void
883
+	 */
884
+	public function load_global_scripts_styles()
885
+	{
886
+		parent::load_global_scripts_styles();
887
+		if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
888
+			//setup custom post status object for localize script but only if we've got a cpt object
889
+			$statuses = $this->_cpt_model_obj->get_custom_post_statuses();
890
+			if ( ! empty($statuses)) {
891
+				//get ALL statuses!
892
+				$statuses = $this->_cpt_model_obj->get_all_post_statuses();
893
+				//setup object
894
+				$ee_cpt_statuses = array();
895
+				foreach ($statuses as $status => $label) {
896
+					$ee_cpt_statuses[$status] = array(
897
+						'label'      => $label,
898
+						'save_label' => sprintf(__('Save as %s', 'event_espresso'), $label),
899
+					);
900
+				}
901
+				wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
902
+			}
903
+		}
904
+	}
905
+
906
+
907
+
908
+	/**
909
+	 * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
910
+	 * insert/updates
911
+	 *
912
+	 * @param  int     $post_id ID of post being updated
913
+	 * @param  WP_Post $post    Post object from WP
914
+	 * @param  bool    $update  Whether this is an update or a new save.
915
+	 * @return void
916
+	 * @throws \EE_Error
917
+	 */
918
+	public function insert_update($post_id, $post, $update)
919
+	{
920
+		//make sure that if this is a revision OR trash action that we don't do any updates!
921
+		if (
922
+			isset($this->_req_data['action'])
923
+			&& (
924
+				$this->_req_data['action'] === 'restore'
925
+				|| $this->_req_data['action'] === 'trash'
926
+			)
927
+		) {
928
+			return;
929
+		}
930
+		$this->_set_model_object($post_id, true, 'insert_update');
931
+		//if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit.
932
+		if ($update
933
+			&& (
934
+				! $this->_cpt_model_obj instanceof EE_CPT_Base
935
+				|| $this->_cpt_model_obj->ID() !== $post_id
936
+			)
937
+		) {
938
+			return;
939
+		}
940
+		//check for autosave and update our req_data property accordingly.
941
+		/*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
942 942
             foreach( (array) $this->_req_data['ee_autosave_data'] as $id => $values ) {
943 943
 
944 944
                 foreach ( (array) $values as $key => $value ) {
@@ -948,527 +948,527 @@  discard block
 block discarded – undo
948 948
 
949 949
         }/**/ //TODO reactivate after autosave is implemented in 4.2
950 950
 
951
-        //take care of updating any selected page_template IF this cpt supports it.
952
-        if ($this->_supports_page_templates($post->post_type) && ! empty($this->_req_data['page_template'])) {
953
-            //wp version aware.
954
-            if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) {
955
-                $page_templates = wp_get_theme()->get_page_templates();
956
-            } else {
957
-                $post->page_template = $this->_req_data['page_template'];
958
-                $page_templates      = wp_get_theme()->get_page_templates($post);
959
-            }
960
-            if ('default' != $this->_req_data['page_template'] && ! isset($page_templates[$this->_req_data['page_template']])) {
961
-                EE_Error::add_error(__('Invalid Page Template.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
962
-            } else {
963
-                update_post_meta($post_id, '_wp_page_template', $this->_req_data['page_template']);
964
-            }
965
-        }
966
-        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
967
-            return;
968
-        } //TODO we'll remove this after reimplementing autosave in 4.2
969
-        $this->_insert_update_cpt_item($post_id, $post);
970
-    }
971
-
972
-
973
-
974
-    /**
975
-     * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
976
-     * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
977
-     * so we don't have to check for our CPT.
978
-     *
979
-     * @param  int $post_id ID of the post
980
-     * @return void
981
-     */
982
-    public function dont_permanently_delete_ee_cpts($post_id)
983
-    {
984
-        //only do this if we're actually processing one of our CPTs
985
-        //if our cpt object isn't existent then get out immediately.
986
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
987
-            return;
988
-        }
989
-        delete_post_meta($post_id, '_wp_trash_meta_status');
990
-        delete_post_meta($post_id, '_wp_trash_meta_time');
991
-        //our cpts may have comments so let's take care of that too
992
-        delete_post_meta($post_id, '_wp_trash_meta_comments_status');
993
-    }
994
-
995
-
996
-
997
-    /**
998
-     * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
999
-     * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1000
-     * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1001
-     *
1002
-     * @param  int $post_id     ID of cpt item
1003
-     * @param  int $revision_id ID of revision being restored
1004
-     * @return void
1005
-     */
1006
-    public function restore_revision($post_id, $revision_id)
1007
-    {
1008
-        $this->_restore_cpt_item($post_id, $revision_id);
1009
-        //global action
1010
-        do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1011
-        //class specific action so you can limit hooking into a specific page.
1012
-        do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1013
-    }
1014
-
1015
-
1016
-
1017
-    /**
1018
-     * @see restore_revision() for details
1019
-     * @param  int $post_id     ID of cpt item
1020
-     * @param  int $revision_id ID of revision for item
1021
-     * @return void
1022
-     */
1023
-    abstract protected function _restore_cpt_item($post_id, $revision_id);
1024
-
1025
-
1026
-
1027
-    /**
1028
-     * Execution of this method is added to the end of the load_page_dependencies method in the parent
1029
-     * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1030
-     * To fix we have to reset the current_screen using the page_slug
1031
-     * (which is identical - or should be - to our registered_post_type id.)
1032
-     * Also, since the core WP file loads the admin_header.php for WP
1033
-     * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1034
-     * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1035
-     *
1036
-     * @return void
1037
-     */
1038
-    public function modify_current_screen()
1039
-    {
1040
-        //ONLY do this if the current page_route IS a cpt route
1041
-        if ( ! $this->_cpt_route) {
1042
-            return;
1043
-        }
1044
-        //routing things REALLY early b/c this is a cpt admin page
1045
-        set_current_screen($this->_cpt_routes[$this->_req_action]);
1046
-        $this->_current_screen       = get_current_screen();
1047
-        $this->_current_screen->base = 'event-espresso';
1048
-        $this->_add_help_tabs(); //we make sure we add any help tabs back in!
1049
-        /*try {
951
+		//take care of updating any selected page_template IF this cpt supports it.
952
+		if ($this->_supports_page_templates($post->post_type) && ! empty($this->_req_data['page_template'])) {
953
+			//wp version aware.
954
+			if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) {
955
+				$page_templates = wp_get_theme()->get_page_templates();
956
+			} else {
957
+				$post->page_template = $this->_req_data['page_template'];
958
+				$page_templates      = wp_get_theme()->get_page_templates($post);
959
+			}
960
+			if ('default' != $this->_req_data['page_template'] && ! isset($page_templates[$this->_req_data['page_template']])) {
961
+				EE_Error::add_error(__('Invalid Page Template.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
962
+			} else {
963
+				update_post_meta($post_id, '_wp_page_template', $this->_req_data['page_template']);
964
+			}
965
+		}
966
+		if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
967
+			return;
968
+		} //TODO we'll remove this after reimplementing autosave in 4.2
969
+		$this->_insert_update_cpt_item($post_id, $post);
970
+	}
971
+
972
+
973
+
974
+	/**
975
+	 * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
976
+	 * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
977
+	 * so we don't have to check for our CPT.
978
+	 *
979
+	 * @param  int $post_id ID of the post
980
+	 * @return void
981
+	 */
982
+	public function dont_permanently_delete_ee_cpts($post_id)
983
+	{
984
+		//only do this if we're actually processing one of our CPTs
985
+		//if our cpt object isn't existent then get out immediately.
986
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
987
+			return;
988
+		}
989
+		delete_post_meta($post_id, '_wp_trash_meta_status');
990
+		delete_post_meta($post_id, '_wp_trash_meta_time');
991
+		//our cpts may have comments so let's take care of that too
992
+		delete_post_meta($post_id, '_wp_trash_meta_comments_status');
993
+	}
994
+
995
+
996
+
997
+	/**
998
+	 * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
999
+	 * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1000
+	 * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1001
+	 *
1002
+	 * @param  int $post_id     ID of cpt item
1003
+	 * @param  int $revision_id ID of revision being restored
1004
+	 * @return void
1005
+	 */
1006
+	public function restore_revision($post_id, $revision_id)
1007
+	{
1008
+		$this->_restore_cpt_item($post_id, $revision_id);
1009
+		//global action
1010
+		do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1011
+		//class specific action so you can limit hooking into a specific page.
1012
+		do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1013
+	}
1014
+
1015
+
1016
+
1017
+	/**
1018
+	 * @see restore_revision() for details
1019
+	 * @param  int $post_id     ID of cpt item
1020
+	 * @param  int $revision_id ID of revision for item
1021
+	 * @return void
1022
+	 */
1023
+	abstract protected function _restore_cpt_item($post_id, $revision_id);
1024
+
1025
+
1026
+
1027
+	/**
1028
+	 * Execution of this method is added to the end of the load_page_dependencies method in the parent
1029
+	 * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1030
+	 * To fix we have to reset the current_screen using the page_slug
1031
+	 * (which is identical - or should be - to our registered_post_type id.)
1032
+	 * Also, since the core WP file loads the admin_header.php for WP
1033
+	 * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1034
+	 * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1035
+	 *
1036
+	 * @return void
1037
+	 */
1038
+	public function modify_current_screen()
1039
+	{
1040
+		//ONLY do this if the current page_route IS a cpt route
1041
+		if ( ! $this->_cpt_route) {
1042
+			return;
1043
+		}
1044
+		//routing things REALLY early b/c this is a cpt admin page
1045
+		set_current_screen($this->_cpt_routes[$this->_req_action]);
1046
+		$this->_current_screen       = get_current_screen();
1047
+		$this->_current_screen->base = 'event-espresso';
1048
+		$this->_add_help_tabs(); //we make sure we add any help tabs back in!
1049
+		/*try {
1050 1050
             $this->_route_admin_request();
1051 1051
         } catch ( EE_Error $e ) {
1052 1052
             $e->get_error();
1053 1053
         }/**/
1054
-    }
1055
-
1056
-
1057
-
1058
-    /**
1059
-     * This allows child classes to modify the default editor title that appears when people add a new or edit an
1060
-     * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1061
-     * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1062
-     * default to be.
1063
-     *
1064
-     * @param string $title The new title (or existing if there is no editor_title defined)
1065
-     * @return string
1066
-     */
1067
-    public function add_custom_editor_default_title($title)
1068
-    {
1069
-        return isset($this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]])
1070
-            ? $this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]]
1071
-            : $title;
1072
-    }
1073
-
1074
-
1075
-
1076
-    /**
1077
-     * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1078
-     *
1079
-     * @param string $shortlink   The already generated shortlink
1080
-     * @param int    $id          Post ID for this item
1081
-     * @param string $context     The context for the link
1082
-     * @param bool   $allow_slugs Whether to allow post slugs in the shortlink.
1083
-     * @return string
1084
-     */
1085
-    public function add_shortlink_button_to_editor($shortlink, $id, $context, $allow_slugs)
1086
-    {
1087
-        if ( ! empty($id) && get_option('permalink_structure') !== '') {
1088
-            $post = get_post($id);
1089
-            if (isset($post->post_type) && $this->page_slug === $post->post_type) {
1090
-                $shortlink = home_url('?p=' . $post->ID);
1091
-            }
1092
-        }
1093
-        return $shortlink;
1094
-    }
1095
-
1096
-
1097
-
1098
-    /**
1099
-     * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1100
-     * already run in modify_current_screen())
1101
-     *
1102
-     * @return void
1103
-     */
1104
-    public function route_admin_request()
1105
-    {
1106
-        if ($this->_cpt_route) {
1107
-            return;
1108
-        }
1109
-        try {
1110
-            $this->_route_admin_request();
1111
-        } catch (EE_Error $e) {
1112
-            $e->get_error();
1113
-        }
1114
-    }
1115
-
1116
-
1117
-
1118
-    /**
1119
-     * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1120
-     *
1121
-     * @return void
1122
-     */
1123
-    public function cpt_post_form_hidden_input()
1124
-    {
1125
-        echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />';
1126
-        //we're also going to add the route value and the current page so we can direct autosave parsing correctly
1127
-        echo '<div id="ee-cpt-hidden-inputs">';
1128
-        echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />';
1129
-        echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />';
1130
-        echo '</div>';
1131
-    }
1132
-
1133
-
1134
-
1135
-    /**
1136
-     * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1137
-     *
1138
-     * @param  string $location Original location url
1139
-     * @param  int    $status   Status for http header
1140
-     * @return string           new (or original) url to redirect to.
1141
-     */
1142
-    public function revision_redirect($location, $status)
1143
-    {
1144
-        //get revision
1145
-        $rev_id = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
1146
-        //can't do anything without revision so let's get out if not present
1147
-        if (empty($rev_id)) {
1148
-            return $location;
1149
-        }
1150
-        //get rev_post_data
1151
-        $rev = get_post($rev_id);
1152
-        $admin_url = $this->_admin_base_url;
1153
-        $query_args = array(
1154
-            'action'   => 'edit',
1155
-            'post'     => $rev->post_parent,
1156
-            'revision' => $rev_id,
1157
-            'message'  => 5,
1158
-        );
1159
-        $this->_process_notices($query_args, true);
1160
-        return self::add_query_args_and_nonce($query_args, $admin_url);
1161
-    }
1162
-
1163
-
1164
-
1165
-    /**
1166
-     * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1167
-     *
1168
-     * @param  string $link    the original generated link
1169
-     * @param  int    $id      post id
1170
-     * @param  string $context optional, defaults to display.  How to write the '&'
1171
-     * @return string          the link
1172
-     */
1173
-    public function modify_edit_post_link($link, $id, $context)
1174
-    {
1175
-        $post = get_post($id);
1176
-        if ( ! isset($this->_req_data['action'])
1177
-             || ! isset($this->_cpt_routes[$this->_req_data['action']])
1178
-             || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1179
-        ) {
1180
-            return $link;
1181
-        }
1182
-        $query_args = array(
1183
-            'action' => isset($this->_cpt_edit_routes[$post->post_type])
1184
-                ? $this->_cpt_edit_routes[$post->post_type]
1185
-                : 'edit',
1186
-            'post'   => $id,
1187
-        );
1188
-        return self::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1189
-    }
1190
-
1191
-
1192
-    /**
1193
-     * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1194
-     * our routes.
1195
-     *
1196
-     * @param  string $delete_link  original delete link
1197
-     * @param  int    $post_id      id of cpt object
1198
-     * @param  bool   $force_delete whether this is forcing a hard delete instead of trash
1199
-     * @return string new delete link
1200
-     * @throws EE_Error
1201
-     */
1202
-    public function modify_delete_post_link($delete_link, $post_id, $force_delete)
1203
-    {
1204
-        $post = get_post($post_id);
1205
-
1206
-        if (empty($this->_req_data['action'])
1207
-            || ! isset($this->_cpt_routes[$this->_req_data['action']])
1208
-            || ! $post instanceof WP_Post
1209
-            || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1210
-        ) {
1211
-            return $delete_link;
1212
-        }
1213
-        $this->_set_model_object($post->ID, true);
1214
-
1215
-        //returns something like `trash_event` or `trash_attendee` or `trash_venue`
1216
-        $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1217
-
1218
-        return EE_Admin_Page::add_query_args_and_nonce(
1219
-            array(
1220
-                'page' => $this->_req_data['page'],
1221
-                'action' => $action,
1222
-                $this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name()
1223
-                    => $post->ID
1224
-            ),
1225
-            admin_url()
1226
-        );
1227
-    }
1228
-
1229
-
1230
-
1231
-    /**
1232
-     * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1233
-     * so that we can hijack the default redirect locations for wp custom post types
1234
-     * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1235
-     *
1236
-     * @param  string $location This is the incoming currently set redirect location
1237
-     * @param  string $post_id  This is the 'ID' value of the wp_posts table
1238
-     * @return string           the new location to redirect to
1239
-     */
1240
-    public function cpt_post_location_redirect($location, $post_id)
1241
-    {
1242
-        //we DO have a match so let's setup the url
1243
-        //we have to get the post to determine our route
1244
-        $post       = get_post($post_id);
1245
-        $edit_route = $this->_cpt_edit_routes[$post->post_type];
1246
-        //shared query_args
1247
-        $query_args = array('action' => $edit_route, 'post' => $post_id);
1248
-        $admin_url  = $this->_admin_base_url;
1249
-        if (isset($this->_req_data['save']) || isset($this->_req_data['publish'])) {
1250
-            $status = get_post_status($post_id);
1251
-            if (isset($this->_req_data['publish'])) {
1252
-                switch ($status) {
1253
-                    case 'pending':
1254
-                        $message = 8;
1255
-                        break;
1256
-                    case 'future':
1257
-                        $message = 9;
1258
-                        break;
1259
-                    default:
1260
-                        $message = 6;
1261
-                }
1262
-            } else {
1263
-                $message = 'draft' === $status ? 10 : 1;
1264
-            }
1265
-        } else if (isset($this->_req_data['addmeta']) && $this->_req_data['addmeta']) {
1266
-            $message = 2;
1267
-            //			$append = '#postcustom';
1268
-        } else if (isset($this->_req_data['deletemeta']) && $this->_req_data['deletemeta']) {
1269
-            $message = 3;
1270
-            //			$append = '#postcustom';
1271
-        } elseif ($this->_req_data['action'] === 'post-quickpress-save-cont') {
1272
-            $message = 7;
1273
-        } else {
1274
-            $message = 4;
1275
-        }
1276
-        //change the message if the post type is not viewable on the frontend
1277
-        $this->_cpt_object = get_post_type_object($post->post_type);
1278
-        $message           = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1279
-        $query_args = array_merge(array('message' => $message), $query_args);
1280
-        $this->_process_notices($query_args, true);
1281
-        return self::add_query_args_and_nonce($query_args, $admin_url);
1282
-    }
1283
-
1284
-
1285
-
1286
-    /**
1287
-     * This method is called to inject nav tabs on core WP cpt pages
1288
-     *
1289
-     * @access public
1290
-     * @return void
1291
-     */
1292
-    public function inject_nav_tabs()
1293
-    {
1294
-        //can we hijack and insert the nav_tabs?
1295
-        $nav_tabs = $this->_get_main_nav_tabs();
1296
-        //first close off existing form tag
1297
-        $html = '>';
1298
-        $html .= $nav_tabs;
1299
-        //now let's handle the remaining tag ( missing ">" is CORRECT )
1300
-        $html .= '<span></span';
1301
-        echo $html;
1302
-    }
1303
-
1304
-
1305
-
1306
-    /**
1307
-     * This just sets up the post update messages when an update form is loaded
1308
-     *
1309
-     * @access public
1310
-     * @param  array $messages the original messages array
1311
-     * @return array           the new messages array
1312
-     */
1313
-    public function post_update_messages($messages)
1314
-    {
1315
-        global $post;
1316
-        $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1317
-        $id = empty($id) && is_object($post) ? $post->ID : null;
1318
-        //		$post_type = $post ? $post->post_type : false;
1319
-        /*$current_route = isset($this->_req_data['current_route']) ? $this->_req_data['current_route'] : 'shouldneverwork';
1054
+	}
1055
+
1056
+
1057
+
1058
+	/**
1059
+	 * This allows child classes to modify the default editor title that appears when people add a new or edit an
1060
+	 * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1061
+	 * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1062
+	 * default to be.
1063
+	 *
1064
+	 * @param string $title The new title (or existing if there is no editor_title defined)
1065
+	 * @return string
1066
+	 */
1067
+	public function add_custom_editor_default_title($title)
1068
+	{
1069
+		return isset($this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]])
1070
+			? $this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]]
1071
+			: $title;
1072
+	}
1073
+
1074
+
1075
+
1076
+	/**
1077
+	 * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1078
+	 *
1079
+	 * @param string $shortlink   The already generated shortlink
1080
+	 * @param int    $id          Post ID for this item
1081
+	 * @param string $context     The context for the link
1082
+	 * @param bool   $allow_slugs Whether to allow post slugs in the shortlink.
1083
+	 * @return string
1084
+	 */
1085
+	public function add_shortlink_button_to_editor($shortlink, $id, $context, $allow_slugs)
1086
+	{
1087
+		if ( ! empty($id) && get_option('permalink_structure') !== '') {
1088
+			$post = get_post($id);
1089
+			if (isset($post->post_type) && $this->page_slug === $post->post_type) {
1090
+				$shortlink = home_url('?p=' . $post->ID);
1091
+			}
1092
+		}
1093
+		return $shortlink;
1094
+	}
1095
+
1096
+
1097
+
1098
+	/**
1099
+	 * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1100
+	 * already run in modify_current_screen())
1101
+	 *
1102
+	 * @return void
1103
+	 */
1104
+	public function route_admin_request()
1105
+	{
1106
+		if ($this->_cpt_route) {
1107
+			return;
1108
+		}
1109
+		try {
1110
+			$this->_route_admin_request();
1111
+		} catch (EE_Error $e) {
1112
+			$e->get_error();
1113
+		}
1114
+	}
1115
+
1116
+
1117
+
1118
+	/**
1119
+	 * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1120
+	 *
1121
+	 * @return void
1122
+	 */
1123
+	public function cpt_post_form_hidden_input()
1124
+	{
1125
+		echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />';
1126
+		//we're also going to add the route value and the current page so we can direct autosave parsing correctly
1127
+		echo '<div id="ee-cpt-hidden-inputs">';
1128
+		echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />';
1129
+		echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />';
1130
+		echo '</div>';
1131
+	}
1132
+
1133
+
1134
+
1135
+	/**
1136
+	 * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1137
+	 *
1138
+	 * @param  string $location Original location url
1139
+	 * @param  int    $status   Status for http header
1140
+	 * @return string           new (or original) url to redirect to.
1141
+	 */
1142
+	public function revision_redirect($location, $status)
1143
+	{
1144
+		//get revision
1145
+		$rev_id = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
1146
+		//can't do anything without revision so let's get out if not present
1147
+		if (empty($rev_id)) {
1148
+			return $location;
1149
+		}
1150
+		//get rev_post_data
1151
+		$rev = get_post($rev_id);
1152
+		$admin_url = $this->_admin_base_url;
1153
+		$query_args = array(
1154
+			'action'   => 'edit',
1155
+			'post'     => $rev->post_parent,
1156
+			'revision' => $rev_id,
1157
+			'message'  => 5,
1158
+		);
1159
+		$this->_process_notices($query_args, true);
1160
+		return self::add_query_args_and_nonce($query_args, $admin_url);
1161
+	}
1162
+
1163
+
1164
+
1165
+	/**
1166
+	 * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1167
+	 *
1168
+	 * @param  string $link    the original generated link
1169
+	 * @param  int    $id      post id
1170
+	 * @param  string $context optional, defaults to display.  How to write the '&'
1171
+	 * @return string          the link
1172
+	 */
1173
+	public function modify_edit_post_link($link, $id, $context)
1174
+	{
1175
+		$post = get_post($id);
1176
+		if ( ! isset($this->_req_data['action'])
1177
+			 || ! isset($this->_cpt_routes[$this->_req_data['action']])
1178
+			 || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1179
+		) {
1180
+			return $link;
1181
+		}
1182
+		$query_args = array(
1183
+			'action' => isset($this->_cpt_edit_routes[$post->post_type])
1184
+				? $this->_cpt_edit_routes[$post->post_type]
1185
+				: 'edit',
1186
+			'post'   => $id,
1187
+		);
1188
+		return self::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1189
+	}
1190
+
1191
+
1192
+	/**
1193
+	 * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1194
+	 * our routes.
1195
+	 *
1196
+	 * @param  string $delete_link  original delete link
1197
+	 * @param  int    $post_id      id of cpt object
1198
+	 * @param  bool   $force_delete whether this is forcing a hard delete instead of trash
1199
+	 * @return string new delete link
1200
+	 * @throws EE_Error
1201
+	 */
1202
+	public function modify_delete_post_link($delete_link, $post_id, $force_delete)
1203
+	{
1204
+		$post = get_post($post_id);
1205
+
1206
+		if (empty($this->_req_data['action'])
1207
+			|| ! isset($this->_cpt_routes[$this->_req_data['action']])
1208
+			|| ! $post instanceof WP_Post
1209
+			|| $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1210
+		) {
1211
+			return $delete_link;
1212
+		}
1213
+		$this->_set_model_object($post->ID, true);
1214
+
1215
+		//returns something like `trash_event` or `trash_attendee` or `trash_venue`
1216
+		$action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1217
+
1218
+		return EE_Admin_Page::add_query_args_and_nonce(
1219
+			array(
1220
+				'page' => $this->_req_data['page'],
1221
+				'action' => $action,
1222
+				$this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name()
1223
+					=> $post->ID
1224
+			),
1225
+			admin_url()
1226
+		);
1227
+	}
1228
+
1229
+
1230
+
1231
+	/**
1232
+	 * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1233
+	 * so that we can hijack the default redirect locations for wp custom post types
1234
+	 * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1235
+	 *
1236
+	 * @param  string $location This is the incoming currently set redirect location
1237
+	 * @param  string $post_id  This is the 'ID' value of the wp_posts table
1238
+	 * @return string           the new location to redirect to
1239
+	 */
1240
+	public function cpt_post_location_redirect($location, $post_id)
1241
+	{
1242
+		//we DO have a match so let's setup the url
1243
+		//we have to get the post to determine our route
1244
+		$post       = get_post($post_id);
1245
+		$edit_route = $this->_cpt_edit_routes[$post->post_type];
1246
+		//shared query_args
1247
+		$query_args = array('action' => $edit_route, 'post' => $post_id);
1248
+		$admin_url  = $this->_admin_base_url;
1249
+		if (isset($this->_req_data['save']) || isset($this->_req_data['publish'])) {
1250
+			$status = get_post_status($post_id);
1251
+			if (isset($this->_req_data['publish'])) {
1252
+				switch ($status) {
1253
+					case 'pending':
1254
+						$message = 8;
1255
+						break;
1256
+					case 'future':
1257
+						$message = 9;
1258
+						break;
1259
+					default:
1260
+						$message = 6;
1261
+				}
1262
+			} else {
1263
+				$message = 'draft' === $status ? 10 : 1;
1264
+			}
1265
+		} else if (isset($this->_req_data['addmeta']) && $this->_req_data['addmeta']) {
1266
+			$message = 2;
1267
+			//			$append = '#postcustom';
1268
+		} else if (isset($this->_req_data['deletemeta']) && $this->_req_data['deletemeta']) {
1269
+			$message = 3;
1270
+			//			$append = '#postcustom';
1271
+		} elseif ($this->_req_data['action'] === 'post-quickpress-save-cont') {
1272
+			$message = 7;
1273
+		} else {
1274
+			$message = 4;
1275
+		}
1276
+		//change the message if the post type is not viewable on the frontend
1277
+		$this->_cpt_object = get_post_type_object($post->post_type);
1278
+		$message           = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1279
+		$query_args = array_merge(array('message' => $message), $query_args);
1280
+		$this->_process_notices($query_args, true);
1281
+		return self::add_query_args_and_nonce($query_args, $admin_url);
1282
+	}
1283
+
1284
+
1285
+
1286
+	/**
1287
+	 * This method is called to inject nav tabs on core WP cpt pages
1288
+	 *
1289
+	 * @access public
1290
+	 * @return void
1291
+	 */
1292
+	public function inject_nav_tabs()
1293
+	{
1294
+		//can we hijack and insert the nav_tabs?
1295
+		$nav_tabs = $this->_get_main_nav_tabs();
1296
+		//first close off existing form tag
1297
+		$html = '>';
1298
+		$html .= $nav_tabs;
1299
+		//now let's handle the remaining tag ( missing ">" is CORRECT )
1300
+		$html .= '<span></span';
1301
+		echo $html;
1302
+	}
1303
+
1304
+
1305
+
1306
+	/**
1307
+	 * This just sets up the post update messages when an update form is loaded
1308
+	 *
1309
+	 * @access public
1310
+	 * @param  array $messages the original messages array
1311
+	 * @return array           the new messages array
1312
+	 */
1313
+	public function post_update_messages($messages)
1314
+	{
1315
+		global $post;
1316
+		$id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1317
+		$id = empty($id) && is_object($post) ? $post->ID : null;
1318
+		//		$post_type = $post ? $post->post_type : false;
1319
+		/*$current_route = isset($this->_req_data['current_route']) ? $this->_req_data['current_route'] : 'shouldneverwork';
1320 1320
 
1321 1321
         $route_to_check = $post_type && isset( $this->_cpt_routes[$current_route]) ? $this->_cpt_routes[$current_route] : '';/**/
1322
-        $messages[$post->post_type] = array(
1323
-            0 => '', //Unused. Messages start at index 1.
1324
-            1 => sprintf(
1325
-                __('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1326
-                $this->_cpt_object->labels->singular_name,
1327
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1328
-                '</a>'
1329
-            ),
1330
-            2 => __('Custom field updated'),
1331
-            3 => __('Custom field deleted.'),
1332
-            4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1333
-            5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'),
1334
-                $this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false))
1335
-                : false,
1336
-            6 => sprintf(
1337
-                __('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1338
-                $this->_cpt_object->labels->singular_name,
1339
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1340
-                '</a>'
1341
-            ),
1342
-            7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1343
-            8 => sprintf(
1344
-                __('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1345
-                $this->_cpt_object->labels->singular_name,
1346
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1347
-                '</a>'
1348
-            ),
1349
-            9 => sprintf(
1350
-                __('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1351
-                $this->_cpt_object->labels->singular_name,
1352
-                '<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>',
1353
-                '<a target="_blank" href="' . esc_url(get_permalink($id)),
1354
-                '</a>'
1355
-            ),
1356
-            10 => sprintf(
1357
-                __('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1358
-                $this->_cpt_object->labels->singular_name,
1359
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1360
-                '</a>'
1361
-            ),
1362
-        );
1363
-        return $messages;
1364
-    }
1365
-
1366
-
1367
-
1368
-    /**
1369
-     * default method for the 'create_new' route for cpt admin pages.
1370
-     * For reference what to include in here, see wp-admin/post-new.php
1371
-     *
1372
-     * @access  protected
1373
-     * @return void
1374
-     */
1375
-    protected function _create_new_cpt_item()
1376
-    {
1377
-        // gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1378
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1379
-        $post_type        = $this->_cpt_routes[$this->_req_action];
1380
-        $post_type_object = $this->_cpt_object;
1381
-        $title            = $post_type_object->labels->add_new_item;
1382
-        $editing          = true;
1383
-        wp_enqueue_script('autosave');
1384
-        $post    = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true);
1385
-        $post_ID = $post->ID;
1386
-        add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1387
-        //modify the default editor title field with default title.
1388
-        add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1389
-        include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1390
-    }
1391
-
1392
-
1393
-
1394
-    public function add_new_admin_page_global()
1395
-    {
1396
-        $admin_page = ! empty($this->_req_data['post']) ? 'post-php' : 'post-new-php';
1397
-        ?>
1322
+		$messages[$post->post_type] = array(
1323
+			0 => '', //Unused. Messages start at index 1.
1324
+			1 => sprintf(
1325
+				__('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1326
+				$this->_cpt_object->labels->singular_name,
1327
+				'<a href="' . esc_url(get_permalink($id)) . '">',
1328
+				'</a>'
1329
+			),
1330
+			2 => __('Custom field updated'),
1331
+			3 => __('Custom field deleted.'),
1332
+			4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1333
+			5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'),
1334
+				$this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false))
1335
+				: false,
1336
+			6 => sprintf(
1337
+				__('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1338
+				$this->_cpt_object->labels->singular_name,
1339
+				'<a href="' . esc_url(get_permalink($id)) . '">',
1340
+				'</a>'
1341
+			),
1342
+			7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1343
+			8 => sprintf(
1344
+				__('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1345
+				$this->_cpt_object->labels->singular_name,
1346
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1347
+				'</a>'
1348
+			),
1349
+			9 => sprintf(
1350
+				__('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1351
+				$this->_cpt_object->labels->singular_name,
1352
+				'<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>',
1353
+				'<a target="_blank" href="' . esc_url(get_permalink($id)),
1354
+				'</a>'
1355
+			),
1356
+			10 => sprintf(
1357
+				__('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1358
+				$this->_cpt_object->labels->singular_name,
1359
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1360
+				'</a>'
1361
+			),
1362
+		);
1363
+		return $messages;
1364
+	}
1365
+
1366
+
1367
+
1368
+	/**
1369
+	 * default method for the 'create_new' route for cpt admin pages.
1370
+	 * For reference what to include in here, see wp-admin/post-new.php
1371
+	 *
1372
+	 * @access  protected
1373
+	 * @return void
1374
+	 */
1375
+	protected function _create_new_cpt_item()
1376
+	{
1377
+		// gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1378
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1379
+		$post_type        = $this->_cpt_routes[$this->_req_action];
1380
+		$post_type_object = $this->_cpt_object;
1381
+		$title            = $post_type_object->labels->add_new_item;
1382
+		$editing          = true;
1383
+		wp_enqueue_script('autosave');
1384
+		$post    = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true);
1385
+		$post_ID = $post->ID;
1386
+		add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1387
+		//modify the default editor title field with default title.
1388
+		add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1389
+		include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1390
+	}
1391
+
1392
+
1393
+
1394
+	public function add_new_admin_page_global()
1395
+	{
1396
+		$admin_page = ! empty($this->_req_data['post']) ? 'post-php' : 'post-new-php';
1397
+		?>
1398 1398
         <script type="text/javascript">
1399 1399
             adminpage = '<?php echo $admin_page; ?>';
1400 1400
         </script>
1401 1401
         <?php
1402
-    }
1403
-
1404
-
1405
-
1406
-    /**
1407
-     * default method for the 'edit' route for cpt admin pages
1408
-     * For reference on what to put in here, refer to wp-admin/post.php
1409
-     *
1410
-     * @access protected
1411
-     * @return string   template for edit cpt form
1412
-     */
1413
-    protected function _edit_cpt_item()
1414
-    {
1415
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1416
-        $post_id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1417
-        $post = ! empty($post_id) ? get_post($post_id, OBJECT, 'edit') : null;
1418
-        if (empty ($post)) {
1419
-            wp_die(__('You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?'));
1420
-        }
1421
-        if ( ! empty($_GET['get-post-lock'])) {
1422
-            wp_set_post_lock($post_id);
1423
-            wp_redirect(get_edit_post_link($post_id, 'url'));
1424
-            exit();
1425
-        }
1426
-
1427
-        // template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1428
-        $editing          = true;
1429
-        $post_ID          = $post_id;
1430
-        $post_type        = $this->_cpt_routes[$this->_req_action];
1431
-        $post_type_object = $this->_cpt_object;
1432
-
1433
-        if ( ! wp_check_post_lock($post->ID)) {
1434
-            $active_post_lock = wp_set_post_lock($post->ID);
1435
-            //wp_enqueue_script('autosave');
1436
-        }
1437
-        $title = $this->_cpt_object->labels->edit_item;
1438
-        add_action('admin_footer', '_admin_notice_post_locked');
1439
-        if (isset($this->_cpt_routes[$this->_req_data['action']])
1440
-            && ! isset($this->_labels['hide_add_button_on_cpt_route'][$this->_req_data['action']])
1441
-        ) {
1442
-            $create_new_action = apply_filters('FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1443
-                'create_new', $this);
1444
-            $post_new_file = EE_Admin_Page::add_query_args_and_nonce(array(
1445
-                'action' => $create_new_action,
1446
-                'page'   => $this->page_slug,
1447
-            ), 'admin.php');
1448
-        }
1449
-        if (post_type_supports($this->_cpt_routes[$this->_req_action], 'comments')) {
1450
-            wp_enqueue_script('admin-comments');
1451
-            enqueue_comment_hotkeys_js();
1452
-        }
1453
-        add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1454
-        //modify the default editor title field with default title.
1455
-        add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1456
-        include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1457
-    }
1458
-
1459
-
1460
-
1461
-    /**
1462
-     * some getters
1463
-     */
1464
-    /**
1465
-     * This returns the protected _cpt_model_obj property
1466
-     *
1467
-     * @return EE_CPT_Base
1468
-     */
1469
-    public function get_cpt_model_obj()
1470
-    {
1471
-        return $this->_cpt_model_obj;
1472
-    }
1402
+	}
1403
+
1404
+
1405
+
1406
+	/**
1407
+	 * default method for the 'edit' route for cpt admin pages
1408
+	 * For reference on what to put in here, refer to wp-admin/post.php
1409
+	 *
1410
+	 * @access protected
1411
+	 * @return string   template for edit cpt form
1412
+	 */
1413
+	protected function _edit_cpt_item()
1414
+	{
1415
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1416
+		$post_id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1417
+		$post = ! empty($post_id) ? get_post($post_id, OBJECT, 'edit') : null;
1418
+		if (empty ($post)) {
1419
+			wp_die(__('You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?'));
1420
+		}
1421
+		if ( ! empty($_GET['get-post-lock'])) {
1422
+			wp_set_post_lock($post_id);
1423
+			wp_redirect(get_edit_post_link($post_id, 'url'));
1424
+			exit();
1425
+		}
1426
+
1427
+		// template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1428
+		$editing          = true;
1429
+		$post_ID          = $post_id;
1430
+		$post_type        = $this->_cpt_routes[$this->_req_action];
1431
+		$post_type_object = $this->_cpt_object;
1432
+
1433
+		if ( ! wp_check_post_lock($post->ID)) {
1434
+			$active_post_lock = wp_set_post_lock($post->ID);
1435
+			//wp_enqueue_script('autosave');
1436
+		}
1437
+		$title = $this->_cpt_object->labels->edit_item;
1438
+		add_action('admin_footer', '_admin_notice_post_locked');
1439
+		if (isset($this->_cpt_routes[$this->_req_data['action']])
1440
+			&& ! isset($this->_labels['hide_add_button_on_cpt_route'][$this->_req_data['action']])
1441
+		) {
1442
+			$create_new_action = apply_filters('FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1443
+				'create_new', $this);
1444
+			$post_new_file = EE_Admin_Page::add_query_args_and_nonce(array(
1445
+				'action' => $create_new_action,
1446
+				'page'   => $this->page_slug,
1447
+			), 'admin.php');
1448
+		}
1449
+		if (post_type_supports($this->_cpt_routes[$this->_req_action], 'comments')) {
1450
+			wp_enqueue_script('admin-comments');
1451
+			enqueue_comment_hotkeys_js();
1452
+		}
1453
+		add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1454
+		//modify the default editor title field with default title.
1455
+		add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1456
+		include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1457
+	}
1458
+
1459
+
1460
+
1461
+	/**
1462
+	 * some getters
1463
+	 */
1464
+	/**
1465
+	 * This returns the protected _cpt_model_obj property
1466
+	 *
1467
+	 * @return EE_CPT_Base
1468
+	 */
1469
+	public function get_cpt_model_obj()
1470
+	{
1471
+		return $this->_cpt_model_obj;
1472
+	}
1473 1473
 
1474 1474
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -235,7 +235,7 @@  discard block
 block discarded – undo
235 235
      */
236 236
     protected function _register_autosave_containers($ids)
237 237
     {
238
-        $this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids);
238
+        $this->_autosave_containers = array_merge($this->_autosave_fields, (array) $ids);
239 239
     }
240 240
 
241 241
 
@@ -282,7 +282,7 @@  discard block
 block discarded – undo
282 282
         //filter _autosave_containers
283 283
         $containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
284 284
             $this->_autosave_containers, $this);
285
-        $containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
285
+        $containers = apply_filters('FHEE__EE_Admin_Page_CPT__'.get_class($this).'___load_autosave_scripts_styles__containers',
286 286
             $containers, $this);
287 287
 
288 288
         wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS',
@@ -394,7 +394,7 @@  discard block
 block discarded – undo
394 394
         // This is for any plugins that are doing things properly
395 395
         // and hooking into the load page hook for core wp cpt routes.
396 396
         global $pagenow;
397
-        do_action('load-' . $pagenow);
397
+        do_action('load-'.$pagenow);
398 398
         $this->modify_current_screen();
399 399
         add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30);
400 400
         //we route REALLY early.
@@ -425,8 +425,8 @@  discard block
 block discarded – undo
425 425
                 'admin.php?page=espresso_registrations&action=contact_list',
426 426
             ),
427 427
             1 => array(
428
-                'edit.php?post_type=' . $this->_cpt_object->name,
429
-                'admin.php?page=' . $this->_cpt_object->name,
428
+                'edit.php?post_type='.$this->_cpt_object->name,
429
+                'admin.php?page='.$this->_cpt_object->name,
430 430
             ),
431 431
         );
432 432
         foreach ($routes_to_match as $route_matches) {
@@ -454,7 +454,7 @@  discard block
 block discarded – undo
454 454
         $cpt_has_support = ! empty($cpt_args['page_templates']);
455 455
 
456 456
         //if the installed version of WP is > 4.7 we do some additional checks.
457
-        if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
457
+        if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) {
458 458
             $post_templates = wp_get_theme()->get_post_templates();
459 459
             //if there are $post_templates for this cpt, then we return false for this method because
460 460
             //that means we aren't going to load our page template manager and leave that up to the native
@@ -477,7 +477,7 @@  discard block
 block discarded – undo
477 477
         global $post;
478 478
         $template = '';
479 479
 
480
-        if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
480
+        if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) {
481 481
             $page_template_count = count(get_page_templates());
482 482
         } else {
483 483
             $page_template_count = count(get_page_templates($post));
@@ -514,7 +514,7 @@  discard block
 block discarded – undo
514 514
         $post = get_post($id);
515 515
         if ('publish' !== get_post_status($post)) {
516 516
             //include shims for the `get_preview_post_link` function
517
-            require_once( EE_CORE . 'wordpress-shims.php' );
517
+            require_once(EE_CORE.'wordpress-shims.php');
518 518
             $return .= '<span_id="view-post-btn"><a target="_blank" href="'
519 519
                        . get_preview_post_link($id)
520 520
                        . '" class="button button-small">'
@@ -552,7 +552,7 @@  discard block
 block discarded – undo
552 552
             $template_args['statuses']         = $statuses;
553 553
         }
554 554
 
555
-        $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
555
+        $template = EE_ADMIN_TEMPLATE.'status_dropdown.template.php';
556 556
         EEH_Template::display_template($template, $template_args);
557 557
     }
558 558
 
@@ -606,7 +606,7 @@  discard block
 block discarded – undo
606 606
             $this->_template_args['success'] = true;
607 607
         }
608 608
         do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
609
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
609
+        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_'.get_class($this), $this);
610 610
         //now let's return json
611 611
         $this->_return_json();
612 612
     }
@@ -1009,7 +1009,7 @@  discard block
 block discarded – undo
1009 1009
         //global action
1010 1010
         do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1011 1011
         //class specific action so you can limit hooking into a specific page.
1012
-        do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1012
+        do_action('AHEE_EE_Admin_Page_CPT_'.get_class($this).'__restore_revision', $post_id, $revision_id);
1013 1013
     }
1014 1014
 
1015 1015
 
@@ -1087,7 +1087,7 @@  discard block
 block discarded – undo
1087 1087
         if ( ! empty($id) && get_option('permalink_structure') !== '') {
1088 1088
             $post = get_post($id);
1089 1089
             if (isset($post->post_type) && $this->page_slug === $post->post_type) {
1090
-                $shortlink = home_url('?p=' . $post->ID);
1090
+                $shortlink = home_url('?p='.$post->ID);
1091 1091
             }
1092 1092
         }
1093 1093
         return $shortlink;
@@ -1122,11 +1122,11 @@  discard block
 block discarded – undo
1122 1122
      */
1123 1123
     public function cpt_post_form_hidden_input()
1124 1124
     {
1125
-        echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />';
1125
+        echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="'.$this->_admin_base_url.'" />';
1126 1126
         //we're also going to add the route value and the current page so we can direct autosave parsing correctly
1127 1127
         echo '<div id="ee-cpt-hidden-inputs">';
1128
-        echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />';
1129
-        echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />';
1128
+        echo '<input type="hidden" id="current_route" name="current_route" value="'.$this->_current_view.'" />';
1129
+        echo '<input type="hidden" id="current_page" name="current_page" value="'.$this->page_slug.'" />';
1130 1130
         echo '</div>';
1131 1131
     }
1132 1132
 
@@ -1213,7 +1213,7 @@  discard block
 block discarded – undo
1213 1213
         $this->_set_model_object($post->ID, true);
1214 1214
 
1215 1215
         //returns something like `trash_event` or `trash_attendee` or `trash_venue`
1216
-        $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1216
+        $action = 'trash_'.str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1217 1217
 
1218 1218
         return EE_Admin_Page::add_query_args_and_nonce(
1219 1219
             array(
@@ -1324,39 +1324,39 @@  discard block
 block discarded – undo
1324 1324
             1 => sprintf(
1325 1325
                 __('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1326 1326
                 $this->_cpt_object->labels->singular_name,
1327
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1327
+                '<a href="'.esc_url(get_permalink($id)).'">',
1328 1328
                 '</a>'
1329 1329
             ),
1330 1330
             2 => __('Custom field updated'),
1331 1331
             3 => __('Custom field deleted.'),
1332 1332
             4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1333 1333
             5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'),
1334
-                $this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false))
1334
+                $this->_cpt_object->labels->singular_name, wp_post_revision_title((int) $_GET['revision'], false))
1335 1335
                 : false,
1336 1336
             6 => sprintf(
1337 1337
                 __('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1338 1338
                 $this->_cpt_object->labels->singular_name,
1339
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1339
+                '<a href="'.esc_url(get_permalink($id)).'">',
1340 1340
                 '</a>'
1341 1341
             ),
1342 1342
             7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1343 1343
             8 => sprintf(
1344 1344
                 __('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1345 1345
                 $this->_cpt_object->labels->singular_name,
1346
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1346
+                '<a target="_blank" href="'.esc_url(add_query_arg('preview', 'true', get_permalink($id))).'">',
1347 1347
                 '</a>'
1348 1348
             ),
1349 1349
             9 => sprintf(
1350 1350
                 __('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1351 1351
                 $this->_cpt_object->labels->singular_name,
1352
-                '<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>',
1353
-                '<a target="_blank" href="' . esc_url(get_permalink($id)),
1352
+                '<strong>'.date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)).'</strong>',
1353
+                '<a target="_blank" href="'.esc_url(get_permalink($id)),
1354 1354
                 '</a>'
1355 1355
             ),
1356 1356
             10 => sprintf(
1357 1357
                 __('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1358 1358
                 $this->_cpt_object->labels->singular_name,
1359
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1359
+                '<a target="_blank" href="'.esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1360 1360
                 '</a>'
1361 1361
             ),
1362 1362
         );
@@ -1386,7 +1386,7 @@  discard block
 block discarded – undo
1386 1386
         add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1387 1387
         //modify the default editor title field with default title.
1388 1388
         add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1389
-        include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1389
+        include_once WP_ADMIN_PATH.'edit-form-advanced.php';
1390 1390
     }
1391 1391
 
1392 1392
 
@@ -1453,7 +1453,7 @@  discard block
 block discarded – undo
1453 1453
         add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1454 1454
         //modify the default editor title field with default title.
1455 1455
         add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1456
-        include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1456
+        include_once WP_ADMIN_PATH.'edit-form-advanced.php';
1457 1457
     }
1458 1458
 
1459 1459
 
Please login to merge, or discard this patch.
admin/extend/registration_form/Extend_Registration_Form_Admin_Page.core.php 1 patch
Indentation   +1088 added lines, -1088 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 if (! defined('EVENT_ESPRESSO_VERSION')) {
3
-    exit('NO direct script access allowed');
3
+	exit('NO direct script access allowed');
4 4
 }
5 5
 
6 6
 /**
@@ -25,1093 +25,1093 @@  discard block
 block discarded – undo
25 25
 {
26 26
 
27 27
 
28
-    /**
29
-     * @Constructor
30
-     * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
31
-     * @access public
32
-     */
33
-    public function __construct($routing = true)
34
-    {
35
-        define('REGISTRATION_FORM_CAF_ADMIN', EE_CORE_CAF_ADMIN_EXTEND . 'registration_form' . DS);
36
-        define('REGISTRATION_FORM_CAF_ASSETS_PATH', REGISTRATION_FORM_CAF_ADMIN . 'assets' . DS);
37
-        define('REGISTRATION_FORM_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'registration_form/assets/');
38
-        define('REGISTRATION_FORM_CAF_TEMPLATE_PATH', REGISTRATION_FORM_CAF_ADMIN . 'templates' . DS);
39
-        define('REGISTRATION_FORM_CAF_TEMPLATE_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'registration_form/templates/');
40
-        parent::__construct($routing);
41
-    }
42
-
43
-
44
-    protected function _extend_page_config()
45
-    {
46
-        $this->_admin_base_path = REGISTRATION_FORM_CAF_ADMIN;
47
-        $qst_id = ! empty($this->_req_data['QST_ID']) && ! is_array($this->_req_data['QST_ID']) ? $this->_req_data['QST_ID'] : 0;
48
-        $qsg_id = ! empty($this->_req_data['QSG_ID']) && ! is_array($this->_req_data['QSG_ID']) ? $this->_req_data['QSG_ID'] : 0;
49
-
50
-        $new_page_routes    = array(
51
-            'question_groups'    => array(
52
-                'func'       => '_question_groups_overview_list_table',
53
-                'capability' => 'ee_read_question_groups',
54
-            ),
55
-            'add_question'       => array(
56
-                'func'       => '_edit_question',
57
-                'capability' => 'ee_edit_questions',
58
-            ),
59
-            'insert_question'    => array(
60
-                'func'       => '_insert_or_update_question',
61
-                'args'       => array('new_question' => true),
62
-                'capability' => 'ee_edit_questions',
63
-                'noheader'   => true,
64
-            ),
65
-            'duplicate_question' => array(
66
-                'func'       => '_duplicate_question',
67
-                'capability' => 'ee_edit_questions',
68
-                'noheader'   => true,
69
-            ),
70
-            'trash_question'     => array(
71
-                'func'       => '_trash_question',
72
-                'capability' => 'ee_delete_question',
73
-                'obj_id'     => $qst_id,
74
-                'noheader'   => true,
75
-            ),
76
-
77
-            'restore_question' => array(
78
-                'func'       => '_trash_or_restore_questions',
79
-                'capability' => 'ee_delete_question',
80
-                'obj_id'     => $qst_id,
81
-                'args'       => array('trash' => false),
82
-                'noheader'   => true,
83
-            ),
84
-
85
-            'delete_question' => array(
86
-                'func'       => '_delete_question',
87
-                'capability' => 'ee_delete_question',
88
-                'obj_id'     => $qst_id,
89
-                'noheader'   => true,
90
-            ),
91
-
92
-            'trash_questions' => array(
93
-                'func'       => '_trash_or_restore_questions',
94
-                'capability' => 'ee_delete_questions',
95
-                'args'       => array('trash' => true),
96
-                'noheader'   => true,
97
-            ),
98
-
99
-            'restore_questions' => array(
100
-                'func'       => '_trash_or_restore_questions',
101
-                'capability' => 'ee_delete_questions',
102
-                'args'       => array('trash' => false),
103
-                'noheader'   => true,
104
-            ),
105
-
106
-            'delete_questions' => array(
107
-                'func'       => '_delete_questions',
108
-                'args'       => array(),
109
-                'capability' => 'ee_delete_questions',
110
-                'noheader'   => true,
111
-            ),
112
-
113
-            'add_question_group' => array(
114
-                'func'       => '_edit_question_group',
115
-                'capability' => 'ee_edit_question_groups',
116
-            ),
117
-
118
-            'edit_question_group' => array(
119
-                'func'       => '_edit_question_group',
120
-                'capability' => 'ee_edit_question_group',
121
-                'obj_id'     => $qsg_id,
122
-                'args'       => array('edit'),
123
-            ),
124
-
125
-            'delete_question_groups' => array(
126
-                'func'       => '_delete_question_groups',
127
-                'capability' => 'ee_delete_question_groups',
128
-                'noheader'   => true,
129
-            ),
130
-
131
-            'delete_question_group' => array(
132
-                'func'       => '_delete_question_groups',
133
-                'capability' => 'ee_delete_question_group',
134
-                'obj_id'     => $qsg_id,
135
-                'noheader'   => true,
136
-            ),
137
-
138
-            'trash_question_group' => array(
139
-                'func'       => '_trash_or_restore_question_groups',
140
-                'args'       => array('trash' => true),
141
-                'capability' => 'ee_delete_question_group',
142
-                'obj_id'     => $qsg_id,
143
-                'noheader'   => true,
144
-            ),
145
-
146
-            'restore_question_group' => array(
147
-                'func'       => '_trash_or_restore_question_groups',
148
-                'args'       => array('trash' => false),
149
-                'capability' => 'ee_delete_question_group',
150
-                'obj_id'     => $qsg_id,
151
-                'noheader'   => true,
152
-            ),
153
-
154
-            'insert_question_group' => array(
155
-                'func'       => '_insert_or_update_question_group',
156
-                'args'       => array('new_question_group' => true),
157
-                'capability' => 'ee_edit_question_groups',
158
-                'noheader'   => true,
159
-            ),
160
-
161
-            'update_question_group' => array(
162
-                'func'       => '_insert_or_update_question_group',
163
-                'args'       => array('new_question_group' => false),
164
-                'capability' => 'ee_edit_question_group',
165
-                'obj_id'     => $qsg_id,
166
-                'noheader'   => true,
167
-            ),
168
-
169
-            'trash_question_groups' => array(
170
-                'func'       => '_trash_or_restore_question_groups',
171
-                'args'       => array('trash' => true),
172
-                'capability' => 'ee_delete_question_groups',
173
-                'noheader'   => array('trash' => false),
174
-            ),
175
-
176
-            'restore_question_groups' => array(
177
-                'func'       => '_trash_or_restore_question_groups',
178
-                'args'       => array('trash' => false),
179
-                'capability' => 'ee_delete_question_groups',
180
-                'noheader'   => true,
181
-            ),
182
-
183
-
184
-            'espresso_update_question_group_order' => array(
185
-                'func'       => 'update_question_group_order',
186
-                'capability' => 'ee_edit_question_groups',
187
-                'noheader'   => true,
188
-            ),
189
-
190
-            'view_reg_form_settings' => array(
191
-                'func'       => '_reg_form_settings',
192
-                'capability' => 'manage_options',
193
-            ),
194
-
195
-            'update_reg_form_settings' => array(
196
-                'func'       => '_update_reg_form_settings',
197
-                'capability' => 'manage_options',
198
-                'noheader'   => true,
199
-            ),
200
-        );
201
-        $this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
202
-
203
-        $new_page_config    = array(
204
-
205
-            'question_groups' => array(
206
-                'nav'           => array(
207
-                    'label' => esc_html__('Question Groups', 'event_espresso'),
208
-                    'order' => 20,
209
-                ),
210
-                'list_table'    => 'Registration_Form_Question_Groups_Admin_List_Table',
211
-                'help_tabs'     => array(
212
-                    'registration_form_question_groups_help_tab'                           => array(
213
-                        'title'    => esc_html__('Question Groups', 'event_espresso'),
214
-                        'filename' => 'registration_form_question_groups',
215
-                    ),
216
-                    'registration_form_question_groups_table_column_headings_help_tab'     => array(
217
-                        'title'    => esc_html__('Question Groups Table Column Headings', 'event_espresso'),
218
-                        'filename' => 'registration_form_question_groups_table_column_headings',
219
-                    ),
220
-                    'registration_form_question_groups_views_bulk_actions_search_help_tab' => array(
221
-                        'title'    => esc_html__('Question Groups Views & Bulk Actions & Search', 'event_espresso'),
222
-                        'filename' => 'registration_form_question_groups_views_bulk_actions_search',
223
-                    ),
224
-                ),
225
-                'help_tour'     => array('Registration_Form_Question_Groups_Help_Tour'),
226
-                'metaboxes'     => $this->_default_espresso_metaboxes,
227
-                'require_nonce' => false,
228
-                'qtips'         => array(
229
-                    'EE_Registration_Form_Tips',
230
-                ),
231
-            ),
232
-
233
-            'add_question' => array(
234
-                'nav'           => array(
235
-                    'label'      => esc_html__('Add Question', 'event_espresso'),
236
-                    'order'      => 5,
237
-                    'persistent' => false,
238
-                ),
239
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
240
-                'help_tabs'     => array(
241
-                    'registration_form_add_question_help_tab' => array(
242
-                        'title'    => esc_html__('Add Question', 'event_espresso'),
243
-                        'filename' => 'registration_form_add_question',
244
-                    ),
245
-                ),
246
-                'help_tour'     => array('Registration_Form_Add_Question_Help_Tour'),
247
-                'require_nonce' => false,
248
-            ),
249
-
250
-            'add_question_group' => array(
251
-                'nav'           => array(
252
-                    'label'      => esc_html__('Add Question Group', 'event_espresso'),
253
-                    'order'      => 5,
254
-                    'persistent' => false,
255
-                ),
256
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
257
-                'help_tabs'     => array(
258
-                    'registration_form_add_question_group_help_tab' => array(
259
-                        'title'    => esc_html__('Add Question Group', 'event_espresso'),
260
-                        'filename' => 'registration_form_add_question_group',
261
-                    ),
262
-                ),
263
-                'help_tour'     => array('Registration_Form_Add_Question_Group_Help_Tour'),
264
-                'require_nonce' => false,
265
-            ),
266
-
267
-            'edit_question_group' => array(
268
-                'nav'           => array(
269
-                    'label'      => esc_html__('Edit Question Group', 'event_espresso'),
270
-                    'order'      => 5,
271
-                    'persistent' => false,
272
-                    'url'        => isset($this->_req_data['question_group_id']) ? add_query_arg(array('question_group_id' => $this->_req_data['question_group_id']),
273
-                        $this->_current_page_view_url) : $this->_admin_base_url,
274
-                ),
275
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
276
-                'help_tabs'     => array(
277
-                    'registration_form_edit_question_group_help_tab' => array(
278
-                        'title'    => esc_html__('Edit Question Group', 'event_espresso'),
279
-                        'filename' => 'registration_form_edit_question_group',
280
-                    ),
281
-                ),
282
-                'help_tour'     => array('Registration_Form_Edit_Question_Group_Help_Tour'),
283
-                'require_nonce' => false,
284
-            ),
285
-
286
-            'view_reg_form_settings' => array(
287
-                'nav'           => array(
288
-                    'label' => esc_html__('Reg Form Settings', 'event_espresso'),
289
-                    'order' => 40,
290
-                ),
291
-                'labels'        => array(
292
-                    'publishbox' => esc_html__('Update Settings', 'event_espresso'),
293
-                ),
294
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
295
-                'help_tabs'     => array(
296
-                    'registration_form_reg_form_settings_help_tab' => array(
297
-                        'title'    => esc_html__('Registration Form Settings', 'event_espresso'),
298
-                        'filename' => 'registration_form_reg_form_settings',
299
-                    ),
300
-                ),
301
-                'help_tour'     => array('Registration_Form_Settings_Help_Tour'),
302
-                'require_nonce' => false,
303
-            ),
304
-
305
-        );
306
-        $this->_page_config = array_merge($this->_page_config, $new_page_config);
307
-
308
-        //change the list table we're going to use so it's the NEW list table!
309
-        $this->_page_config['default']['list_table'] = 'Extend_Registration_Form_Questions_Admin_List_Table';
310
-
311
-
312
-        //additional labels
313
-        $new_labels               = array(
314
-            'add_question'          => esc_html__('Add New Question', 'event_espresso'),
315
-            'delete_question'       => esc_html__('Delete Question', 'event_espresso'),
316
-            'add_question_group'    => esc_html__('Add New Question Group', 'event_espresso'),
317
-            'edit_question_group'   => esc_html__('Edit Question Group', 'event_espresso'),
318
-            'delete_question_group' => esc_html__('Delete Question Group', 'event_espresso'),
319
-        );
320
-        $this->_labels['buttons'] = array_merge($this->_labels['buttons'], $new_labels);
321
-
322
-    }
323
-
324
-
325
-    protected function _ajax_hooks()
326
-    {
327
-        add_action('wp_ajax_espresso_update_question_group_order', array($this, 'update_question_group_order'));
328
-    }
329
-
330
-
331
-    public function load_scripts_styles_question_groups()
332
-    {
333
-        wp_enqueue_script('espresso_ajax_table_sorting');
334
-    }
335
-
336
-
337
-    public function load_scripts_styles_add_question_group()
338
-    {
339
-        $this->load_scripts_styles_forms();
340
-        $this->load_sortable_question_script();
341
-    }
342
-
343
-    public function load_scripts_styles_edit_question_group()
344
-    {
345
-        $this->load_scripts_styles_forms();
346
-        $this->load_sortable_question_script();
347
-    }
348
-
349
-
350
-    /**
351
-     * registers and enqueues script for questions
352
-     *
353
-     * @return void
354
-     */
355
-    public function load_sortable_question_script()
356
-    {
357
-        wp_register_script('ee-question-sortable', REGISTRATION_FORM_CAF_ASSETS_URL . 'ee_question_order.js',
358
-            array('jquery-ui-sortable'), EVENT_ESPRESSO_VERSION, true);
359
-        wp_enqueue_script('ee-question-sortable');
360
-    }
361
-
362
-
363
-    protected function _set_list_table_views_default()
364
-    {
365
-        $this->_views = array(
366
-            'all' => array(
367
-                'slug'        => 'all',
368
-                'label'       => esc_html__('View All Questions', 'event_espresso'),
369
-                'count'       => 0,
370
-                'bulk_action' => array(
371
-                    'trash_questions' => esc_html__('Trash', 'event_espresso'),
372
-                ),
373
-            ),
374
-        );
375
-
376
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_questions',
377
-            'espresso_registration_form_trash_questions')
378
-        ) {
379
-            $this->_views['trash'] = array(
380
-                'slug'        => 'trash',
381
-                'label'       => esc_html__('Trash', 'event_espresso'),
382
-                'count'       => 0,
383
-                'bulk_action' => array(
384
-                    'delete_questions'  => esc_html__('Delete Permanently', 'event_espresso'),
385
-                    'restore_questions' => esc_html__('Restore', 'event_espresso'),
386
-                ),
387
-            );
388
-        }
389
-    }
390
-
391
-
392
-    protected function _set_list_table_views_question_groups()
393
-    {
394
-        $this->_views = array(
395
-            'all' => array(
396
-                'slug'        => 'all',
397
-                'label'       => esc_html__('All', 'event_espresso'),
398
-                'count'       => 0,
399
-                'bulk_action' => array(
400
-                    'trash_question_groups' => esc_html__('Trash', 'event_espresso'),
401
-                ),
402
-            ),
403
-        );
404
-
405
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_question_groups',
406
-            'espresso_registration_form_trash_question_groups')
407
-        ) {
408
-            $this->_views['trash'] = array(
409
-                'slug'        => 'trash',
410
-                'label'       => esc_html__('Trash', 'event_espresso'),
411
-                'count'       => 0,
412
-                'bulk_action' => array(
413
-                    'delete_question_groups'  => esc_html__('Delete Permanently', 'event_espresso'),
414
-                    'restore_question_groups' => esc_html__('Restore', 'event_espresso'),
415
-                ),
416
-            );
417
-        }
418
-    }
419
-
420
-
421
-    protected function _questions_overview_list_table()
422
-    {
423
-        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
424
-                'add_question',
425
-                'add_question',
426
-                array(),
427
-                'add-new-h2'
428
-            );
429
-        parent::_questions_overview_list_table();
430
-    }
431
-
432
-
433
-    protected function _question_groups_overview_list_table()
434
-    {
435
-        $this->_search_btn_label = esc_html__('Question Groups', 'event_espresso');
436
-        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
437
-                'add_question_group',
438
-                'add_question_group',
439
-                array(),
440
-                'add-new-h2'
441
-            );
442
-        $this->display_admin_list_table_page_with_sidebar();
443
-    }
444
-
445
-
446
-    protected function _delete_question()
447
-    {
448
-        $success = $this->_delete_items($this->_question_model);
449
-        $this->_redirect_after_action(
450
-            $success,
451
-            $this->_question_model->item_name($success),
452
-            'deleted',
453
-            array('action' => 'default', 'status' => 'all')
454
-        );
455
-    }
456
-
457
-
458
-    protected function _delete_questions()
459
-    {
460
-        $success = $this->_delete_items($this->_question_model);
461
-        $this->_redirect_after_action(
462
-            $success,
463
-            $this->_question_model->item_name($success),
464
-            'deleted permanently',
465
-            array('action' => 'default', 'status' => 'trash')
466
-        );
467
-    }
468
-
469
-
470
-    /**
471
-     * Performs the deletion of a single or multiple questions or question groups.
472
-     *
473
-     * @param EEM_Soft_Delete_Base $model
474
-     * @return int number of items deleted permanently
475
-     */
476
-    private function _delete_items(EEM_Soft_Delete_Base $model)
477
-    {
478
-        $success = 0;
479
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
480
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
481
-            // if array has more than one element than success message should be plural
482
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
483
-            // cycle thru bulk action checkboxes
484
-            while (list($ID, $value) = each($this->_req_data['checkbox'])) {
485
-                if (! $this->_delete_item($ID, $model)) {
486
-                    $success = 0;
487
-                }
488
-            }
489
-
490
-        } elseif (! empty($this->_req_data['QSG_ID'])) {
491
-            $success = $this->_delete_item($this->_req_data['QSG_ID'], $model);
492
-
493
-        } elseif (! empty($this->_req_data['QST_ID'])) {
494
-            $success = $this->_delete_item($this->_req_data['QST_ID'], $model);
495
-        } else {
496
-            EE_Error::add_error(sprintf(esc_html__("No Questions or Question Groups were selected for deleting. This error usually shows when you've attempted to delete via bulk action but there were no selections.",
497
-                "event_espresso")), __FILE__, __FUNCTION__, __LINE__);
498
-        }
499
-        return $success;
500
-    }
501
-
502
-    /**
503
-     * Deletes the specified question (and its associated question options) or question group
504
-     *
505
-     * @param int                  $id
506
-     * @param EEM_Soft_Delete_Base $model
507
-     * @return boolean
508
-     */
509
-    protected function _delete_item($id, $model)
510
-    {
511
-        if ($model instanceof EEM_Question) {
512
-            EEM_Question_Option::instance()->delete_permanently(array(array('QST_ID' => absint($id))));
513
-        }
514
-        return $model->delete_permanently_by_ID(absint($id));
515
-    }
516
-
517
-
518
-    /******************************    QUESTION GROUPS    ******************************/
519
-
520
-
521
-    protected function _edit_question_group($type = 'add')
522
-    {
523
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
524
-        $ID = isset($this->_req_data['QSG_ID']) && ! empty($this->_req_data['QSG_ID']) ? absint($this->_req_data['QSG_ID']) : false;
525
-
526
-        switch ($this->_req_action) {
527
-            case 'add_question_group' :
528
-                $this->_admin_page_title = esc_html__('Add Question Group', 'event_espresso');
529
-                break;
530
-            case 'edit_question_group' :
531
-                $this->_admin_page_title = esc_html__('Edit Question Group', 'event_espresso');
532
-                break;
533
-            default :
534
-                $this->_admin_page_title = ucwords(str_replace('_', ' ', $this->_req_action));
535
-        }
536
-        // add ID to title if editing
537
-        $this->_admin_page_title = $ID ? $this->_admin_page_title . ' # ' . $ID : $this->_admin_page_title;
538
-        if ($ID) {
539
-            /** @var EE_Question_Group $questionGroup */
540
-            $questionGroup            = $this->_question_group_model->get_one_by_ID($ID);
541
-            $additional_hidden_fields = array('QSG_ID' => array('type' => 'hidden', 'value' => $ID));
542
-            $this->_set_add_edit_form_tags('update_question_group', $additional_hidden_fields);
543
-        } else {
544
-            /** @var EE_Question_Group $questionGroup */
545
-            $questionGroup = EEM_Question_Group::instance()->create_default_object();
546
-            $questionGroup->set_order_to_latest();
547
-            $this->_set_add_edit_form_tags('insert_question_group');
548
-        }
549
-        $this->_template_args['values']         = $this->_yes_no_values;
550
-        $this->_template_args['all_questions']  = $questionGroup->questions_in_and_not_in_group();
551
-        $this->_template_args['QSG_ID']         = $ID ? $ID : true;
552
-        $this->_template_args['question_group'] = $questionGroup;
553
-
554
-        $redirect_URL = add_query_arg(array('action' => 'question_groups'), $this->_admin_base_url);
555
-        $this->_set_publish_post_box_vars('id', $ID, false, $redirect_URL);
556
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(REGISTRATION_FORM_CAF_TEMPLATE_PATH . 'question_groups_main_meta_box.template.php',
557
-            $this->_template_args, true);
558
-
559
-        // the details template wrapper
560
-        $this->display_admin_page_with_sidebar();
561
-    }
562
-
563
-
564
-    protected function _delete_question_groups()
565
-    {
566
-        $success = $this->_delete_items($this->_question_group_model);
567
-        $this->_redirect_after_action($success, $this->_question_group_model->item_name($success),
568
-            'deleted permanently', array('action' => 'question_groups', 'status' => 'trash'));
569
-    }
570
-
571
-
572
-    /**
573
-     * @param bool $new_question_group
574
-     */
575
-    protected function _insert_or_update_question_group($new_question_group = true)
576
-    {
577
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
578
-        $set_column_values = $this->_set_column_values_for($this->_question_group_model);
579
-        if ($new_question_group) {
580
-            $QSG_ID  = $this->_question_group_model->insert($set_column_values);
581
-            $success = $QSG_ID ? 1 : 0;
582
-        } else {
583
-            $QSG_ID = absint($this->_req_data['QSG_ID']);
584
-            unset($set_column_values['QSG_ID']);
585
-            $success = $this->_question_group_model->update($set_column_values, array(array('QSG_ID' => $QSG_ID)));
586
-        }
587
-        $phone_question_id = EEM_Question::instance()->get_Question_ID_from_system_string(EEM_Attendee::system_question_phone);
588
-        // update the existing related questions
589
-        // BUT FIRST...  delete the phone question from the Question_Group_Question if it is being added to this question group (therefore removed from the existing group)
590
-        if (isset($this->_req_data['questions'], $this->_req_data['questions'][$phone_question_id])) {
591
-            // delete where QST ID = system phone question ID and Question Group ID is NOT this group
592
-            EEM_Question_Group_Question::instance()->delete(array(
593
-                array(
594
-                    'QST_ID' => $phone_question_id,
595
-                    'QSG_ID' => array('!=', $QSG_ID),
596
-                ),
597
-            ));
598
-        }
599
-        /** @type EE_Question_Group $question_group */
600
-        $question_group = $this->_question_group_model->get_one_by_ID($QSG_ID);
601
-        $questions      = $question_group->questions();
602
-        // make sure system phone question is added to list of questions for this group
603
-        if (! isset($questions[$phone_question_id])) {
604
-            $questions[$phone_question_id] = EEM_Question::instance()->get_one_by_ID($phone_question_id);
605
-        }
606
-
607
-        foreach ($questions as $question_ID => $question) {
608
-            // first we always check for order.
609
-            if (! empty($this->_req_data['question_orders'][$question_ID])) {
610
-                //update question order
611
-                $question_group->update_question_order($question_ID, $this->_req_data['question_orders'][$question_ID]);
612
-            }
613
-
614
-            // then we always check if adding or removing.
615
-            if (isset($this->_req_data['questions'], $this->_req_data['questions'][$question_ID])) {
616
-                $question_group->add_question($question_ID);
617
-            } else {
618
-                // not found, remove it (but only if not a system question for the personal group with the exception of lname system question - we allow removal of it)
619
-                if (
620
-                in_array(
621
-                    $question->system_ID(),
622
-                    EEM_Question::instance()->required_system_questions_in_system_question_group($question_group->system_group())
623
-                )
624
-                ) {
625
-                    continue;
626
-                } else {
627
-                    $question_group->remove_question($question_ID);
628
-                }
629
-            }
630
-        }
631
-        // save new related questions
632
-        if (isset($this->_req_data['questions'])) {
633
-            foreach ($this->_req_data['questions'] as $QST_ID) {
634
-                $question_group->add_question($QST_ID);
635
-                if (isset($this->_req_data['question_orders'][$QST_ID])) {
636
-                    $question_group->update_question_order($QST_ID, $this->_req_data['question_orders'][$QST_ID]);
637
-                }
638
-            }
639
-        }
640
-
641
-        if ($success !== false) {
642
-            $msg = $new_question_group ? sprintf(esc_html__('The %s has been created', 'event_espresso'),
643
-                $this->_question_group_model->item_name()) : sprintf(esc_html__('The %s has been updated',
644
-                'event_espresso'), $this->_question_group_model->item_name());
645
-            EE_Error::add_success($msg);
646
-        }
647
-        $this->_redirect_after_action(false, '', '', array('action' => 'edit_question_group', 'QSG_ID' => $QSG_ID),
648
-            true);
649
-
650
-    }
651
-
652
-    /**
653
-     * duplicates a question and all its question options and redirects to the new question.
654
-     */
655
-    public function _duplicate_question()
656
-    {
657
-        $question_ID = (int)$this->_req_data['QST_ID'];
658
-        $question    = EEM_Question::instance()->get_one_by_ID($question_ID);
659
-        if ($question instanceof EE_Question) {
660
-            $new_question = $question->duplicate();
661
-            if ($new_question instanceof EE_Question) {
662
-                $this->_redirect_after_action(true, esc_html__('Question', 'event_espresso'),
663
-                    esc_html__('Duplicated', 'event_espresso'),
664
-                    array('action' => 'edit_question', 'QST_ID' => $new_question->ID()), true);
665
-            } else {
666
-                global $wpdb;
667
-                EE_Error::add_error(sprintf(esc_html__('Could not duplicate question with ID %1$d because: %2$s',
668
-                    'event_espresso'), $question_ID, $wpdb->last_error), __FILE__, __FUNCTION__, __LINE__);
669
-                $this->_redirect_after_action(false, '', '', array('action' => 'default'), false);
670
-            }
671
-        } else {
672
-            EE_Error::add_error(sprintf(esc_html__('Could not duplicate question with ID %d because it didn\'t exist!',
673
-                'event_espresso'), $question_ID), __FILE__, __FUNCTION__, __LINE__);
674
-            $this->_redirect_after_action(false, '', '', array('action' => 'default'), false);
675
-        }
676
-    }
677
-
678
-
679
-    /**
680
-     * @param bool $trash
681
-     */
682
-    protected function _trash_or_restore_question_groups($trash = true)
683
-    {
684
-        $this->_trash_or_restore_items($this->_question_group_model, $trash);
685
-    }
686
-
687
-
688
-    /**
689
-     *_trash_question
690
-     */
691
-    protected function _trash_question()
692
-    {
693
-        $success    = $this->_question_model->delete_by_ID((int)$this->_req_data['QST_ID']);
694
-        $query_args = array('action' => 'default', 'status' => 'all');
695
-        $this->_redirect_after_action($success, $this->_question_model->item_name($success), 'trashed', $query_args);
696
-    }
697
-
698
-
699
-    /**
700
-     * @param bool $trash
701
-     */
702
-    protected function _trash_or_restore_questions($trash = true)
703
-    {
704
-        $this->_trash_or_restore_items($this->_question_model, $trash);
705
-    }
706
-
707
-
708
-    /**
709
-     * Internally used to delete or restore items, using the request data. Meant to be
710
-     * flexible between question or question groups
711
-     *
712
-     * @param EEM_Soft_Delete_Base $model
713
-     * @param boolean              $trash whether to trash or restore
714
-     */
715
-    private function _trash_or_restore_items(EEM_Soft_Delete_Base $model, $trash = true)
716
-    {
717
-
718
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
719
-
720
-        $success = 1;
721
-        //Checkboxes
722
-        //echo "trash $trash";
723
-        //var_dump($this->_req_data['checkbox']);die;
724
-        if (isset($this->_req_data['checkbox'])) {
725
-            if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
726
-                // if array has more than one element than success message should be plural
727
-                $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
728
-                // cycle thru bulk action checkboxes
729
-                while (list($ID, $value) = each($this->_req_data['checkbox'])) {
730
-                    if (! $model->delete_or_restore_by_ID($trash, absint($ID))) {
731
-                        $success = 0;
732
-                    }
733
-                }
734
-
735
-            } else {
736
-                // grab single id and delete
737
-                $ID = absint($this->_req_data['checkbox']);
738
-                if (! $model->delete_or_restore_by_ID($trash, $ID)) {
739
-                    $success = 0;
740
-                }
741
-            }
742
-
743
-        } else {
744
-            // delete via trash link
745
-            // grab single id and delete
746
-            $ID = absint($this->_req_data[$model->primary_key_name()]);
747
-            if (! $model->delete_or_restore_by_ID($trash, $ID)) {
748
-                $success = 0;
749
-            }
750
-
751
-        }
752
-
753
-
754
-        $action = $model instanceof EEM_Question ? 'default' : 'question_groups';//strtolower( $model->item_name(2) );
755
-        //echo "action :$action";
756
-        //$action = 'questions' ? 'default' : $action;
757
-        if ($trash) {
758
-            $action_desc = 'trashed';
759
-            $status      = 'trash';
760
-        } else {
761
-            $action_desc = 'restored';
762
-            $status      = 'all';
763
-        }
764
-        $this->_redirect_after_action($success, $model->item_name($success), $action_desc,
765
-            array('action' => $action, 'status' => $status));
766
-    }
767
-
768
-
769
-    /**
770
-     * @param            $per_page
771
-     * @param int        $current_page
772
-     * @param bool|false $count
773
-     * @return \EE_Soft_Delete_Base_Class[]|int
774
-     */
775
-    public function get_trashed_questions($per_page, $current_page = 1, $count = false)
776
-    {
777
-        $query_params = $this->get_query_params(EEM_Question::instance(), $per_page, $current_page);
778
-
779
-        if ($count) {
780
-            //note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
781
-            $where   = isset($query_params[0]) ? array($query_params[0]) : array();
782
-            $results = $this->_question_model->count_deleted($where);
783
-        } else {
784
-            //note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
785
-            $results = $this->_question_model->get_all_deleted($query_params);
786
-        }
787
-        return $results;
788
-    }
789
-
790
-
791
-    /**
792
-     * @param            $per_page
793
-     * @param int        $current_page
794
-     * @param bool|false $count
795
-     * @return \EE_Soft_Delete_Base_Class[]
796
-     */
797
-    public function get_question_groups($per_page, $current_page = 1, $count = false)
798
-    {
799
-        $questionGroupModel = EEM_Question_Group::instance();
800
-        $query_params       = $this->get_query_params($questionGroupModel, $per_page, $current_page);
801
-        if ($count) {
802
-            $where   = isset($query_params[0]) ? array($query_params[0]) : array();
803
-            $results = $questionGroupModel->count($where);
804
-        } else {
805
-            $results = $questionGroupModel->get_all($query_params);
806
-        }
807
-        return $results;
808
-    }
809
-
810
-
811
-    /**
812
-     * @param      $per_page
813
-     * @param int  $current_page
814
-     * @param bool $count
815
-     * @return \EE_Soft_Delete_Base_Class[]|int
816
-     */
817
-    public function get_trashed_question_groups($per_page, $current_page = 1, $count = false)
818
-    {
819
-        $questionGroupModel = EEM_Question_Group::instance();
820
-        $query_params       = $this->get_query_params($questionGroupModel, $per_page, $current_page);
821
-        if ($count) {
822
-            $where                 = isset($query_params[0]) ? array($query_params[0]) : array();
823
-            $query_params['limit'] = null;
824
-            $results               = $questionGroupModel->count_deleted($where);
825
-        } else {
826
-            $results = $questionGroupModel->get_all_deleted($query_params);
827
-        }
828
-        return $results;
829
-    }
830
-
831
-
832
-    /**
833
-     * method for performing updates to question order
834
-     *
835
-     * @return array results array
836
-     */
837
-    public function update_question_group_order()
838
-    {
839
-
840
-        $success = esc_html__('Question group order was updated successfully.', 'event_espresso');
841
-
842
-        // grab our row IDs
843
-        $row_ids = isset($this->_req_data['row_ids']) && ! empty($this->_req_data['row_ids'])
844
-            ? explode(',', rtrim($this->_req_data['row_ids'], ','))
845
-            : array();
846
-
847
-        $perpage = ! empty($this->_req_data['perpage'])
848
-            ? (int)$this->_req_data['perpage']
849
-            : null;
850
-        $curpage = ! empty($this->_req_data['curpage'])
851
-            ? (int)$this->_req_data['curpage']
852
-            : null;
853
-
854
-        if (! empty($row_ids)) {
855
-            //figure out where we start the row_id count at for the current page.
856
-            $qsgcount = empty($curpage) ? 0 : ($curpage - 1) * $perpage;
857
-
858
-            $row_count = count($row_ids);
859
-            for ($i = 0; $i < $row_count; $i++) {
860
-                //Update the questions when re-ordering
861
-                $updated = EEM_Question_Group::instance()->update(
862
-                    array('QSG_order' => $qsgcount),
863
-                    array(array('QSG_ID' => $row_ids[$i]))
864
-                );
865
-                if ($updated === false) {
866
-                    $success = false;
867
-                }
868
-                $qsgcount++;
869
-            }
870
-        } else {
871
-            $success = false;
872
-        }
873
-
874
-        $errors = ! $success
875
-            ? esc_html__('An error occurred. The question group order was not updated.', 'event_espresso')
876
-            : false;
877
-
878
-        echo wp_json_encode(array('return_data' => false, 'success' => $success, 'errors' => $errors));
879
-        die();
880
-
881
-    }
882
-
883
-
884
-
885
-    /***************************************        REGISTRATION SETTINGS        ***************************************/
886
-
887
-
888
-    /**
889
-     * _reg_form_settings
890
-     *
891
-     * @throws \EE_Error
892
-     */
893
-    protected function _reg_form_settings()
894
-    {
895
-        $this->_template_args['values'] = $this->_yes_no_values;
896
-        add_action(
897
-            'AHEE__Extend_Registration_Form_Admin_Page___reg_form_settings_template',
898
-            array($this, 'email_validation_settings_form'),
899
-            2
900
-        );
901
-        $this->_template_args = (array)apply_filters(
902
-            'FHEE__Extend_Registration_Form_Admin_Page___reg_form_settings___template_args',
903
-            $this->_template_args
904
-        );
905
-        $this->_set_add_edit_form_tags('update_reg_form_settings');
906
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
907
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
908
-            REGISTRATION_FORM_CAF_TEMPLATE_PATH . 'reg_form_settings.template.php',
909
-            $this->_template_args,
910
-            true
911
-        );
912
-        $this->display_admin_page_with_sidebar();
913
-    }
914
-
915
-
916
-    /**
917
-     * _update_reg_form_settings
918
-     */
919
-    protected function _update_reg_form_settings()
920
-    {
921
-        EE_Registry::instance()->CFG->registration = $this->update_email_validation_settings_form(
922
-            EE_Registry::instance()->CFG->registration
923
-        );
924
-        EE_Registry::instance()->CFG->registration = apply_filters(
925
-            'FHEE__Extend_Registration_Form_Admin_Page___update_reg_form_settings__CFG_registration',
926
-            EE_Registry::instance()->CFG->registration
927
-        );
928
-        $success                                   = $this->_update_espresso_configuration(
929
-            esc_html__('Registration Form Options', 'event_espresso'),
930
-            EE_Registry::instance()->CFG,
931
-            __FILE__, __FUNCTION__, __LINE__
932
-        );
933
-        $this->_redirect_after_action($success, esc_html__('Registration Form Options', 'event_espresso'), 'updated',
934
-            array('action' => 'view_reg_form_settings'));
935
-    }
936
-
937
-
938
-    /**
939
-     * email_validation_settings_form
940
-     *
941
-     * @access    public
942
-     * @return    void
943
-     * @throws \EE_Error
944
-     */
945
-    public function email_validation_settings_form()
946
-    {
947
-        echo $this->_email_validation_settings_form()->get_html();
948
-    }
949
-
950
-
951
-    /**
952
-     * _email_validation_settings_form
953
-     *
954
-     * @access protected
955
-     * @return EE_Form_Section_Proper
956
-     * @throws \EE_Error
957
-     */
958
-    protected function _email_validation_settings_form()
959
-    {
960
-        return new EE_Form_Section_Proper(
961
-            array(
962
-                'name'            => 'email_validation_settings',
963
-                'html_id'         => 'email_validation_settings',
964
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
965
-                'subsections'     => apply_filters(
966
-                    'FHEE__Extend_Registration_Form_Admin_Page___email_validation_settings_form__form_subsections',
967
-                    array(
968
-                        'email_validation_hdr'   => new EE_Form_Section_HTML(
969
-                            EEH_HTML::h2(esc_html__('Email Validation Settings', 'event_espresso'))
970
-                        ),
971
-                        'email_validation_level' => new EE_Select_Input(
972
-                            array(
973
-                                'basic'      => esc_html__('Basic', 'event_espresso'),
974
-                                'wp_default' => esc_html__('WordPress Default', 'event_espresso'),
975
-                                'i18n'       => esc_html__('International', 'event_espresso'),
976
-                                'i18n_dns'   => esc_html__('International + DNS Check', 'event_espresso'),
977
-                            ),
978
-                            array(
979
-                                'html_label_text' => esc_html__('Email Validation Level', 'event_espresso')
980
-                                                     . EEH_Template::get_help_tab_link('email_validation_info'),
981
-                                'html_help_text'  => esc_html__('These levels range from basic validation ( ie: [email protected] ) to more advanced checks against international email addresses (ie: üñîçøðé@example.com ) with additional MX and A record checks to confirm the domain actually exists. More information on on each level can be found within the help section.',
982
-                                    'event_espresso'),
983
-                                'default'         => isset(EE_Registry::instance()->CFG->registration->email_validation_level)
984
-                                    ? EE_Registry::instance()->CFG->registration->email_validation_level
985
-                                    : 'wp_default',
986
-                                'required'        => false,
987
-                            )
988
-                        ),
989
-                    )
990
-                ),
991
-            )
992
-        );
993
-    }
994
-
995
-
996
-    /**
997
-     * update_email_validation_settings_form
998
-     *
999
-     * @access    public
1000
-     * @param \EE_Registration_Config $EE_Registration_Config
1001
-     * @return \EE_Registration_Config
1002
-     */
1003
-    public function update_email_validation_settings_form(EE_Registration_Config $EE_Registration_Config)
1004
-    {
1005
-        $prev_email_validation_level = $EE_Registration_Config->email_validation_level;
1006
-        try {
1007
-            $email_validation_settings_form = $this->_email_validation_settings_form();
1008
-            // if not displaying a form, then check for form submission
1009
-            if ($email_validation_settings_form->was_submitted()) {
1010
-                // capture form data
1011
-                $email_validation_settings_form->receive_form_submission();
1012
-                // validate form data
1013
-                if ($email_validation_settings_form->is_valid()) {
1014
-                    // grab validated data from form
1015
-                    $valid_data = $email_validation_settings_form->valid_data();
1016
-                    if (isset($valid_data['email_validation_level'])) {
1017
-                        $email_validation_level = $valid_data['email_validation_level'];
1018
-                        // now if they want to use international email addresses
1019
-                        if ($email_validation_level === 'i18n' || $email_validation_level === 'i18n_dns') {
1020
-                            // in case we need to reset their email validation level,
1021
-                            // make sure that the previous value wasn't already set to one of the i18n options.
1022
-                            if ($prev_email_validation_level === 'i18n' || $prev_email_validation_level === 'i18n_dns') {
1023
-                                // if so, then reset it back to "basic" since that is the only other option that,
1024
-                                // despite offering poor validation, supports i18n email addresses
1025
-                                $prev_email_validation_level = 'basic';
1026
-                            }
1027
-                            // confirm our i18n email validation will work on the server
1028
-                            if (! $this->_verify_pcre_support($EE_Registration_Config, $email_validation_level)) {
1029
-                                // or reset email validation level to previous value
1030
-                                $email_validation_level = $prev_email_validation_level;
1031
-                            }
1032
-                        }
1033
-                        $EE_Registration_Config->email_validation_level = $email_validation_level;
1034
-                    } else {
1035
-                        EE_Error::add_error(
1036
-                            esc_html__(
1037
-                                'Invalid or missing Email Validation settings. Please refresh the form and try again.',
1038
-                                'event_espresso'
1039
-                            ),
1040
-                            __FILE__, __FUNCTION__, __LINE__
1041
-                        );
1042
-                    }
1043
-                } else {
1044
-                    if ($email_validation_settings_form->submission_error_message() !== '') {
1045
-                        EE_Error::add_error(
1046
-                            $email_validation_settings_form->submission_error_message(),
1047
-                            __FILE__, __FUNCTION__, __LINE__
1048
-                        );
1049
-                    }
1050
-                }
1051
-            }
1052
-        } catch (EE_Error $e) {
1053
-            $e->get_error();
1054
-        }
1055
-        return $EE_Registration_Config;
1056
-    }
1057
-
1058
-
1059
-    /**
1060
-     * confirms that the server's PHP version has the PCRE module enabled,
1061
-     * and that the PCRE version works with our i18n email validation
1062
-     *
1063
-     * @param \EE_Registration_Config $EE_Registration_Config
1064
-     * @param string                  $email_validation_level
1065
-     * @return bool
1066
-     */
1067
-    private function _verify_pcre_support(EE_Registration_Config $EE_Registration_Config, $email_validation_level)
1068
-    {
1069
-        // first check that PCRE is enabled
1070
-        if (! defined('PREG_BAD_UTF8_ERROR')) {
1071
-            EE_Error::add_error(
1072
-                sprintf(
1073
-                    esc_html__(
1074
-                        'We\'re sorry, but it appears that your server\'s version of PHP was not compiled with PCRE unicode support.%1$sPlease contact your hosting company and ask them whether the PCRE compiled with your version of PHP on your server can be been built with the "--enable-unicode-properties" and "--enable-utf8" configuration switches to enable more complex regex expressions.%1$sIf they are unable, or unwilling to do so, then your server will not support international email addresses using UTF-8 unicode characters. This means you will either have to lower your email validation level to "Basic" or "WordPress Default", or switch to a hosting company that has/can enable PCRE unicode support on the server.',
1075
-                        'event_espresso'
1076
-                    ),
1077
-                    '<br />'
1078
-                ),
1079
-                __FILE__,
1080
-                __FUNCTION__,
1081
-                __LINE__
1082
-            );
1083
-            return false;
1084
-        } else {
1085
-            // PCRE support is enabled, but let's still
1086
-            // perform a test to see if the server will support it.
1087
-            // but first, save the updated validation level to the config,
1088
-            // so that the validation strategy picks it up.
1089
-            // this will get bumped back down if it doesn't work
1090
-            $EE_Registration_Config->email_validation_level = $email_validation_level;
1091
-            try {
1092
-                $email_validator    = new EE_Email_Validation_Strategy();
1093
-                $i18n_email_address = apply_filters(
1094
-                    'FHEE__Extend_Registration_Form_Admin_Page__update_email_validation_settings_form__i18n_email_address',
1095
-                    'jägerjü[email protected]'
1096
-                );
1097
-                $email_validator->validate($i18n_email_address);
1098
-            } catch (Exception $e) {
1099
-                EE_Error::add_error(
1100
-                    sprintf(
1101
-                        esc_html__(
1102
-                            'We\'re sorry, but it appears that your server\'s configuration will not support the "International" or "International + DNS Check" email validation levels.%1$sTo correct this issue, please consult with your hosting company regarding your server\'s PCRE settings.%1$sIt is recommended that your PHP version be configured to use PCRE 8.10 or newer.%1$sMore information regarding PCRE versions and installation can be found here: %2$s',
1103
-                            'event_espresso'
1104
-                        ),
1105
-                        '<br />',
1106
-                        '<a href="http://php.net/manual/en/pcre.installation.php" target="_blank">http://php.net/manual/en/pcre.installation.php</a>'
1107
-                    ),
1108
-                    __FILE__, __FUNCTION__, __LINE__
1109
-                );
1110
-                return false;
1111
-            }
1112
-        }
1113
-        return true;
1114
-    }
28
+	/**
29
+	 * @Constructor
30
+	 * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
31
+	 * @access public
32
+	 */
33
+	public function __construct($routing = true)
34
+	{
35
+		define('REGISTRATION_FORM_CAF_ADMIN', EE_CORE_CAF_ADMIN_EXTEND . 'registration_form' . DS);
36
+		define('REGISTRATION_FORM_CAF_ASSETS_PATH', REGISTRATION_FORM_CAF_ADMIN . 'assets' . DS);
37
+		define('REGISTRATION_FORM_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'registration_form/assets/');
38
+		define('REGISTRATION_FORM_CAF_TEMPLATE_PATH', REGISTRATION_FORM_CAF_ADMIN . 'templates' . DS);
39
+		define('REGISTRATION_FORM_CAF_TEMPLATE_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'registration_form/templates/');
40
+		parent::__construct($routing);
41
+	}
42
+
43
+
44
+	protected function _extend_page_config()
45
+	{
46
+		$this->_admin_base_path = REGISTRATION_FORM_CAF_ADMIN;
47
+		$qst_id = ! empty($this->_req_data['QST_ID']) && ! is_array($this->_req_data['QST_ID']) ? $this->_req_data['QST_ID'] : 0;
48
+		$qsg_id = ! empty($this->_req_data['QSG_ID']) && ! is_array($this->_req_data['QSG_ID']) ? $this->_req_data['QSG_ID'] : 0;
49
+
50
+		$new_page_routes    = array(
51
+			'question_groups'    => array(
52
+				'func'       => '_question_groups_overview_list_table',
53
+				'capability' => 'ee_read_question_groups',
54
+			),
55
+			'add_question'       => array(
56
+				'func'       => '_edit_question',
57
+				'capability' => 'ee_edit_questions',
58
+			),
59
+			'insert_question'    => array(
60
+				'func'       => '_insert_or_update_question',
61
+				'args'       => array('new_question' => true),
62
+				'capability' => 'ee_edit_questions',
63
+				'noheader'   => true,
64
+			),
65
+			'duplicate_question' => array(
66
+				'func'       => '_duplicate_question',
67
+				'capability' => 'ee_edit_questions',
68
+				'noheader'   => true,
69
+			),
70
+			'trash_question'     => array(
71
+				'func'       => '_trash_question',
72
+				'capability' => 'ee_delete_question',
73
+				'obj_id'     => $qst_id,
74
+				'noheader'   => true,
75
+			),
76
+
77
+			'restore_question' => array(
78
+				'func'       => '_trash_or_restore_questions',
79
+				'capability' => 'ee_delete_question',
80
+				'obj_id'     => $qst_id,
81
+				'args'       => array('trash' => false),
82
+				'noheader'   => true,
83
+			),
84
+
85
+			'delete_question' => array(
86
+				'func'       => '_delete_question',
87
+				'capability' => 'ee_delete_question',
88
+				'obj_id'     => $qst_id,
89
+				'noheader'   => true,
90
+			),
91
+
92
+			'trash_questions' => array(
93
+				'func'       => '_trash_or_restore_questions',
94
+				'capability' => 'ee_delete_questions',
95
+				'args'       => array('trash' => true),
96
+				'noheader'   => true,
97
+			),
98
+
99
+			'restore_questions' => array(
100
+				'func'       => '_trash_or_restore_questions',
101
+				'capability' => 'ee_delete_questions',
102
+				'args'       => array('trash' => false),
103
+				'noheader'   => true,
104
+			),
105
+
106
+			'delete_questions' => array(
107
+				'func'       => '_delete_questions',
108
+				'args'       => array(),
109
+				'capability' => 'ee_delete_questions',
110
+				'noheader'   => true,
111
+			),
112
+
113
+			'add_question_group' => array(
114
+				'func'       => '_edit_question_group',
115
+				'capability' => 'ee_edit_question_groups',
116
+			),
117
+
118
+			'edit_question_group' => array(
119
+				'func'       => '_edit_question_group',
120
+				'capability' => 'ee_edit_question_group',
121
+				'obj_id'     => $qsg_id,
122
+				'args'       => array('edit'),
123
+			),
124
+
125
+			'delete_question_groups' => array(
126
+				'func'       => '_delete_question_groups',
127
+				'capability' => 'ee_delete_question_groups',
128
+				'noheader'   => true,
129
+			),
130
+
131
+			'delete_question_group' => array(
132
+				'func'       => '_delete_question_groups',
133
+				'capability' => 'ee_delete_question_group',
134
+				'obj_id'     => $qsg_id,
135
+				'noheader'   => true,
136
+			),
137
+
138
+			'trash_question_group' => array(
139
+				'func'       => '_trash_or_restore_question_groups',
140
+				'args'       => array('trash' => true),
141
+				'capability' => 'ee_delete_question_group',
142
+				'obj_id'     => $qsg_id,
143
+				'noheader'   => true,
144
+			),
145
+
146
+			'restore_question_group' => array(
147
+				'func'       => '_trash_or_restore_question_groups',
148
+				'args'       => array('trash' => false),
149
+				'capability' => 'ee_delete_question_group',
150
+				'obj_id'     => $qsg_id,
151
+				'noheader'   => true,
152
+			),
153
+
154
+			'insert_question_group' => array(
155
+				'func'       => '_insert_or_update_question_group',
156
+				'args'       => array('new_question_group' => true),
157
+				'capability' => 'ee_edit_question_groups',
158
+				'noheader'   => true,
159
+			),
160
+
161
+			'update_question_group' => array(
162
+				'func'       => '_insert_or_update_question_group',
163
+				'args'       => array('new_question_group' => false),
164
+				'capability' => 'ee_edit_question_group',
165
+				'obj_id'     => $qsg_id,
166
+				'noheader'   => true,
167
+			),
168
+
169
+			'trash_question_groups' => array(
170
+				'func'       => '_trash_or_restore_question_groups',
171
+				'args'       => array('trash' => true),
172
+				'capability' => 'ee_delete_question_groups',
173
+				'noheader'   => array('trash' => false),
174
+			),
175
+
176
+			'restore_question_groups' => array(
177
+				'func'       => '_trash_or_restore_question_groups',
178
+				'args'       => array('trash' => false),
179
+				'capability' => 'ee_delete_question_groups',
180
+				'noheader'   => true,
181
+			),
182
+
183
+
184
+			'espresso_update_question_group_order' => array(
185
+				'func'       => 'update_question_group_order',
186
+				'capability' => 'ee_edit_question_groups',
187
+				'noheader'   => true,
188
+			),
189
+
190
+			'view_reg_form_settings' => array(
191
+				'func'       => '_reg_form_settings',
192
+				'capability' => 'manage_options',
193
+			),
194
+
195
+			'update_reg_form_settings' => array(
196
+				'func'       => '_update_reg_form_settings',
197
+				'capability' => 'manage_options',
198
+				'noheader'   => true,
199
+			),
200
+		);
201
+		$this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
202
+
203
+		$new_page_config    = array(
204
+
205
+			'question_groups' => array(
206
+				'nav'           => array(
207
+					'label' => esc_html__('Question Groups', 'event_espresso'),
208
+					'order' => 20,
209
+				),
210
+				'list_table'    => 'Registration_Form_Question_Groups_Admin_List_Table',
211
+				'help_tabs'     => array(
212
+					'registration_form_question_groups_help_tab'                           => array(
213
+						'title'    => esc_html__('Question Groups', 'event_espresso'),
214
+						'filename' => 'registration_form_question_groups',
215
+					),
216
+					'registration_form_question_groups_table_column_headings_help_tab'     => array(
217
+						'title'    => esc_html__('Question Groups Table Column Headings', 'event_espresso'),
218
+						'filename' => 'registration_form_question_groups_table_column_headings',
219
+					),
220
+					'registration_form_question_groups_views_bulk_actions_search_help_tab' => array(
221
+						'title'    => esc_html__('Question Groups Views & Bulk Actions & Search', 'event_espresso'),
222
+						'filename' => 'registration_form_question_groups_views_bulk_actions_search',
223
+					),
224
+				),
225
+				'help_tour'     => array('Registration_Form_Question_Groups_Help_Tour'),
226
+				'metaboxes'     => $this->_default_espresso_metaboxes,
227
+				'require_nonce' => false,
228
+				'qtips'         => array(
229
+					'EE_Registration_Form_Tips',
230
+				),
231
+			),
232
+
233
+			'add_question' => array(
234
+				'nav'           => array(
235
+					'label'      => esc_html__('Add Question', 'event_espresso'),
236
+					'order'      => 5,
237
+					'persistent' => false,
238
+				),
239
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
240
+				'help_tabs'     => array(
241
+					'registration_form_add_question_help_tab' => array(
242
+						'title'    => esc_html__('Add Question', 'event_espresso'),
243
+						'filename' => 'registration_form_add_question',
244
+					),
245
+				),
246
+				'help_tour'     => array('Registration_Form_Add_Question_Help_Tour'),
247
+				'require_nonce' => false,
248
+			),
249
+
250
+			'add_question_group' => array(
251
+				'nav'           => array(
252
+					'label'      => esc_html__('Add Question Group', 'event_espresso'),
253
+					'order'      => 5,
254
+					'persistent' => false,
255
+				),
256
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
257
+				'help_tabs'     => array(
258
+					'registration_form_add_question_group_help_tab' => array(
259
+						'title'    => esc_html__('Add Question Group', 'event_espresso'),
260
+						'filename' => 'registration_form_add_question_group',
261
+					),
262
+				),
263
+				'help_tour'     => array('Registration_Form_Add_Question_Group_Help_Tour'),
264
+				'require_nonce' => false,
265
+			),
266
+
267
+			'edit_question_group' => array(
268
+				'nav'           => array(
269
+					'label'      => esc_html__('Edit Question Group', 'event_espresso'),
270
+					'order'      => 5,
271
+					'persistent' => false,
272
+					'url'        => isset($this->_req_data['question_group_id']) ? add_query_arg(array('question_group_id' => $this->_req_data['question_group_id']),
273
+						$this->_current_page_view_url) : $this->_admin_base_url,
274
+				),
275
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
276
+				'help_tabs'     => array(
277
+					'registration_form_edit_question_group_help_tab' => array(
278
+						'title'    => esc_html__('Edit Question Group', 'event_espresso'),
279
+						'filename' => 'registration_form_edit_question_group',
280
+					),
281
+				),
282
+				'help_tour'     => array('Registration_Form_Edit_Question_Group_Help_Tour'),
283
+				'require_nonce' => false,
284
+			),
285
+
286
+			'view_reg_form_settings' => array(
287
+				'nav'           => array(
288
+					'label' => esc_html__('Reg Form Settings', 'event_espresso'),
289
+					'order' => 40,
290
+				),
291
+				'labels'        => array(
292
+					'publishbox' => esc_html__('Update Settings', 'event_espresso'),
293
+				),
294
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
295
+				'help_tabs'     => array(
296
+					'registration_form_reg_form_settings_help_tab' => array(
297
+						'title'    => esc_html__('Registration Form Settings', 'event_espresso'),
298
+						'filename' => 'registration_form_reg_form_settings',
299
+					),
300
+				),
301
+				'help_tour'     => array('Registration_Form_Settings_Help_Tour'),
302
+				'require_nonce' => false,
303
+			),
304
+
305
+		);
306
+		$this->_page_config = array_merge($this->_page_config, $new_page_config);
307
+
308
+		//change the list table we're going to use so it's the NEW list table!
309
+		$this->_page_config['default']['list_table'] = 'Extend_Registration_Form_Questions_Admin_List_Table';
310
+
311
+
312
+		//additional labels
313
+		$new_labels               = array(
314
+			'add_question'          => esc_html__('Add New Question', 'event_espresso'),
315
+			'delete_question'       => esc_html__('Delete Question', 'event_espresso'),
316
+			'add_question_group'    => esc_html__('Add New Question Group', 'event_espresso'),
317
+			'edit_question_group'   => esc_html__('Edit Question Group', 'event_espresso'),
318
+			'delete_question_group' => esc_html__('Delete Question Group', 'event_espresso'),
319
+		);
320
+		$this->_labels['buttons'] = array_merge($this->_labels['buttons'], $new_labels);
321
+
322
+	}
323
+
324
+
325
+	protected function _ajax_hooks()
326
+	{
327
+		add_action('wp_ajax_espresso_update_question_group_order', array($this, 'update_question_group_order'));
328
+	}
329
+
330
+
331
+	public function load_scripts_styles_question_groups()
332
+	{
333
+		wp_enqueue_script('espresso_ajax_table_sorting');
334
+	}
335
+
336
+
337
+	public function load_scripts_styles_add_question_group()
338
+	{
339
+		$this->load_scripts_styles_forms();
340
+		$this->load_sortable_question_script();
341
+	}
342
+
343
+	public function load_scripts_styles_edit_question_group()
344
+	{
345
+		$this->load_scripts_styles_forms();
346
+		$this->load_sortable_question_script();
347
+	}
348
+
349
+
350
+	/**
351
+	 * registers and enqueues script for questions
352
+	 *
353
+	 * @return void
354
+	 */
355
+	public function load_sortable_question_script()
356
+	{
357
+		wp_register_script('ee-question-sortable', REGISTRATION_FORM_CAF_ASSETS_URL . 'ee_question_order.js',
358
+			array('jquery-ui-sortable'), EVENT_ESPRESSO_VERSION, true);
359
+		wp_enqueue_script('ee-question-sortable');
360
+	}
361
+
362
+
363
+	protected function _set_list_table_views_default()
364
+	{
365
+		$this->_views = array(
366
+			'all' => array(
367
+				'slug'        => 'all',
368
+				'label'       => esc_html__('View All Questions', 'event_espresso'),
369
+				'count'       => 0,
370
+				'bulk_action' => array(
371
+					'trash_questions' => esc_html__('Trash', 'event_espresso'),
372
+				),
373
+			),
374
+		);
375
+
376
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_questions',
377
+			'espresso_registration_form_trash_questions')
378
+		) {
379
+			$this->_views['trash'] = array(
380
+				'slug'        => 'trash',
381
+				'label'       => esc_html__('Trash', 'event_espresso'),
382
+				'count'       => 0,
383
+				'bulk_action' => array(
384
+					'delete_questions'  => esc_html__('Delete Permanently', 'event_espresso'),
385
+					'restore_questions' => esc_html__('Restore', 'event_espresso'),
386
+				),
387
+			);
388
+		}
389
+	}
390
+
391
+
392
+	protected function _set_list_table_views_question_groups()
393
+	{
394
+		$this->_views = array(
395
+			'all' => array(
396
+				'slug'        => 'all',
397
+				'label'       => esc_html__('All', 'event_espresso'),
398
+				'count'       => 0,
399
+				'bulk_action' => array(
400
+					'trash_question_groups' => esc_html__('Trash', 'event_espresso'),
401
+				),
402
+			),
403
+		);
404
+
405
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_question_groups',
406
+			'espresso_registration_form_trash_question_groups')
407
+		) {
408
+			$this->_views['trash'] = array(
409
+				'slug'        => 'trash',
410
+				'label'       => esc_html__('Trash', 'event_espresso'),
411
+				'count'       => 0,
412
+				'bulk_action' => array(
413
+					'delete_question_groups'  => esc_html__('Delete Permanently', 'event_espresso'),
414
+					'restore_question_groups' => esc_html__('Restore', 'event_espresso'),
415
+				),
416
+			);
417
+		}
418
+	}
419
+
420
+
421
+	protected function _questions_overview_list_table()
422
+	{
423
+		$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
424
+				'add_question',
425
+				'add_question',
426
+				array(),
427
+				'add-new-h2'
428
+			);
429
+		parent::_questions_overview_list_table();
430
+	}
431
+
432
+
433
+	protected function _question_groups_overview_list_table()
434
+	{
435
+		$this->_search_btn_label = esc_html__('Question Groups', 'event_espresso');
436
+		$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
437
+				'add_question_group',
438
+				'add_question_group',
439
+				array(),
440
+				'add-new-h2'
441
+			);
442
+		$this->display_admin_list_table_page_with_sidebar();
443
+	}
444
+
445
+
446
+	protected function _delete_question()
447
+	{
448
+		$success = $this->_delete_items($this->_question_model);
449
+		$this->_redirect_after_action(
450
+			$success,
451
+			$this->_question_model->item_name($success),
452
+			'deleted',
453
+			array('action' => 'default', 'status' => 'all')
454
+		);
455
+	}
456
+
457
+
458
+	protected function _delete_questions()
459
+	{
460
+		$success = $this->_delete_items($this->_question_model);
461
+		$this->_redirect_after_action(
462
+			$success,
463
+			$this->_question_model->item_name($success),
464
+			'deleted permanently',
465
+			array('action' => 'default', 'status' => 'trash')
466
+		);
467
+	}
468
+
469
+
470
+	/**
471
+	 * Performs the deletion of a single or multiple questions or question groups.
472
+	 *
473
+	 * @param EEM_Soft_Delete_Base $model
474
+	 * @return int number of items deleted permanently
475
+	 */
476
+	private function _delete_items(EEM_Soft_Delete_Base $model)
477
+	{
478
+		$success = 0;
479
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
480
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
481
+			// if array has more than one element than success message should be plural
482
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
483
+			// cycle thru bulk action checkboxes
484
+			while (list($ID, $value) = each($this->_req_data['checkbox'])) {
485
+				if (! $this->_delete_item($ID, $model)) {
486
+					$success = 0;
487
+				}
488
+			}
489
+
490
+		} elseif (! empty($this->_req_data['QSG_ID'])) {
491
+			$success = $this->_delete_item($this->_req_data['QSG_ID'], $model);
492
+
493
+		} elseif (! empty($this->_req_data['QST_ID'])) {
494
+			$success = $this->_delete_item($this->_req_data['QST_ID'], $model);
495
+		} else {
496
+			EE_Error::add_error(sprintf(esc_html__("No Questions or Question Groups were selected for deleting. This error usually shows when you've attempted to delete via bulk action but there were no selections.",
497
+				"event_espresso")), __FILE__, __FUNCTION__, __LINE__);
498
+		}
499
+		return $success;
500
+	}
501
+
502
+	/**
503
+	 * Deletes the specified question (and its associated question options) or question group
504
+	 *
505
+	 * @param int                  $id
506
+	 * @param EEM_Soft_Delete_Base $model
507
+	 * @return boolean
508
+	 */
509
+	protected function _delete_item($id, $model)
510
+	{
511
+		if ($model instanceof EEM_Question) {
512
+			EEM_Question_Option::instance()->delete_permanently(array(array('QST_ID' => absint($id))));
513
+		}
514
+		return $model->delete_permanently_by_ID(absint($id));
515
+	}
516
+
517
+
518
+	/******************************    QUESTION GROUPS    ******************************/
519
+
520
+
521
+	protected function _edit_question_group($type = 'add')
522
+	{
523
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
524
+		$ID = isset($this->_req_data['QSG_ID']) && ! empty($this->_req_data['QSG_ID']) ? absint($this->_req_data['QSG_ID']) : false;
525
+
526
+		switch ($this->_req_action) {
527
+			case 'add_question_group' :
528
+				$this->_admin_page_title = esc_html__('Add Question Group', 'event_espresso');
529
+				break;
530
+			case 'edit_question_group' :
531
+				$this->_admin_page_title = esc_html__('Edit Question Group', 'event_espresso');
532
+				break;
533
+			default :
534
+				$this->_admin_page_title = ucwords(str_replace('_', ' ', $this->_req_action));
535
+		}
536
+		// add ID to title if editing
537
+		$this->_admin_page_title = $ID ? $this->_admin_page_title . ' # ' . $ID : $this->_admin_page_title;
538
+		if ($ID) {
539
+			/** @var EE_Question_Group $questionGroup */
540
+			$questionGroup            = $this->_question_group_model->get_one_by_ID($ID);
541
+			$additional_hidden_fields = array('QSG_ID' => array('type' => 'hidden', 'value' => $ID));
542
+			$this->_set_add_edit_form_tags('update_question_group', $additional_hidden_fields);
543
+		} else {
544
+			/** @var EE_Question_Group $questionGroup */
545
+			$questionGroup = EEM_Question_Group::instance()->create_default_object();
546
+			$questionGroup->set_order_to_latest();
547
+			$this->_set_add_edit_form_tags('insert_question_group');
548
+		}
549
+		$this->_template_args['values']         = $this->_yes_no_values;
550
+		$this->_template_args['all_questions']  = $questionGroup->questions_in_and_not_in_group();
551
+		$this->_template_args['QSG_ID']         = $ID ? $ID : true;
552
+		$this->_template_args['question_group'] = $questionGroup;
553
+
554
+		$redirect_URL = add_query_arg(array('action' => 'question_groups'), $this->_admin_base_url);
555
+		$this->_set_publish_post_box_vars('id', $ID, false, $redirect_URL);
556
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(REGISTRATION_FORM_CAF_TEMPLATE_PATH . 'question_groups_main_meta_box.template.php',
557
+			$this->_template_args, true);
558
+
559
+		// the details template wrapper
560
+		$this->display_admin_page_with_sidebar();
561
+	}
562
+
563
+
564
+	protected function _delete_question_groups()
565
+	{
566
+		$success = $this->_delete_items($this->_question_group_model);
567
+		$this->_redirect_after_action($success, $this->_question_group_model->item_name($success),
568
+			'deleted permanently', array('action' => 'question_groups', 'status' => 'trash'));
569
+	}
570
+
571
+
572
+	/**
573
+	 * @param bool $new_question_group
574
+	 */
575
+	protected function _insert_or_update_question_group($new_question_group = true)
576
+	{
577
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
578
+		$set_column_values = $this->_set_column_values_for($this->_question_group_model);
579
+		if ($new_question_group) {
580
+			$QSG_ID  = $this->_question_group_model->insert($set_column_values);
581
+			$success = $QSG_ID ? 1 : 0;
582
+		} else {
583
+			$QSG_ID = absint($this->_req_data['QSG_ID']);
584
+			unset($set_column_values['QSG_ID']);
585
+			$success = $this->_question_group_model->update($set_column_values, array(array('QSG_ID' => $QSG_ID)));
586
+		}
587
+		$phone_question_id = EEM_Question::instance()->get_Question_ID_from_system_string(EEM_Attendee::system_question_phone);
588
+		// update the existing related questions
589
+		// BUT FIRST...  delete the phone question from the Question_Group_Question if it is being added to this question group (therefore removed from the existing group)
590
+		if (isset($this->_req_data['questions'], $this->_req_data['questions'][$phone_question_id])) {
591
+			// delete where QST ID = system phone question ID and Question Group ID is NOT this group
592
+			EEM_Question_Group_Question::instance()->delete(array(
593
+				array(
594
+					'QST_ID' => $phone_question_id,
595
+					'QSG_ID' => array('!=', $QSG_ID),
596
+				),
597
+			));
598
+		}
599
+		/** @type EE_Question_Group $question_group */
600
+		$question_group = $this->_question_group_model->get_one_by_ID($QSG_ID);
601
+		$questions      = $question_group->questions();
602
+		// make sure system phone question is added to list of questions for this group
603
+		if (! isset($questions[$phone_question_id])) {
604
+			$questions[$phone_question_id] = EEM_Question::instance()->get_one_by_ID($phone_question_id);
605
+		}
606
+
607
+		foreach ($questions as $question_ID => $question) {
608
+			// first we always check for order.
609
+			if (! empty($this->_req_data['question_orders'][$question_ID])) {
610
+				//update question order
611
+				$question_group->update_question_order($question_ID, $this->_req_data['question_orders'][$question_ID]);
612
+			}
613
+
614
+			// then we always check if adding or removing.
615
+			if (isset($this->_req_data['questions'], $this->_req_data['questions'][$question_ID])) {
616
+				$question_group->add_question($question_ID);
617
+			} else {
618
+				// not found, remove it (but only if not a system question for the personal group with the exception of lname system question - we allow removal of it)
619
+				if (
620
+				in_array(
621
+					$question->system_ID(),
622
+					EEM_Question::instance()->required_system_questions_in_system_question_group($question_group->system_group())
623
+				)
624
+				) {
625
+					continue;
626
+				} else {
627
+					$question_group->remove_question($question_ID);
628
+				}
629
+			}
630
+		}
631
+		// save new related questions
632
+		if (isset($this->_req_data['questions'])) {
633
+			foreach ($this->_req_data['questions'] as $QST_ID) {
634
+				$question_group->add_question($QST_ID);
635
+				if (isset($this->_req_data['question_orders'][$QST_ID])) {
636
+					$question_group->update_question_order($QST_ID, $this->_req_data['question_orders'][$QST_ID]);
637
+				}
638
+			}
639
+		}
640
+
641
+		if ($success !== false) {
642
+			$msg = $new_question_group ? sprintf(esc_html__('The %s has been created', 'event_espresso'),
643
+				$this->_question_group_model->item_name()) : sprintf(esc_html__('The %s has been updated',
644
+				'event_espresso'), $this->_question_group_model->item_name());
645
+			EE_Error::add_success($msg);
646
+		}
647
+		$this->_redirect_after_action(false, '', '', array('action' => 'edit_question_group', 'QSG_ID' => $QSG_ID),
648
+			true);
649
+
650
+	}
651
+
652
+	/**
653
+	 * duplicates a question and all its question options and redirects to the new question.
654
+	 */
655
+	public function _duplicate_question()
656
+	{
657
+		$question_ID = (int)$this->_req_data['QST_ID'];
658
+		$question    = EEM_Question::instance()->get_one_by_ID($question_ID);
659
+		if ($question instanceof EE_Question) {
660
+			$new_question = $question->duplicate();
661
+			if ($new_question instanceof EE_Question) {
662
+				$this->_redirect_after_action(true, esc_html__('Question', 'event_espresso'),
663
+					esc_html__('Duplicated', 'event_espresso'),
664
+					array('action' => 'edit_question', 'QST_ID' => $new_question->ID()), true);
665
+			} else {
666
+				global $wpdb;
667
+				EE_Error::add_error(sprintf(esc_html__('Could not duplicate question with ID %1$d because: %2$s',
668
+					'event_espresso'), $question_ID, $wpdb->last_error), __FILE__, __FUNCTION__, __LINE__);
669
+				$this->_redirect_after_action(false, '', '', array('action' => 'default'), false);
670
+			}
671
+		} else {
672
+			EE_Error::add_error(sprintf(esc_html__('Could not duplicate question with ID %d because it didn\'t exist!',
673
+				'event_espresso'), $question_ID), __FILE__, __FUNCTION__, __LINE__);
674
+			$this->_redirect_after_action(false, '', '', array('action' => 'default'), false);
675
+		}
676
+	}
677
+
678
+
679
+	/**
680
+	 * @param bool $trash
681
+	 */
682
+	protected function _trash_or_restore_question_groups($trash = true)
683
+	{
684
+		$this->_trash_or_restore_items($this->_question_group_model, $trash);
685
+	}
686
+
687
+
688
+	/**
689
+	 *_trash_question
690
+	 */
691
+	protected function _trash_question()
692
+	{
693
+		$success    = $this->_question_model->delete_by_ID((int)$this->_req_data['QST_ID']);
694
+		$query_args = array('action' => 'default', 'status' => 'all');
695
+		$this->_redirect_after_action($success, $this->_question_model->item_name($success), 'trashed', $query_args);
696
+	}
697
+
698
+
699
+	/**
700
+	 * @param bool $trash
701
+	 */
702
+	protected function _trash_or_restore_questions($trash = true)
703
+	{
704
+		$this->_trash_or_restore_items($this->_question_model, $trash);
705
+	}
706
+
707
+
708
+	/**
709
+	 * Internally used to delete or restore items, using the request data. Meant to be
710
+	 * flexible between question or question groups
711
+	 *
712
+	 * @param EEM_Soft_Delete_Base $model
713
+	 * @param boolean              $trash whether to trash or restore
714
+	 */
715
+	private function _trash_or_restore_items(EEM_Soft_Delete_Base $model, $trash = true)
716
+	{
717
+
718
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
719
+
720
+		$success = 1;
721
+		//Checkboxes
722
+		//echo "trash $trash";
723
+		//var_dump($this->_req_data['checkbox']);die;
724
+		if (isset($this->_req_data['checkbox'])) {
725
+			if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
726
+				// if array has more than one element than success message should be plural
727
+				$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
728
+				// cycle thru bulk action checkboxes
729
+				while (list($ID, $value) = each($this->_req_data['checkbox'])) {
730
+					if (! $model->delete_or_restore_by_ID($trash, absint($ID))) {
731
+						$success = 0;
732
+					}
733
+				}
734
+
735
+			} else {
736
+				// grab single id and delete
737
+				$ID = absint($this->_req_data['checkbox']);
738
+				if (! $model->delete_or_restore_by_ID($trash, $ID)) {
739
+					$success = 0;
740
+				}
741
+			}
742
+
743
+		} else {
744
+			// delete via trash link
745
+			// grab single id and delete
746
+			$ID = absint($this->_req_data[$model->primary_key_name()]);
747
+			if (! $model->delete_or_restore_by_ID($trash, $ID)) {
748
+				$success = 0;
749
+			}
750
+
751
+		}
752
+
753
+
754
+		$action = $model instanceof EEM_Question ? 'default' : 'question_groups';//strtolower( $model->item_name(2) );
755
+		//echo "action :$action";
756
+		//$action = 'questions' ? 'default' : $action;
757
+		if ($trash) {
758
+			$action_desc = 'trashed';
759
+			$status      = 'trash';
760
+		} else {
761
+			$action_desc = 'restored';
762
+			$status      = 'all';
763
+		}
764
+		$this->_redirect_after_action($success, $model->item_name($success), $action_desc,
765
+			array('action' => $action, 'status' => $status));
766
+	}
767
+
768
+
769
+	/**
770
+	 * @param            $per_page
771
+	 * @param int        $current_page
772
+	 * @param bool|false $count
773
+	 * @return \EE_Soft_Delete_Base_Class[]|int
774
+	 */
775
+	public function get_trashed_questions($per_page, $current_page = 1, $count = false)
776
+	{
777
+		$query_params = $this->get_query_params(EEM_Question::instance(), $per_page, $current_page);
778
+
779
+		if ($count) {
780
+			//note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
781
+			$where   = isset($query_params[0]) ? array($query_params[0]) : array();
782
+			$results = $this->_question_model->count_deleted($where);
783
+		} else {
784
+			//note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
785
+			$results = $this->_question_model->get_all_deleted($query_params);
786
+		}
787
+		return $results;
788
+	}
789
+
790
+
791
+	/**
792
+	 * @param            $per_page
793
+	 * @param int        $current_page
794
+	 * @param bool|false $count
795
+	 * @return \EE_Soft_Delete_Base_Class[]
796
+	 */
797
+	public function get_question_groups($per_page, $current_page = 1, $count = false)
798
+	{
799
+		$questionGroupModel = EEM_Question_Group::instance();
800
+		$query_params       = $this->get_query_params($questionGroupModel, $per_page, $current_page);
801
+		if ($count) {
802
+			$where   = isset($query_params[0]) ? array($query_params[0]) : array();
803
+			$results = $questionGroupModel->count($where);
804
+		} else {
805
+			$results = $questionGroupModel->get_all($query_params);
806
+		}
807
+		return $results;
808
+	}
809
+
810
+
811
+	/**
812
+	 * @param      $per_page
813
+	 * @param int  $current_page
814
+	 * @param bool $count
815
+	 * @return \EE_Soft_Delete_Base_Class[]|int
816
+	 */
817
+	public function get_trashed_question_groups($per_page, $current_page = 1, $count = false)
818
+	{
819
+		$questionGroupModel = EEM_Question_Group::instance();
820
+		$query_params       = $this->get_query_params($questionGroupModel, $per_page, $current_page);
821
+		if ($count) {
822
+			$where                 = isset($query_params[0]) ? array($query_params[0]) : array();
823
+			$query_params['limit'] = null;
824
+			$results               = $questionGroupModel->count_deleted($where);
825
+		} else {
826
+			$results = $questionGroupModel->get_all_deleted($query_params);
827
+		}
828
+		return $results;
829
+	}
830
+
831
+
832
+	/**
833
+	 * method for performing updates to question order
834
+	 *
835
+	 * @return array results array
836
+	 */
837
+	public function update_question_group_order()
838
+	{
839
+
840
+		$success = esc_html__('Question group order was updated successfully.', 'event_espresso');
841
+
842
+		// grab our row IDs
843
+		$row_ids = isset($this->_req_data['row_ids']) && ! empty($this->_req_data['row_ids'])
844
+			? explode(',', rtrim($this->_req_data['row_ids'], ','))
845
+			: array();
846
+
847
+		$perpage = ! empty($this->_req_data['perpage'])
848
+			? (int)$this->_req_data['perpage']
849
+			: null;
850
+		$curpage = ! empty($this->_req_data['curpage'])
851
+			? (int)$this->_req_data['curpage']
852
+			: null;
853
+
854
+		if (! empty($row_ids)) {
855
+			//figure out where we start the row_id count at for the current page.
856
+			$qsgcount = empty($curpage) ? 0 : ($curpage - 1) * $perpage;
857
+
858
+			$row_count = count($row_ids);
859
+			for ($i = 0; $i < $row_count; $i++) {
860
+				//Update the questions when re-ordering
861
+				$updated = EEM_Question_Group::instance()->update(
862
+					array('QSG_order' => $qsgcount),
863
+					array(array('QSG_ID' => $row_ids[$i]))
864
+				);
865
+				if ($updated === false) {
866
+					$success = false;
867
+				}
868
+				$qsgcount++;
869
+			}
870
+		} else {
871
+			$success = false;
872
+		}
873
+
874
+		$errors = ! $success
875
+			? esc_html__('An error occurred. The question group order was not updated.', 'event_espresso')
876
+			: false;
877
+
878
+		echo wp_json_encode(array('return_data' => false, 'success' => $success, 'errors' => $errors));
879
+		die();
880
+
881
+	}
882
+
883
+
884
+
885
+	/***************************************        REGISTRATION SETTINGS        ***************************************/
886
+
887
+
888
+	/**
889
+	 * _reg_form_settings
890
+	 *
891
+	 * @throws \EE_Error
892
+	 */
893
+	protected function _reg_form_settings()
894
+	{
895
+		$this->_template_args['values'] = $this->_yes_no_values;
896
+		add_action(
897
+			'AHEE__Extend_Registration_Form_Admin_Page___reg_form_settings_template',
898
+			array($this, 'email_validation_settings_form'),
899
+			2
900
+		);
901
+		$this->_template_args = (array)apply_filters(
902
+			'FHEE__Extend_Registration_Form_Admin_Page___reg_form_settings___template_args',
903
+			$this->_template_args
904
+		);
905
+		$this->_set_add_edit_form_tags('update_reg_form_settings');
906
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
907
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
908
+			REGISTRATION_FORM_CAF_TEMPLATE_PATH . 'reg_form_settings.template.php',
909
+			$this->_template_args,
910
+			true
911
+		);
912
+		$this->display_admin_page_with_sidebar();
913
+	}
914
+
915
+
916
+	/**
917
+	 * _update_reg_form_settings
918
+	 */
919
+	protected function _update_reg_form_settings()
920
+	{
921
+		EE_Registry::instance()->CFG->registration = $this->update_email_validation_settings_form(
922
+			EE_Registry::instance()->CFG->registration
923
+		);
924
+		EE_Registry::instance()->CFG->registration = apply_filters(
925
+			'FHEE__Extend_Registration_Form_Admin_Page___update_reg_form_settings__CFG_registration',
926
+			EE_Registry::instance()->CFG->registration
927
+		);
928
+		$success                                   = $this->_update_espresso_configuration(
929
+			esc_html__('Registration Form Options', 'event_espresso'),
930
+			EE_Registry::instance()->CFG,
931
+			__FILE__, __FUNCTION__, __LINE__
932
+		);
933
+		$this->_redirect_after_action($success, esc_html__('Registration Form Options', 'event_espresso'), 'updated',
934
+			array('action' => 'view_reg_form_settings'));
935
+	}
936
+
937
+
938
+	/**
939
+	 * email_validation_settings_form
940
+	 *
941
+	 * @access    public
942
+	 * @return    void
943
+	 * @throws \EE_Error
944
+	 */
945
+	public function email_validation_settings_form()
946
+	{
947
+		echo $this->_email_validation_settings_form()->get_html();
948
+	}
949
+
950
+
951
+	/**
952
+	 * _email_validation_settings_form
953
+	 *
954
+	 * @access protected
955
+	 * @return EE_Form_Section_Proper
956
+	 * @throws \EE_Error
957
+	 */
958
+	protected function _email_validation_settings_form()
959
+	{
960
+		return new EE_Form_Section_Proper(
961
+			array(
962
+				'name'            => 'email_validation_settings',
963
+				'html_id'         => 'email_validation_settings',
964
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
965
+				'subsections'     => apply_filters(
966
+					'FHEE__Extend_Registration_Form_Admin_Page___email_validation_settings_form__form_subsections',
967
+					array(
968
+						'email_validation_hdr'   => new EE_Form_Section_HTML(
969
+							EEH_HTML::h2(esc_html__('Email Validation Settings', 'event_espresso'))
970
+						),
971
+						'email_validation_level' => new EE_Select_Input(
972
+							array(
973
+								'basic'      => esc_html__('Basic', 'event_espresso'),
974
+								'wp_default' => esc_html__('WordPress Default', 'event_espresso'),
975
+								'i18n'       => esc_html__('International', 'event_espresso'),
976
+								'i18n_dns'   => esc_html__('International + DNS Check', 'event_espresso'),
977
+							),
978
+							array(
979
+								'html_label_text' => esc_html__('Email Validation Level', 'event_espresso')
980
+													 . EEH_Template::get_help_tab_link('email_validation_info'),
981
+								'html_help_text'  => esc_html__('These levels range from basic validation ( ie: [email protected] ) to more advanced checks against international email addresses (ie: üñîçøðé@example.com ) with additional MX and A record checks to confirm the domain actually exists. More information on on each level can be found within the help section.',
982
+									'event_espresso'),
983
+								'default'         => isset(EE_Registry::instance()->CFG->registration->email_validation_level)
984
+									? EE_Registry::instance()->CFG->registration->email_validation_level
985
+									: 'wp_default',
986
+								'required'        => false,
987
+							)
988
+						),
989
+					)
990
+				),
991
+			)
992
+		);
993
+	}
994
+
995
+
996
+	/**
997
+	 * update_email_validation_settings_form
998
+	 *
999
+	 * @access    public
1000
+	 * @param \EE_Registration_Config $EE_Registration_Config
1001
+	 * @return \EE_Registration_Config
1002
+	 */
1003
+	public function update_email_validation_settings_form(EE_Registration_Config $EE_Registration_Config)
1004
+	{
1005
+		$prev_email_validation_level = $EE_Registration_Config->email_validation_level;
1006
+		try {
1007
+			$email_validation_settings_form = $this->_email_validation_settings_form();
1008
+			// if not displaying a form, then check for form submission
1009
+			if ($email_validation_settings_form->was_submitted()) {
1010
+				// capture form data
1011
+				$email_validation_settings_form->receive_form_submission();
1012
+				// validate form data
1013
+				if ($email_validation_settings_form->is_valid()) {
1014
+					// grab validated data from form
1015
+					$valid_data = $email_validation_settings_form->valid_data();
1016
+					if (isset($valid_data['email_validation_level'])) {
1017
+						$email_validation_level = $valid_data['email_validation_level'];
1018
+						// now if they want to use international email addresses
1019
+						if ($email_validation_level === 'i18n' || $email_validation_level === 'i18n_dns') {
1020
+							// in case we need to reset their email validation level,
1021
+							// make sure that the previous value wasn't already set to one of the i18n options.
1022
+							if ($prev_email_validation_level === 'i18n' || $prev_email_validation_level === 'i18n_dns') {
1023
+								// if so, then reset it back to "basic" since that is the only other option that,
1024
+								// despite offering poor validation, supports i18n email addresses
1025
+								$prev_email_validation_level = 'basic';
1026
+							}
1027
+							// confirm our i18n email validation will work on the server
1028
+							if (! $this->_verify_pcre_support($EE_Registration_Config, $email_validation_level)) {
1029
+								// or reset email validation level to previous value
1030
+								$email_validation_level = $prev_email_validation_level;
1031
+							}
1032
+						}
1033
+						$EE_Registration_Config->email_validation_level = $email_validation_level;
1034
+					} else {
1035
+						EE_Error::add_error(
1036
+							esc_html__(
1037
+								'Invalid or missing Email Validation settings. Please refresh the form and try again.',
1038
+								'event_espresso'
1039
+							),
1040
+							__FILE__, __FUNCTION__, __LINE__
1041
+						);
1042
+					}
1043
+				} else {
1044
+					if ($email_validation_settings_form->submission_error_message() !== '') {
1045
+						EE_Error::add_error(
1046
+							$email_validation_settings_form->submission_error_message(),
1047
+							__FILE__, __FUNCTION__, __LINE__
1048
+						);
1049
+					}
1050
+				}
1051
+			}
1052
+		} catch (EE_Error $e) {
1053
+			$e->get_error();
1054
+		}
1055
+		return $EE_Registration_Config;
1056
+	}
1057
+
1058
+
1059
+	/**
1060
+	 * confirms that the server's PHP version has the PCRE module enabled,
1061
+	 * and that the PCRE version works with our i18n email validation
1062
+	 *
1063
+	 * @param \EE_Registration_Config $EE_Registration_Config
1064
+	 * @param string                  $email_validation_level
1065
+	 * @return bool
1066
+	 */
1067
+	private function _verify_pcre_support(EE_Registration_Config $EE_Registration_Config, $email_validation_level)
1068
+	{
1069
+		// first check that PCRE is enabled
1070
+		if (! defined('PREG_BAD_UTF8_ERROR')) {
1071
+			EE_Error::add_error(
1072
+				sprintf(
1073
+					esc_html__(
1074
+						'We\'re sorry, but it appears that your server\'s version of PHP was not compiled with PCRE unicode support.%1$sPlease contact your hosting company and ask them whether the PCRE compiled with your version of PHP on your server can be been built with the "--enable-unicode-properties" and "--enable-utf8" configuration switches to enable more complex regex expressions.%1$sIf they are unable, or unwilling to do so, then your server will not support international email addresses using UTF-8 unicode characters. This means you will either have to lower your email validation level to "Basic" or "WordPress Default", or switch to a hosting company that has/can enable PCRE unicode support on the server.',
1075
+						'event_espresso'
1076
+					),
1077
+					'<br />'
1078
+				),
1079
+				__FILE__,
1080
+				__FUNCTION__,
1081
+				__LINE__
1082
+			);
1083
+			return false;
1084
+		} else {
1085
+			// PCRE support is enabled, but let's still
1086
+			// perform a test to see if the server will support it.
1087
+			// but first, save the updated validation level to the config,
1088
+			// so that the validation strategy picks it up.
1089
+			// this will get bumped back down if it doesn't work
1090
+			$EE_Registration_Config->email_validation_level = $email_validation_level;
1091
+			try {
1092
+				$email_validator    = new EE_Email_Validation_Strategy();
1093
+				$i18n_email_address = apply_filters(
1094
+					'FHEE__Extend_Registration_Form_Admin_Page__update_email_validation_settings_form__i18n_email_address',
1095
+					'jägerjü[email protected]'
1096
+				);
1097
+				$email_validator->validate($i18n_email_address);
1098
+			} catch (Exception $e) {
1099
+				EE_Error::add_error(
1100
+					sprintf(
1101
+						esc_html__(
1102
+							'We\'re sorry, but it appears that your server\'s configuration will not support the "International" or "International + DNS Check" email validation levels.%1$sTo correct this issue, please consult with your hosting company regarding your server\'s PCRE settings.%1$sIt is recommended that your PHP version be configured to use PCRE 8.10 or newer.%1$sMore information regarding PCRE versions and installation can be found here: %2$s',
1103
+							'event_espresso'
1104
+						),
1105
+						'<br />',
1106
+						'<a href="http://php.net/manual/en/pcre.installation.php" target="_blank">http://php.net/manual/en/pcre.installation.php</a>'
1107
+					),
1108
+					__FILE__, __FUNCTION__, __LINE__
1109
+				);
1110
+				return false;
1111
+			}
1112
+		}
1113
+		return true;
1114
+	}
1115 1115
 
1116 1116
 
1117 1117
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/Model_Data_Translator.php 2 patches
Indentation   +521 added lines, -521 removed lines patch added patch discarded remove patch
@@ -2,7 +2,7 @@  discard block
 block discarded – undo
2 2
 namespace EventEspresso\core\libraries\rest_api;
3 3
 
4 4
 if (! defined('EVENT_ESPRESSO_VERSION')) {
5
-    exit('No direct script access allowed');
5
+	exit('No direct script access allowed');
6 6
 }
7 7
 
8 8
 
@@ -26,525 +26,525 @@  discard block
 block discarded – undo
26 26
 class Model_Data_Translator
27 27
 {
28 28
 
29
-    /**
30
-     * We used to use -1 for infinity in the rest api, but that's ambiguous for
31
-     * fields that COULD contain -1; so we use null
32
-     */
33
-    const ee_inf_in_rest = null;
34
-
35
-
36
-
37
-    /**
38
-     * Prepares a possible array of input values from JSON for use by the models
39
-     *
40
-     * @param \EE_Model_Field_Base $field_obj
41
-     * @param mixed                $original_value_maybe_array
42
-     * @param string               $requested_version
43
-     * @param string               $timezone_string treat values as being in this timezone
44
-     * @return mixed
45
-     * @throws \DomainException
46
-     */
47
-    public static function prepare_field_values_from_json(
48
-        $field_obj,
49
-        $original_value_maybe_array,
50
-        $requested_version,
51
-        $timezone_string = 'UTC'
52
-    ) {
53
-        if (is_array($original_value_maybe_array)) {
54
-            $new_value_maybe_array = array();
55
-            foreach ($original_value_maybe_array as $array_key => $array_item) {
56
-                $new_value_maybe_array[$array_key] = Model_Data_Translator::prepare_field_value_from_json(
57
-                    $field_obj,
58
-                    $array_item,
59
-                    $requested_version,
60
-                    $timezone_string
61
-                );
62
-            }
63
-        } else {
64
-            $new_value_maybe_array = Model_Data_Translator::prepare_field_value_from_json(
65
-                $field_obj,
66
-                $original_value_maybe_array,
67
-                $requested_version,
68
-                $timezone_string
69
-            );
70
-        }
71
-        return $new_value_maybe_array;
72
-    }
73
-
74
-
75
-
76
-    /**
77
-     * Prepares an array of field values FOR use in JSON/REST API
78
-     *
79
-     * @param \EE_Model_Field_Base $field_obj
80
-     * @param mixed                $original_value_maybe_array
81
-     * @param string               $request_version (eg 4.8.36)
82
-     * @return array
83
-     */
84
-    public static function prepare_field_values_for_json($field_obj, $original_value_maybe_array, $request_version)
85
-    {
86
-        if (is_array($original_value_maybe_array)) {
87
-            $new_value_maybe_array = array();
88
-            foreach ($original_value_maybe_array as $array_key => $array_item) {
89
-                $new_value_maybe_array[$array_key] = Model_Data_Translator::prepare_field_value_for_json(
90
-                    $field_obj,
91
-                    $array_item,
92
-                    $request_version
93
-                );
94
-            }
95
-        } else {
96
-            $new_value_maybe_array = Model_Data_Translator::prepare_field_value_for_json(
97
-                $field_obj,
98
-                $original_value_maybe_array,
99
-                $request_version
100
-            );
101
-        }
102
-        return $new_value_maybe_array;
103
-    }
104
-
105
-
106
-
107
-    /**
108
-     * Prepares incoming data from the json or $_REQUEST parameters for the models'
109
-     * "$query_params".
110
-     *
111
-     * @param \EE_Model_Field_Base $field_obj
112
-     * @param mixed                $original_value
113
-     * @param string               $requested_version
114
-     * @param string               $timezone_string treat values as being in this timezone
115
-     * @return mixed
116
-     * @throws \DomainException
117
-     */
118
-    public static function prepare_field_value_from_json(
119
-        $field_obj,
120
-        $original_value,
121
-        $requested_version,
122
-        $timezone_string = 'UTC' // UTC
123
-    )
124
-    {
125
-        $timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
126
-        $new_value = null;
127
-        if ($field_obj instanceof \EE_Infinite_Integer_Field
128
-            && in_array($original_value, array(null, ''), true)
129
-        ) {
130
-            $new_value = EE_INF;
131
-        } elseif ($field_obj instanceof \EE_Datetime_Field) {
132
-            list($offset_sign, $offset_secs) = Model_Data_Translator::parse_timezone_offset(
133
-                $field_obj->get_timezone_offset(
134
-                    new \DateTimeZone($timezone_string)
135
-                )
136
-            );
137
-            $offset_string =
138
-                str_pad(
139
-                    floor($offset_secs / HOUR_IN_SECONDS),
140
-                    2,
141
-                    '0',
142
-                    STR_PAD_LEFT
143
-                )
144
-                . ':'
145
-                . str_pad(
146
-                    ($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
147
-                    2,
148
-                    '0',
149
-                    STR_PAD_LEFT
150
-                );
151
-            $new_value = rest_parse_date($original_value . $offset_sign . $offset_string);
152
-        } else {
153
-            $new_value = $original_value;
154
-        }
155
-        return $new_value;
156
-    }
157
-
158
-
159
-
160
-    /**
161
-     * determines what's going on with them timezone strings
162
-     *
163
-     * @param int $timezone_offset
164
-     * @return array
165
-     */
166
-    private static function parse_timezone_offset($timezone_offset)
167
-    {
168
-        $first_char = substr((string)$timezone_offset, 0, 1);
169
-        if ($first_char === '+' || $first_char === '-') {
170
-            $offset_sign = $first_char;
171
-            $offset_secs = substr((string)$timezone_offset, 1);
172
-        } else {
173
-            $offset_sign = '+';
174
-            $offset_secs = $timezone_offset;
175
-        }
176
-        return array($offset_sign, $offset_secs);
177
-    }
178
-
179
-
180
-
181
-    /**
182
-     * Prepares a field's value for display in the API.
183
-     * The $original_value should be in the model object's domain of values, see the explanation at the top of EEM_Base.
184
-     * However, for backward compatibility, we also attempt to handle $original_values from the
185
-     * model client-code domain, and from the database domain.
186
-     * E.g., when working with EE_Datetime_Fields, $original_value should be a DateTime or DbSafeDateTime
187
-     * (model object domain). However, for backward compatibility, we also accept a unix timestamp
188
-     * (old model object domain), MySQL datetime string (database domain) or string formatted according to the
189
-     * WP Datetime format (model client-code domain)
190
-     *
191
-     * @param \EE_Model_Field_Base $field_obj
192
-     * @param mixed                $original_value
193
-     * @param string               $requested_version
194
-     * @return mixed
195
-     */
196
-    public static function prepare_field_value_for_json($field_obj, $original_value, $requested_version)
197
-    {
198
-        if ($original_value === EE_INF) {
199
-            $new_value = Model_Data_Translator::ee_inf_in_rest;
200
-        } elseif ($field_obj instanceof \EE_Datetime_Field) {
201
-            if (is_string($original_value)) {
202
-                //did they submit a string of a unix timestamp?
203
-                if (is_numeric($original_value)) {
204
-                    $datetime_obj = new \DateTime();
205
-                    $datetime_obj->setTimestamp((int)$original_value);
206
-                } else {
207
-                    //first, check if its a MySQL timestamp in GMT
208
-                    $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
209
-                }
210
-                if (! $datetime_obj instanceof \DateTime) {
211
-                    //so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
212
-                    $datetime_obj = $field_obj->prepare_for_set($original_value);
213
-                }
214
-                $original_value = $datetime_obj;
215
-            }
216
-            if ($original_value instanceof \DateTime) {
217
-                $new_value = $original_value->format('Y-m-d H:i:s');
218
-            } elseif (is_int($original_value)) {
219
-                $new_value = date('Y-m-d H:i:s', $original_value);
220
-            } elseif($original_value === null || $original_value === '') {
221
-                $new_value = null;
222
-            } else {
223
-                //so it's not a datetime object, unix timestamp (as string or int),
224
-                //MySQL timestamp, or even a string in the field object's format. So no idea what it is
225
-                throw new \EE_Error(
226
-                    sprintf(
227
-                        esc_html__(
228
-                            // @codingStandardsIgnoreStart
229
-                            'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
230
-                            // @codingStandardsIgnoreEnd
231
-                            'event_espressso'
232
-                        ),
233
-                        $original_value,
234
-                        $field_obj->get_name(),
235
-                        $field_obj->get_model_name(),
236
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
237
-                    )
238
-                );
239
-            }
240
-            $new_value = mysql_to_rfc3339($new_value);
241
-        } else {
242
-            $new_value = $original_value;
243
-        }
244
-        return apply_filters(
245
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
246
-            $new_value,
247
-            $field_obj,
248
-            $original_value,
249
-            $requested_version
250
-        );
251
-    }
252
-
253
-
254
-
255
-    /**
256
-     * Prepares condition-query-parameters (like what's in where and having) from
257
-     * the format expected in the API to use in the models
258
-     *
259
-     * @param array     $inputted_query_params_of_this_type
260
-     * @param \EEM_Base $model
261
-     * @param string    $requested_version
262
-     * @return array
263
-     * @throws \DomainException
264
-     * @throws \EE_Error
265
-     */
266
-    public static function prepare_conditions_query_params_for_models(
267
-        $inputted_query_params_of_this_type,
268
-        \EEM_Base $model,
269
-        $requested_version
270
-    ) {
271
-        $query_param_for_models = array();
272
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
273
-            $query_param_sans_stars = Model_Data_Translator::remove_stars_and_anything_after_from_condition_query_param_key($query_param_key);
274
-            $field = Model_Data_Translator::deduce_field_from_query_param(
275
-                $query_param_sans_stars,
276
-                $model
277
-            );
278
-            //double-check is it a *_gmt field?
279
-            if (! $field instanceof \EE_Model_Field_Base
280
-                && Model_Data_Translator::is_gmt_date_field_name($query_param_sans_stars)
281
-            ) {
282
-                //yep, take off '_gmt', and find the field
283
-                $query_param_key = Model_Data_Translator::remove_gmt_from_field_name($query_param_sans_stars);
284
-                $field = Model_Data_Translator::deduce_field_from_query_param(
285
-                    $query_param_key,
286
-                    $model
287
-                );
288
-                $timezone = 'UTC';
289
-            } else {
290
-                //so it's not a GMT field. Set the timezone on the model to the default
291
-                $timezone = \EEH_DTT_Helper::get_valid_timezone_string();
292
-            }
293
-            if ($field instanceof \EE_Model_Field_Base) {
294
-                //did they specify an operator?
295
-                if (is_array($query_param_value)) {
296
-                    $op = $query_param_value[0];
297
-                    $translated_value = array($op);
298
-                    if (isset($query_param_value[1])) {
299
-                        $value = $query_param_value[1];
300
-                        $translated_value[1] = Model_Data_Translator::prepare_field_values_from_json($field, $value,
301
-                            $requested_version, $timezone);
302
-                    }
303
-                } else {
304
-                    $translated_value = Model_Data_Translator::prepare_field_value_from_json($field, $query_param_value,
305
-                        $requested_version, $timezone);
306
-                }
307
-                $query_param_for_models[$query_param_key] = $translated_value;
308
-            } else {
309
-                //so it's not for a field, assume it's a logic query param key
310
-                $query_param_for_models[$query_param_key] = Model_Data_Translator::prepare_conditions_query_params_for_models($query_param_value,
311
-                    $model, $requested_version);
312
-            }
313
-        }
314
-        return $query_param_for_models;
315
-    }
316
-
317
-
318
-
319
-    /**
320
-     * Mostly checks if the last 4 characters are "_gmt", indicating its a
321
-     * gmt date field name
322
-     *
323
-     * @param string $field_name
324
-     * @return boolean
325
-     */
326
-    public static function is_gmt_date_field_name($field_name)
327
-    {
328
-        return substr(
329
-                   Model_Data_Translator::remove_stars_and_anything_after_from_condition_query_param_key($field_name),
330
-                   -4,
331
-                   4
332
-               ) === '_gmt';
333
-    }
334
-
335
-
336
-
337
-    /**
338
-     * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
339
-     *
340
-     * @param string $field_name
341
-     * @return string
342
-     */
343
-    public static function remove_gmt_from_field_name($field_name)
344
-    {
345
-        if (! Model_Data_Translator::is_gmt_date_field_name($field_name)) {
346
-            return $field_name;
347
-        }
348
-        $query_param_sans_stars = Model_Data_Translator::remove_stars_and_anything_after_from_condition_query_param_key($field_name);
349
-        $query_param_sans_gmt_and_sans_stars = substr(
350
-            $query_param_sans_stars,
351
-            0,
352
-            strrpos(
353
-                $field_name,
354
-                '_gmt'
355
-            )
356
-        );
357
-        return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
358
-    }
359
-
360
-
361
-
362
-    /**
363
-     * Takes a field name from the REST API and prepares it for the model querying
364
-     *
365
-     * @param string $field_name
366
-     * @return string
367
-     */
368
-    public static function prepare_field_name_from_json($field_name)
369
-    {
370
-        if (Model_Data_Translator::is_gmt_date_field_name($field_name)) {
371
-            return Model_Data_Translator::remove_gmt_from_field_name($field_name);
372
-        }
373
-        return $field_name;
374
-    }
375
-
376
-
377
-
378
-    /**
379
-     * Takes array of field names from REST API and prepares for models
380
-     *
381
-     * @param array $field_names
382
-     * @return array of field names (possibly include model prefixes)
383
-     */
384
-    public static function prepare_field_names_from_json(array $field_names)
385
-    {
386
-        $new_array = array();
387
-        foreach ($field_names as $key => $field_name) {
388
-            $new_array[$key] = Model_Data_Translator::prepare_field_name_from_json($field_name);
389
-        }
390
-        return $new_array;
391
-    }
392
-
393
-
394
-
395
-    /**
396
-     * Takes array where array keys are field names (possibly with model path prefixes)
397
-     * from the REST API and prepares them for model querying
398
-     *
399
-     * @param array $field_names_as_keys
400
-     * @return array
401
-     */
402
-    public static function prepare_field_names_in_array_keys_from_json(array $field_names_as_keys)
403
-    {
404
-        $new_array = array();
405
-        foreach ($field_names_as_keys as $field_name => $value) {
406
-            $new_array[Model_Data_Translator::prepare_field_name_from_json($field_name)] = $value;
407
-        }
408
-        return $new_array;
409
-    }
410
-
411
-
412
-
413
-    /**
414
-     * Prepares an array of model query params for use in the REST API
415
-     *
416
-     * @param array     $model_query_params
417
-     * @param \EEM_Base $model
418
-     * @param string    $requested_version eg "4.8.36". If null is provided, defaults to the latest release of the EE4
419
-     *                                     REST API
420
-     * @return array which can be passed into the EE4 REST API when querying a model resource
421
-     * @throws \EE_Error
422
-     */
423
-    public static function prepare_query_params_for_rest_api(
424
-        array $model_query_params,
425
-        \EEM_Base $model,
426
-        $requested_version = null
427
-    ) {
428
-        if ($requested_version === null) {
429
-            $requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
430
-        }
431
-        $rest_query_params = $model_query_params;
432
-        if (isset($model_query_params[0])) {
433
-            $rest_query_params['where'] = Model_Data_Translator::prepare_conditions_query_params_for_rest_api(
434
-                $model_query_params[0],
435
-                $model,
436
-                $requested_version
437
-            );
438
-            unset($rest_query_params[0]);
439
-        }
440
-        if (isset($model_query_params['having'])) {
441
-            $rest_query_params['having'] = Model_Data_Translator::prepare_conditions_query_params_for_rest_api(
442
-                $model_query_params['having'],
443
-                $model,
444
-                $requested_version
445
-            );
446
-        }
447
-        return apply_filters('FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
448
-            $rest_query_params, $model_query_params, $model, $requested_version);
449
-    }
450
-
451
-
452
-
453
-    /**
454
-     * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
455
-     *
456
-     * @param array     $inputted_query_params_of_this_type eg like the "where" or "having" conditions query params
457
-     *                                                      passed into EEM_Base::get_all()
458
-     * @param \EEM_Base $model
459
-     * @param string    $requested_version                  eg "4.8.36"
460
-     * @return array ready for use in the rest api query params
461
-     * @throws \EE_Error
462
-     */
463
-    public static function prepare_conditions_query_params_for_rest_api(
464
-        $inputted_query_params_of_this_type,
465
-        \EEM_Base $model,
466
-        $requested_version
467
-    ) {
468
-        $query_param_for_models = array();
469
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
470
-            $field = Model_Data_Translator::deduce_field_from_query_param(
471
-                Model_Data_Translator::remove_stars_and_anything_after_from_condition_query_param_key($query_param_key),
472
-                $model
473
-            );
474
-            if ($field instanceof \EE_Model_Field_Base) {
475
-                //did they specify an operator?
476
-                if (is_array($query_param_value)) {
477
-                    $op = $query_param_value[0];
478
-                    $translated_value = array($op);
479
-                    if (isset($query_param_value[1])) {
480
-                        $value = $query_param_value[1];
481
-                        $translated_value[1] = Model_Data_Translator::prepare_field_values_for_json($field, $value,
482
-                            $requested_version);
483
-                    }
484
-                } else {
485
-                    $translated_value = Model_Data_Translator::prepare_field_value_for_json($field, $query_param_value,
486
-                        $requested_version);
487
-                }
488
-                $query_param_for_models[$query_param_key] = $translated_value;
489
-            } else {
490
-                //so it's not for a field, assume it's a logic query param key
491
-                $query_param_for_models[$query_param_key] = Model_Data_Translator::prepare_conditions_query_params_for_rest_api($query_param_value,
492
-                    $model, $requested_version);
493
-            }
494
-        }
495
-        return $query_param_for_models;
496
-    }
497
-
498
-
499
-
500
-    /**
501
-     * @param $condition_query_param_key
502
-     * @return string
503
-     */
504
-    public static function remove_stars_and_anything_after_from_condition_query_param_key($condition_query_param_key)
505
-    {
506
-        $pos_of_star = strpos($condition_query_param_key, '*');
507
-        if ($pos_of_star === false) {
508
-            return $condition_query_param_key;
509
-        } else {
510
-            $condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
511
-            return $condition_query_param_sans_star;
512
-        }
513
-    }
514
-
515
-
516
-
517
-    /**
518
-     * Takes the input parameter and finds the model field that it indicates.
519
-     *
520
-     * @param string    $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
521
-     * @param \EEM_Base $model
522
-     * @return \EE_Model_Field_Base
523
-     * @throws \EE_Error
524
-     */
525
-    public static function deduce_field_from_query_param($query_param_name, \EEM_Base $model)
526
-    {
527
-        //ok, now proceed with deducing which part is the model's name, and which is the field's name
528
-        //which will help us find the database table and column
529
-        $query_param_parts = explode('.', $query_param_name);
530
-        if (empty($query_param_parts)) {
531
-            throw new \EE_Error(sprintf(__('_extract_column_name is empty when trying to extract column and table name from %s',
532
-                'event_espresso'), $query_param_name));
533
-        }
534
-        $number_of_parts = count($query_param_parts);
535
-        $last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
536
-        if ($number_of_parts === 1) {
537
-            $field_name = $last_query_param_part;
538
-        } else {// $number_of_parts >= 2
539
-            //the last part is the column name, and there are only 2parts. therefore...
540
-            $field_name = $last_query_param_part;
541
-            $model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]);
542
-        }
543
-        try {
544
-            return $model->field_settings_for($field_name);
545
-        } catch (\EE_Error $e) {
546
-            return null;
547
-        }
548
-    }
29
+	/**
30
+	 * We used to use -1 for infinity in the rest api, but that's ambiguous for
31
+	 * fields that COULD contain -1; so we use null
32
+	 */
33
+	const ee_inf_in_rest = null;
34
+
35
+
36
+
37
+	/**
38
+	 * Prepares a possible array of input values from JSON for use by the models
39
+	 *
40
+	 * @param \EE_Model_Field_Base $field_obj
41
+	 * @param mixed                $original_value_maybe_array
42
+	 * @param string               $requested_version
43
+	 * @param string               $timezone_string treat values as being in this timezone
44
+	 * @return mixed
45
+	 * @throws \DomainException
46
+	 */
47
+	public static function prepare_field_values_from_json(
48
+		$field_obj,
49
+		$original_value_maybe_array,
50
+		$requested_version,
51
+		$timezone_string = 'UTC'
52
+	) {
53
+		if (is_array($original_value_maybe_array)) {
54
+			$new_value_maybe_array = array();
55
+			foreach ($original_value_maybe_array as $array_key => $array_item) {
56
+				$new_value_maybe_array[$array_key] = Model_Data_Translator::prepare_field_value_from_json(
57
+					$field_obj,
58
+					$array_item,
59
+					$requested_version,
60
+					$timezone_string
61
+				);
62
+			}
63
+		} else {
64
+			$new_value_maybe_array = Model_Data_Translator::prepare_field_value_from_json(
65
+				$field_obj,
66
+				$original_value_maybe_array,
67
+				$requested_version,
68
+				$timezone_string
69
+			);
70
+		}
71
+		return $new_value_maybe_array;
72
+	}
73
+
74
+
75
+
76
+	/**
77
+	 * Prepares an array of field values FOR use in JSON/REST API
78
+	 *
79
+	 * @param \EE_Model_Field_Base $field_obj
80
+	 * @param mixed                $original_value_maybe_array
81
+	 * @param string               $request_version (eg 4.8.36)
82
+	 * @return array
83
+	 */
84
+	public static function prepare_field_values_for_json($field_obj, $original_value_maybe_array, $request_version)
85
+	{
86
+		if (is_array($original_value_maybe_array)) {
87
+			$new_value_maybe_array = array();
88
+			foreach ($original_value_maybe_array as $array_key => $array_item) {
89
+				$new_value_maybe_array[$array_key] = Model_Data_Translator::prepare_field_value_for_json(
90
+					$field_obj,
91
+					$array_item,
92
+					$request_version
93
+				);
94
+			}
95
+		} else {
96
+			$new_value_maybe_array = Model_Data_Translator::prepare_field_value_for_json(
97
+				$field_obj,
98
+				$original_value_maybe_array,
99
+				$request_version
100
+			);
101
+		}
102
+		return $new_value_maybe_array;
103
+	}
104
+
105
+
106
+
107
+	/**
108
+	 * Prepares incoming data from the json or $_REQUEST parameters for the models'
109
+	 * "$query_params".
110
+	 *
111
+	 * @param \EE_Model_Field_Base $field_obj
112
+	 * @param mixed                $original_value
113
+	 * @param string               $requested_version
114
+	 * @param string               $timezone_string treat values as being in this timezone
115
+	 * @return mixed
116
+	 * @throws \DomainException
117
+	 */
118
+	public static function prepare_field_value_from_json(
119
+		$field_obj,
120
+		$original_value,
121
+		$requested_version,
122
+		$timezone_string = 'UTC' // UTC
123
+	)
124
+	{
125
+		$timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
126
+		$new_value = null;
127
+		if ($field_obj instanceof \EE_Infinite_Integer_Field
128
+			&& in_array($original_value, array(null, ''), true)
129
+		) {
130
+			$new_value = EE_INF;
131
+		} elseif ($field_obj instanceof \EE_Datetime_Field) {
132
+			list($offset_sign, $offset_secs) = Model_Data_Translator::parse_timezone_offset(
133
+				$field_obj->get_timezone_offset(
134
+					new \DateTimeZone($timezone_string)
135
+				)
136
+			);
137
+			$offset_string =
138
+				str_pad(
139
+					floor($offset_secs / HOUR_IN_SECONDS),
140
+					2,
141
+					'0',
142
+					STR_PAD_LEFT
143
+				)
144
+				. ':'
145
+				. str_pad(
146
+					($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
147
+					2,
148
+					'0',
149
+					STR_PAD_LEFT
150
+				);
151
+			$new_value = rest_parse_date($original_value . $offset_sign . $offset_string);
152
+		} else {
153
+			$new_value = $original_value;
154
+		}
155
+		return $new_value;
156
+	}
157
+
158
+
159
+
160
+	/**
161
+	 * determines what's going on with them timezone strings
162
+	 *
163
+	 * @param int $timezone_offset
164
+	 * @return array
165
+	 */
166
+	private static function parse_timezone_offset($timezone_offset)
167
+	{
168
+		$first_char = substr((string)$timezone_offset, 0, 1);
169
+		if ($first_char === '+' || $first_char === '-') {
170
+			$offset_sign = $first_char;
171
+			$offset_secs = substr((string)$timezone_offset, 1);
172
+		} else {
173
+			$offset_sign = '+';
174
+			$offset_secs = $timezone_offset;
175
+		}
176
+		return array($offset_sign, $offset_secs);
177
+	}
178
+
179
+
180
+
181
+	/**
182
+	 * Prepares a field's value for display in the API.
183
+	 * The $original_value should be in the model object's domain of values, see the explanation at the top of EEM_Base.
184
+	 * However, for backward compatibility, we also attempt to handle $original_values from the
185
+	 * model client-code domain, and from the database domain.
186
+	 * E.g., when working with EE_Datetime_Fields, $original_value should be a DateTime or DbSafeDateTime
187
+	 * (model object domain). However, for backward compatibility, we also accept a unix timestamp
188
+	 * (old model object domain), MySQL datetime string (database domain) or string formatted according to the
189
+	 * WP Datetime format (model client-code domain)
190
+	 *
191
+	 * @param \EE_Model_Field_Base $field_obj
192
+	 * @param mixed                $original_value
193
+	 * @param string               $requested_version
194
+	 * @return mixed
195
+	 */
196
+	public static function prepare_field_value_for_json($field_obj, $original_value, $requested_version)
197
+	{
198
+		if ($original_value === EE_INF) {
199
+			$new_value = Model_Data_Translator::ee_inf_in_rest;
200
+		} elseif ($field_obj instanceof \EE_Datetime_Field) {
201
+			if (is_string($original_value)) {
202
+				//did they submit a string of a unix timestamp?
203
+				if (is_numeric($original_value)) {
204
+					$datetime_obj = new \DateTime();
205
+					$datetime_obj->setTimestamp((int)$original_value);
206
+				} else {
207
+					//first, check if its a MySQL timestamp in GMT
208
+					$datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
209
+				}
210
+				if (! $datetime_obj instanceof \DateTime) {
211
+					//so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
212
+					$datetime_obj = $field_obj->prepare_for_set($original_value);
213
+				}
214
+				$original_value = $datetime_obj;
215
+			}
216
+			if ($original_value instanceof \DateTime) {
217
+				$new_value = $original_value->format('Y-m-d H:i:s');
218
+			} elseif (is_int($original_value)) {
219
+				$new_value = date('Y-m-d H:i:s', $original_value);
220
+			} elseif($original_value === null || $original_value === '') {
221
+				$new_value = null;
222
+			} else {
223
+				//so it's not a datetime object, unix timestamp (as string or int),
224
+				//MySQL timestamp, or even a string in the field object's format. So no idea what it is
225
+				throw new \EE_Error(
226
+					sprintf(
227
+						esc_html__(
228
+							// @codingStandardsIgnoreStart
229
+							'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
230
+							// @codingStandardsIgnoreEnd
231
+							'event_espressso'
232
+						),
233
+						$original_value,
234
+						$field_obj->get_name(),
235
+						$field_obj->get_model_name(),
236
+						$field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
237
+					)
238
+				);
239
+			}
240
+			$new_value = mysql_to_rfc3339($new_value);
241
+		} else {
242
+			$new_value = $original_value;
243
+		}
244
+		return apply_filters(
245
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
246
+			$new_value,
247
+			$field_obj,
248
+			$original_value,
249
+			$requested_version
250
+		);
251
+	}
252
+
253
+
254
+
255
+	/**
256
+	 * Prepares condition-query-parameters (like what's in where and having) from
257
+	 * the format expected in the API to use in the models
258
+	 *
259
+	 * @param array     $inputted_query_params_of_this_type
260
+	 * @param \EEM_Base $model
261
+	 * @param string    $requested_version
262
+	 * @return array
263
+	 * @throws \DomainException
264
+	 * @throws \EE_Error
265
+	 */
266
+	public static function prepare_conditions_query_params_for_models(
267
+		$inputted_query_params_of_this_type,
268
+		\EEM_Base $model,
269
+		$requested_version
270
+	) {
271
+		$query_param_for_models = array();
272
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
273
+			$query_param_sans_stars = Model_Data_Translator::remove_stars_and_anything_after_from_condition_query_param_key($query_param_key);
274
+			$field = Model_Data_Translator::deduce_field_from_query_param(
275
+				$query_param_sans_stars,
276
+				$model
277
+			);
278
+			//double-check is it a *_gmt field?
279
+			if (! $field instanceof \EE_Model_Field_Base
280
+				&& Model_Data_Translator::is_gmt_date_field_name($query_param_sans_stars)
281
+			) {
282
+				//yep, take off '_gmt', and find the field
283
+				$query_param_key = Model_Data_Translator::remove_gmt_from_field_name($query_param_sans_stars);
284
+				$field = Model_Data_Translator::deduce_field_from_query_param(
285
+					$query_param_key,
286
+					$model
287
+				);
288
+				$timezone = 'UTC';
289
+			} else {
290
+				//so it's not a GMT field. Set the timezone on the model to the default
291
+				$timezone = \EEH_DTT_Helper::get_valid_timezone_string();
292
+			}
293
+			if ($field instanceof \EE_Model_Field_Base) {
294
+				//did they specify an operator?
295
+				if (is_array($query_param_value)) {
296
+					$op = $query_param_value[0];
297
+					$translated_value = array($op);
298
+					if (isset($query_param_value[1])) {
299
+						$value = $query_param_value[1];
300
+						$translated_value[1] = Model_Data_Translator::prepare_field_values_from_json($field, $value,
301
+							$requested_version, $timezone);
302
+					}
303
+				} else {
304
+					$translated_value = Model_Data_Translator::prepare_field_value_from_json($field, $query_param_value,
305
+						$requested_version, $timezone);
306
+				}
307
+				$query_param_for_models[$query_param_key] = $translated_value;
308
+			} else {
309
+				//so it's not for a field, assume it's a logic query param key
310
+				$query_param_for_models[$query_param_key] = Model_Data_Translator::prepare_conditions_query_params_for_models($query_param_value,
311
+					$model, $requested_version);
312
+			}
313
+		}
314
+		return $query_param_for_models;
315
+	}
316
+
317
+
318
+
319
+	/**
320
+	 * Mostly checks if the last 4 characters are "_gmt", indicating its a
321
+	 * gmt date field name
322
+	 *
323
+	 * @param string $field_name
324
+	 * @return boolean
325
+	 */
326
+	public static function is_gmt_date_field_name($field_name)
327
+	{
328
+		return substr(
329
+				   Model_Data_Translator::remove_stars_and_anything_after_from_condition_query_param_key($field_name),
330
+				   -4,
331
+				   4
332
+			   ) === '_gmt';
333
+	}
334
+
335
+
336
+
337
+	/**
338
+	 * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
339
+	 *
340
+	 * @param string $field_name
341
+	 * @return string
342
+	 */
343
+	public static function remove_gmt_from_field_name($field_name)
344
+	{
345
+		if (! Model_Data_Translator::is_gmt_date_field_name($field_name)) {
346
+			return $field_name;
347
+		}
348
+		$query_param_sans_stars = Model_Data_Translator::remove_stars_and_anything_after_from_condition_query_param_key($field_name);
349
+		$query_param_sans_gmt_and_sans_stars = substr(
350
+			$query_param_sans_stars,
351
+			0,
352
+			strrpos(
353
+				$field_name,
354
+				'_gmt'
355
+			)
356
+		);
357
+		return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
358
+	}
359
+
360
+
361
+
362
+	/**
363
+	 * Takes a field name from the REST API and prepares it for the model querying
364
+	 *
365
+	 * @param string $field_name
366
+	 * @return string
367
+	 */
368
+	public static function prepare_field_name_from_json($field_name)
369
+	{
370
+		if (Model_Data_Translator::is_gmt_date_field_name($field_name)) {
371
+			return Model_Data_Translator::remove_gmt_from_field_name($field_name);
372
+		}
373
+		return $field_name;
374
+	}
375
+
376
+
377
+
378
+	/**
379
+	 * Takes array of field names from REST API and prepares for models
380
+	 *
381
+	 * @param array $field_names
382
+	 * @return array of field names (possibly include model prefixes)
383
+	 */
384
+	public static function prepare_field_names_from_json(array $field_names)
385
+	{
386
+		$new_array = array();
387
+		foreach ($field_names as $key => $field_name) {
388
+			$new_array[$key] = Model_Data_Translator::prepare_field_name_from_json($field_name);
389
+		}
390
+		return $new_array;
391
+	}
392
+
393
+
394
+
395
+	/**
396
+	 * Takes array where array keys are field names (possibly with model path prefixes)
397
+	 * from the REST API and prepares them for model querying
398
+	 *
399
+	 * @param array $field_names_as_keys
400
+	 * @return array
401
+	 */
402
+	public static function prepare_field_names_in_array_keys_from_json(array $field_names_as_keys)
403
+	{
404
+		$new_array = array();
405
+		foreach ($field_names_as_keys as $field_name => $value) {
406
+			$new_array[Model_Data_Translator::prepare_field_name_from_json($field_name)] = $value;
407
+		}
408
+		return $new_array;
409
+	}
410
+
411
+
412
+
413
+	/**
414
+	 * Prepares an array of model query params for use in the REST API
415
+	 *
416
+	 * @param array     $model_query_params
417
+	 * @param \EEM_Base $model
418
+	 * @param string    $requested_version eg "4.8.36". If null is provided, defaults to the latest release of the EE4
419
+	 *                                     REST API
420
+	 * @return array which can be passed into the EE4 REST API when querying a model resource
421
+	 * @throws \EE_Error
422
+	 */
423
+	public static function prepare_query_params_for_rest_api(
424
+		array $model_query_params,
425
+		\EEM_Base $model,
426
+		$requested_version = null
427
+	) {
428
+		if ($requested_version === null) {
429
+			$requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
430
+		}
431
+		$rest_query_params = $model_query_params;
432
+		if (isset($model_query_params[0])) {
433
+			$rest_query_params['where'] = Model_Data_Translator::prepare_conditions_query_params_for_rest_api(
434
+				$model_query_params[0],
435
+				$model,
436
+				$requested_version
437
+			);
438
+			unset($rest_query_params[0]);
439
+		}
440
+		if (isset($model_query_params['having'])) {
441
+			$rest_query_params['having'] = Model_Data_Translator::prepare_conditions_query_params_for_rest_api(
442
+				$model_query_params['having'],
443
+				$model,
444
+				$requested_version
445
+			);
446
+		}
447
+		return apply_filters('FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
448
+			$rest_query_params, $model_query_params, $model, $requested_version);
449
+	}
450
+
451
+
452
+
453
+	/**
454
+	 * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
455
+	 *
456
+	 * @param array     $inputted_query_params_of_this_type eg like the "where" or "having" conditions query params
457
+	 *                                                      passed into EEM_Base::get_all()
458
+	 * @param \EEM_Base $model
459
+	 * @param string    $requested_version                  eg "4.8.36"
460
+	 * @return array ready for use in the rest api query params
461
+	 * @throws \EE_Error
462
+	 */
463
+	public static function prepare_conditions_query_params_for_rest_api(
464
+		$inputted_query_params_of_this_type,
465
+		\EEM_Base $model,
466
+		$requested_version
467
+	) {
468
+		$query_param_for_models = array();
469
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
470
+			$field = Model_Data_Translator::deduce_field_from_query_param(
471
+				Model_Data_Translator::remove_stars_and_anything_after_from_condition_query_param_key($query_param_key),
472
+				$model
473
+			);
474
+			if ($field instanceof \EE_Model_Field_Base) {
475
+				//did they specify an operator?
476
+				if (is_array($query_param_value)) {
477
+					$op = $query_param_value[0];
478
+					$translated_value = array($op);
479
+					if (isset($query_param_value[1])) {
480
+						$value = $query_param_value[1];
481
+						$translated_value[1] = Model_Data_Translator::prepare_field_values_for_json($field, $value,
482
+							$requested_version);
483
+					}
484
+				} else {
485
+					$translated_value = Model_Data_Translator::prepare_field_value_for_json($field, $query_param_value,
486
+						$requested_version);
487
+				}
488
+				$query_param_for_models[$query_param_key] = $translated_value;
489
+			} else {
490
+				//so it's not for a field, assume it's a logic query param key
491
+				$query_param_for_models[$query_param_key] = Model_Data_Translator::prepare_conditions_query_params_for_rest_api($query_param_value,
492
+					$model, $requested_version);
493
+			}
494
+		}
495
+		return $query_param_for_models;
496
+	}
497
+
498
+
499
+
500
+	/**
501
+	 * @param $condition_query_param_key
502
+	 * @return string
503
+	 */
504
+	public static function remove_stars_and_anything_after_from_condition_query_param_key($condition_query_param_key)
505
+	{
506
+		$pos_of_star = strpos($condition_query_param_key, '*');
507
+		if ($pos_of_star === false) {
508
+			return $condition_query_param_key;
509
+		} else {
510
+			$condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
511
+			return $condition_query_param_sans_star;
512
+		}
513
+	}
514
+
515
+
516
+
517
+	/**
518
+	 * Takes the input parameter and finds the model field that it indicates.
519
+	 *
520
+	 * @param string    $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
521
+	 * @param \EEM_Base $model
522
+	 * @return \EE_Model_Field_Base
523
+	 * @throws \EE_Error
524
+	 */
525
+	public static function deduce_field_from_query_param($query_param_name, \EEM_Base $model)
526
+	{
527
+		//ok, now proceed with deducing which part is the model's name, and which is the field's name
528
+		//which will help us find the database table and column
529
+		$query_param_parts = explode('.', $query_param_name);
530
+		if (empty($query_param_parts)) {
531
+			throw new \EE_Error(sprintf(__('_extract_column_name is empty when trying to extract column and table name from %s',
532
+				'event_espresso'), $query_param_name));
533
+		}
534
+		$number_of_parts = count($query_param_parts);
535
+		$last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
536
+		if ($number_of_parts === 1) {
537
+			$field_name = $last_query_param_part;
538
+		} else {// $number_of_parts >= 2
539
+			//the last part is the column name, and there are only 2parts. therefore...
540
+			$field_name = $last_query_param_part;
541
+			$model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]);
542
+		}
543
+		try {
544
+			return $model->field_settings_for($field_name);
545
+		} catch (\EE_Error $e) {
546
+			return null;
547
+		}
548
+	}
549 549
 
550 550
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 namespace EventEspresso\core\libraries\rest_api;
3 3
 
4
-if (! defined('EVENT_ESPRESSO_VERSION')) {
4
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
5 5
     exit('No direct script access allowed');
6 6
 }
7 7
 
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
                     '0',
149 149
                     STR_PAD_LEFT
150 150
                 );
151
-            $new_value = rest_parse_date($original_value . $offset_sign . $offset_string);
151
+            $new_value = rest_parse_date($original_value.$offset_sign.$offset_string);
152 152
         } else {
153 153
             $new_value = $original_value;
154 154
         }
@@ -165,10 +165,10 @@  discard block
 block discarded – undo
165 165
      */
166 166
     private static function parse_timezone_offset($timezone_offset)
167 167
     {
168
-        $first_char = substr((string)$timezone_offset, 0, 1);
168
+        $first_char = substr((string) $timezone_offset, 0, 1);
169 169
         if ($first_char === '+' || $first_char === '-') {
170 170
             $offset_sign = $first_char;
171
-            $offset_secs = substr((string)$timezone_offset, 1);
171
+            $offset_secs = substr((string) $timezone_offset, 1);
172 172
         } else {
173 173
             $offset_sign = '+';
174 174
             $offset_secs = $timezone_offset;
@@ -202,12 +202,12 @@  discard block
 block discarded – undo
202 202
                 //did they submit a string of a unix timestamp?
203 203
                 if (is_numeric($original_value)) {
204 204
                     $datetime_obj = new \DateTime();
205
-                    $datetime_obj->setTimestamp((int)$original_value);
205
+                    $datetime_obj->setTimestamp((int) $original_value);
206 206
                 } else {
207 207
                     //first, check if its a MySQL timestamp in GMT
208 208
                     $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
209 209
                 }
210
-                if (! $datetime_obj instanceof \DateTime) {
210
+                if ( ! $datetime_obj instanceof \DateTime) {
211 211
                     //so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
212 212
                     $datetime_obj = $field_obj->prepare_for_set($original_value);
213 213
                 }
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
                 $new_value = $original_value->format('Y-m-d H:i:s');
218 218
             } elseif (is_int($original_value)) {
219 219
                 $new_value = date('Y-m-d H:i:s', $original_value);
220
-            } elseif($original_value === null || $original_value === '') {
220
+            } elseif ($original_value === null || $original_value === '') {
221 221
                 $new_value = null;
222 222
             } else {
223 223
                 //so it's not a datetime object, unix timestamp (as string or int),
@@ -233,7 +233,7 @@  discard block
 block discarded – undo
233 233
                         $original_value,
234 234
                         $field_obj->get_name(),
235 235
                         $field_obj->get_model_name(),
236
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
236
+                        $field_obj->get_time_format().' '.$field_obj->get_time_format()
237 237
                     )
238 238
                 );
239 239
             }
@@ -276,7 +276,7 @@  discard block
 block discarded – undo
276 276
                 $model
277 277
             );
278 278
             //double-check is it a *_gmt field?
279
-            if (! $field instanceof \EE_Model_Field_Base
279
+            if ( ! $field instanceof \EE_Model_Field_Base
280 280
                 && Model_Data_Translator::is_gmt_date_field_name($query_param_sans_stars)
281 281
             ) {
282 282
                 //yep, take off '_gmt', and find the field
@@ -342,7 +342,7 @@  discard block
 block discarded – undo
342 342
      */
343 343
     public static function remove_gmt_from_field_name($field_name)
344 344
     {
345
-        if (! Model_Data_Translator::is_gmt_date_field_name($field_name)) {
345
+        if ( ! Model_Data_Translator::is_gmt_date_field_name($field_name)) {
346 346
             return $field_name;
347 347
         }
348 348
         $query_param_sans_stars = Model_Data_Translator::remove_stars_and_anything_after_from_condition_query_param_key($field_name);
Please login to merge, or discard this patch.
caffeinated/admin/extend/events/Extend_Events_Admin_Page.core.php 1 patch
Indentation   +1260 added lines, -1260 removed lines patch added patch discarded remove patch
@@ -14,1264 +14,1264 @@
 block discarded – undo
14 14
 {
15 15
 
16 16
 
17
-    /**
18
-     * Extend_Events_Admin_Page constructor.
19
-     *
20
-     * @param bool $routing
21
-     */
22
-    public function __construct($routing = true)
23
-    {
24
-        parent::__construct($routing);
25
-        if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
26
-            define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
27
-            define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
28
-            define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
29
-        }
30
-    }
31
-
32
-
33
-    /**
34
-     * Sets routes.
35
-     */
36
-    protected function _extend_page_config()
37
-    {
38
-        $this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
39
-        //is there a evt_id in the request?
40
-        $evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
41
-            ? $this->_req_data['EVT_ID']
42
-            : 0;
43
-        $evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
44
-        //tkt_id?
45
-        $tkt_id             = ! empty($this->_req_data['TKT_ID']) && ! is_array($this->_req_data['TKT_ID'])
46
-            ? $this->_req_data['TKT_ID']
47
-            : 0;
48
-        $new_page_routes    = array(
49
-            'duplicate_event'          => array(
50
-                'func'       => '_duplicate_event',
51
-                'capability' => 'ee_edit_event',
52
-                'obj_id'     => $evt_id,
53
-                'noheader'   => true,
54
-            ),
55
-            'ticket_list_table'        => array(
56
-                'func'       => '_tickets_overview_list_table',
57
-                'capability' => 'ee_read_default_tickets',
58
-            ),
59
-            'trash_ticket'             => array(
60
-                'func'       => '_trash_or_restore_ticket',
61
-                'capability' => 'ee_delete_default_ticket',
62
-                'obj_id'     => $tkt_id,
63
-                'noheader'   => true,
64
-                'args'       => array('trash' => true),
65
-            ),
66
-            'trash_tickets'            => array(
67
-                'func'       => '_trash_or_restore_ticket',
68
-                'capability' => 'ee_delete_default_tickets',
69
-                'noheader'   => true,
70
-                'args'       => array('trash' => true),
71
-            ),
72
-            'restore_ticket'           => array(
73
-                'func'       => '_trash_or_restore_ticket',
74
-                'capability' => 'ee_delete_default_ticket',
75
-                'obj_id'     => $tkt_id,
76
-                'noheader'   => true,
77
-            ),
78
-            'restore_tickets'          => array(
79
-                'func'       => '_trash_or_restore_ticket',
80
-                'capability' => 'ee_delete_default_tickets',
81
-                'noheader'   => true,
82
-            ),
83
-            'delete_ticket'            => array(
84
-                'func'       => '_delete_ticket',
85
-                'capability' => 'ee_delete_default_ticket',
86
-                'obj_id'     => $tkt_id,
87
-                'noheader'   => true,
88
-            ),
89
-            'delete_tickets'           => array(
90
-                'func'       => '_delete_ticket',
91
-                'capability' => 'ee_delete_default_tickets',
92
-                'noheader'   => true,
93
-            ),
94
-            'import_page'              => array(
95
-                'func'       => '_import_page',
96
-                'capability' => 'import',
97
-            ),
98
-            'import'                   => array(
99
-                'func'       => '_import_events',
100
-                'capability' => 'import',
101
-                'noheader'   => true,
102
-            ),
103
-            'import_events'            => array(
104
-                'func'       => '_import_events',
105
-                'capability' => 'import',
106
-                'noheader'   => true,
107
-            ),
108
-            'export_events'            => array(
109
-                'func'       => '_events_export',
110
-                'capability' => 'export',
111
-                'noheader'   => true,
112
-            ),
113
-            'export_categories'        => array(
114
-                'func'       => '_categories_export',
115
-                'capability' => 'export',
116
-                'noheader'   => true,
117
-            ),
118
-            'sample_export_file'       => array(
119
-                'func'       => '_sample_export_file',
120
-                'capability' => 'export',
121
-                'noheader'   => true,
122
-            ),
123
-            'update_template_settings' => array(
124
-                'func'       => '_update_template_settings',
125
-                'capability' => 'manage_options',
126
-                'noheader'   => true,
127
-            ),
128
-        );
129
-        $this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
130
-        //partial route/config override
131
-        $this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
132
-        $this->_page_config['create_new']['metaboxes'][]  = '_premium_event_editor_meta_boxes';
133
-        $this->_page_config['create_new']['qtips'][]      = 'EE_Event_Editor_Tips';
134
-        $this->_page_config['edit']['qtips'][]            = 'EE_Event_Editor_Tips';
135
-        $this->_page_config['edit']['metaboxes'][]        = '_premium_event_editor_meta_boxes';
136
-        $this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
137
-        //add tickets tab but only if there are more than one default ticket!
138
-        $tkt_count = EEM_Ticket::instance()->count_deleted_and_undeleted(
139
-            array(array('TKT_is_default' => 1)),
140
-            'TKT_ID',
141
-            true
142
-        );
143
-        if ($tkt_count > 1) {
144
-            $new_page_config = array(
145
-                'ticket_list_table' => array(
146
-                    'nav'           => array(
147
-                        'label' => esc_html__('Default Tickets', 'event_espresso'),
148
-                        'order' => 60,
149
-                    ),
150
-                    'list_table'    => 'Tickets_List_Table',
151
-                    'require_nonce' => false,
152
-                ),
153
-            );
154
-        }
155
-        //template settings
156
-        $new_page_config['template_settings'] = array(
157
-            'nav'           => array(
158
-                'label' => esc_html__('Templates', 'event_espresso'),
159
-                'order' => 30,
160
-            ),
161
-            'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
162
-            'help_tabs'     => array(
163
-                'general_settings_templates_help_tab' => array(
164
-                    'title'    => esc_html__('Templates', 'event_espresso'),
165
-                    'filename' => 'general_settings_templates',
166
-                ),
167
-            ),
168
-            'help_tour'     => array('Templates_Help_Tour'),
169
-            'require_nonce' => false,
170
-        );
171
-        $this->_page_config                   = array_merge($this->_page_config, $new_page_config);
172
-        //add filters and actions
173
-        //modifying _views
174
-        add_filter(
175
-            'FHEE_event_datetime_metabox_add_additional_date_time_template',
176
-            array($this, 'add_additional_datetime_button'),
177
-            10,
178
-            2
179
-        );
180
-        add_filter(
181
-            'FHEE_event_datetime_metabox_clone_button_template',
182
-            array($this, 'add_datetime_clone_button'),
183
-            10,
184
-            2
185
-        );
186
-        add_filter(
187
-            'FHEE_event_datetime_metabox_timezones_template',
188
-            array($this, 'datetime_timezones_template'),
189
-            10,
190
-            2
191
-        );
192
-        //filters for event list table
193
-        add_filter('FHEE__Extend_Events_Admin_List_Table__filters', array($this, 'list_table_filters'), 10, 2);
194
-        add_filter(
195
-            'FHEE__Events_Admin_List_Table__column_actions__action_links',
196
-            array($this, 'extra_list_table_actions'),
197
-            10,
198
-            2
199
-        );
200
-        //legend item
201
-        add_filter('FHEE__Events_Admin_Page___event_legend_items__items', array($this, 'additional_legend_items'));
202
-        add_action('admin_init', array($this, 'admin_init'));
203
-        //heartbeat stuff
204
-        add_filter('heartbeat_received', array($this, 'heartbeat_response'), 10, 2);
205
-    }
206
-
207
-
208
-    /**
209
-     * admin_init
210
-     */
211
-    public function admin_init()
212
-    {
213
-        EE_Registry::$i18n_js_strings = array_merge(
214
-            EE_Registry::$i18n_js_strings,
215
-            array(
216
-                'image_confirm'          => esc_html__(
217
-                    'Do you really want to delete this image? Please remember to update your event to complete the removal.',
218
-                    'event_espresso'
219
-                ),
220
-                'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
221
-                'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
222
-                'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
223
-                'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
224
-                'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
225
-            )
226
-        );
227
-    }
228
-
229
-
230
-    /**
231
-     * This will be used to listen for any heartbeat data packages coming via the WordPress heartbeat API and handle
232
-     * accordingly.
233
-     *
234
-     * @param array $response The existing heartbeat response array.
235
-     * @param array $data     The incoming data package.
236
-     * @return array  possibly appended response.
237
-     */
238
-    public function heartbeat_response($response, $data)
239
-    {
240
-        /**
241
-         * check whether count of tickets is approaching the potential
242
-         * limits for the server.
243
-         */
244
-        if (! empty($data['input_count'])) {
245
-            $response['max_input_vars_check'] = EE_Registry::instance()->CFG->environment->max_input_vars_limit_check(
246
-                $data['input_count']
247
-            );
248
-        }
249
-        return $response;
250
-    }
251
-
252
-
253
-    /**
254
-     * Add per page screen options to the default ticket list table view.
255
-     */
256
-    protected function _add_screen_options_ticket_list_table()
257
-    {
258
-        $this->_per_page_screen_option();
259
-    }
260
-
261
-
262
-    /**
263
-     * @param string $return
264
-     * @param int    $id
265
-     * @param string $new_title
266
-     * @param string $new_slug
267
-     * @return string
268
-     */
269
-    public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
270
-    {
271
-        $return = parent::extra_permalink_field_buttons($return, $id, $new_title, $new_slug);
272
-        //make sure this is only when editing
273
-        if (! empty($id)) {
274
-            $href   = EE_Admin_Page::add_query_args_and_nonce(
275
-                array('action' => 'duplicate_event', 'EVT_ID' => $id),
276
-                $this->_admin_base_url
277
-            );
278
-            $title  = esc_attr__('Duplicate Event', 'event_espresso');
279
-            $return .= '<a href="'
280
-                       . $href
281
-                       . '" title="'
282
-                       . $title
283
-                       . '" id="ee-duplicate-event-button" class="button button-small"  value="duplicate_event">'
284
-                       . $title
285
-                       . '</button>';
286
-        }
287
-        return $return;
288
-    }
289
-
290
-
291
-    /**
292
-     * Set the list table views for the default ticket list table view.
293
-     */
294
-    public function _set_list_table_views_ticket_list_table()
295
-    {
296
-        $this->_views = array(
297
-            'all'     => array(
298
-                'slug'        => 'all',
299
-                'label'       => esc_html__('All', 'event_espresso'),
300
-                'count'       => 0,
301
-                'bulk_action' => array(
302
-                    'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
303
-                ),
304
-            ),
305
-            'trashed' => array(
306
-                'slug'        => 'trashed',
307
-                'label'       => esc_html__('Trash', 'event_espresso'),
308
-                'count'       => 0,
309
-                'bulk_action' => array(
310
-                    'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
311
-                    'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
312
-                ),
313
-            ),
314
-        );
315
-    }
316
-
317
-
318
-    /**
319
-     * Enqueue scripts and styles for the event editor.
320
-     */
321
-    public function load_scripts_styles_edit()
322
-    {
323
-        wp_register_script(
324
-            'ee-event-editor-heartbeat',
325
-            EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
326
-            array('ee_admin_js', 'heartbeat'),
327
-            EVENT_ESPRESSO_VERSION,
328
-            true
329
-        );
330
-        wp_enqueue_script('ee-accounting');
331
-        //styles
332
-        wp_enqueue_style('espresso-ui-theme');
333
-        wp_enqueue_script('event_editor_js');
334
-        wp_enqueue_script('ee-event-editor-heartbeat');
335
-    }
336
-
337
-
338
-    /**
339
-     * Returns template for the additional datetime.
340
-     * @param $template
341
-     * @param $template_args
342
-     * @return mixed
343
-     * @throws DomainException
344
-     */
345
-    public function add_additional_datetime_button($template, $template_args)
346
-    {
347
-        return EEH_Template::display_template(
348
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php',
349
-            $template_args,
350
-            true
351
-        );
352
-    }
353
-
354
-
355
-    /**
356
-     * Returns the template for cloning a datetime.
357
-     * @param $template
358
-     * @param $template_args
359
-     * @return mixed
360
-     * @throws DomainException
361
-     */
362
-    public function add_datetime_clone_button($template, $template_args)
363
-    {
364
-        return EEH_Template::display_template(
365
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php',
366
-            $template_args,
367
-            true
368
-        );
369
-    }
370
-
371
-
372
-    /**
373
-     * Returns the template for datetime timezones.
374
-     * @param $template
375
-     * @param $template_args
376
-     * @return mixed
377
-     * @throws DomainException
378
-     */
379
-    public function datetime_timezones_template($template, $template_args)
380
-    {
381
-        return EEH_Template::display_template(
382
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php',
383
-            $template_args,
384
-            true
385
-        );
386
-    }
387
-
388
-
389
-    /**
390
-     * Sets the views for the default list table view.
391
-     */
392
-    protected function _set_list_table_views_default()
393
-    {
394
-        parent::_set_list_table_views_default();
395
-        $new_views    = array(
396
-            'today' => array(
397
-                'slug'        => 'today',
398
-                'label'       => esc_html__('Today', 'event_espresso'),
399
-                'count'       => $this->total_events_today(),
400
-                'bulk_action' => array(
401
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
402
-                ),
403
-            ),
404
-            'month' => array(
405
-                'slug'        => 'month',
406
-                'label'       => esc_html__('This Month', 'event_espresso'),
407
-                'count'       => $this->total_events_this_month(),
408
-                'bulk_action' => array(
409
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
410
-                ),
411
-            ),
412
-        );
413
-        $this->_views = array_merge($this->_views, $new_views);
414
-    }
415
-
416
-
417
-    /**
418
-     * Returns the extra action links for the default list table view.
419
-     * @param array     $action_links
420
-     * @param \EE_Event $event
421
-     * @return array
422
-     * @throws EE_Error
423
-     */
424
-    public function extra_list_table_actions(array $action_links, \EE_Event $event)
425
-    {
426
-        if (EE_Registry::instance()->CAP->current_user_can(
427
-            'ee_read_registrations',
428
-            'espresso_registrations_reports',
429
-            $event->ID()
430
-        )
431
-        ) {
432
-            $reports_query_args = array(
433
-                'action' => 'reports',
434
-                'EVT_ID' => $event->ID(),
435
-            );
436
-            $reports_link       = EE_Admin_Page::add_query_args_and_nonce($reports_query_args, REG_ADMIN_URL);
437
-            $action_links[]     = '<a href="'
438
-                                  . $reports_link
439
-                                  . '" title="'
440
-                                  . esc_attr__('View Report', 'event_espresso')
441
-                                  . '"><div class="dashicons dashicons-chart-bar"></div></a>'
442
-                                  . "\n\t";
443
-        }
444
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
445
-            EE_Registry::instance()->load_helper('MSG_Template');
446
-            $action_links[] = EEH_MSG_Template::get_message_action_link(
447
-                'see_notifications_for',
448
-                null,
449
-                array('EVT_ID' => $event->ID())
450
-            );
451
-        }
452
-        return $action_links;
453
-    }
454
-
455
-
456
-    /**
457
-     * @param $items
458
-     * @return mixed
459
-     */
460
-    public function additional_legend_items($items)
461
-    {
462
-        if (EE_Registry::instance()->CAP->current_user_can(
463
-            'ee_read_registrations',
464
-            'espresso_registrations_reports'
465
-        )
466
-        ) {
467
-            $items['reports'] = array(
468
-                'class' => 'dashicons dashicons-chart-bar',
469
-                'desc'  => esc_html__('Event Reports', 'event_espresso'),
470
-            );
471
-        }
472
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
473
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
474
-            if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
475
-                $items['view_related_messages'] = array(
476
-                    'class' => $related_for_icon['css_class'],
477
-                    'desc'  => $related_for_icon['label'],
478
-                );
479
-            }
480
-        }
481
-        return $items;
482
-    }
483
-
484
-
485
-    /**
486
-     * This is the callback method for the duplicate event route
487
-     * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
488
-     * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
489
-     * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
490
-     * After duplication the redirect is to the new event edit page.
491
-     *
492
-     * @return void
493
-     * @access protected
494
-     * @throws EE_Error If EE_Event is not available with given ID
495
-     */
496
-    protected function _duplicate_event()
497
-    {
498
-        // first make sure the ID for the event is in the request.
499
-        //  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
500
-        if (! isset($this->_req_data['EVT_ID'])) {
501
-            EE_Error::add_error(
502
-                esc_html__(
503
-                    'In order to duplicate an event an Event ID is required.  None was given.',
504
-                    'event_espresso'
505
-                ),
506
-                __FILE__,
507
-                __FUNCTION__,
508
-                __LINE__
509
-            );
510
-            $this->_redirect_after_action(false, '', '', array(), true);
511
-            return;
512
-        }
513
-        //k we've got EVT_ID so let's use that to get the event we'll duplicate
514
-        $orig_event = EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID']);
515
-        if (! $orig_event instanceof EE_Event) {
516
-            throw new EE_Error(
517
-                sprintf(
518
-                    esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
519
-                    $this->_req_data['EVT_ID']
520
-                )
521
-            );
522
-        }
523
-        //k now let's clone the $orig_event before getting relations
524
-        $new_event = clone $orig_event;
525
-        //original datetimes
526
-        $orig_datetimes = $orig_event->get_many_related('Datetime');
527
-        //other original relations
528
-        $orig_ven = $orig_event->get_many_related('Venue');
529
-        //reset the ID and modify other details to make it clear this is a dupe
530
-        $new_event->set('EVT_ID', 0);
531
-        $new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
532
-        $new_event->set('EVT_name', $new_name);
533
-        $new_event->set(
534
-            'EVT_slug',
535
-            wp_unique_post_slug(
536
-                sanitize_title($orig_event->name()),
537
-                0,
538
-                'publish',
539
-                'espresso_events',
540
-                0
541
-            )
542
-        );
543
-        $new_event->set('status', 'draft');
544
-        //duplicate discussion settings
545
-        $new_event->set('comment_status', $orig_event->get('comment_status'));
546
-        $new_event->set('ping_status', $orig_event->get('ping_status'));
547
-        //save the new event
548
-        $new_event->save();
549
-        //venues
550
-        foreach ($orig_ven as $ven) {
551
-            $new_event->_add_relation_to($ven, 'Venue');
552
-        }
553
-        $new_event->save();
554
-        //now we need to get the question group relations and handle that
555
-        //first primary question groups
556
-        $orig_primary_qgs = $orig_event->get_many_related(
557
-            'Question_Group',
558
-            array(array('Event_Question_Group.EQG_primary' => 1))
559
-        );
560
-        if (! empty($orig_primary_qgs)) {
561
-            foreach ($orig_primary_qgs as $id => $obj) {
562
-                if ($obj instanceof EE_Question_Group) {
563
-                    $new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 1));
564
-                }
565
-            }
566
-        }
567
-        //next additional attendee question groups
568
-        $orig_additional_qgs = $orig_event->get_many_related(
569
-            'Question_Group',
570
-            array(array('Event_Question_Group.EQG_primary' => 0))
571
-        );
572
-        if (! empty($orig_additional_qgs)) {
573
-            foreach ($orig_additional_qgs as $id => $obj) {
574
-                if ($obj instanceof EE_Question_Group) {
575
-                    $new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 0));
576
-                }
577
-            }
578
-        }
579
-
580
-        $new_event->save();
581
-
582
-        //k now that we have the new event saved we can loop through the datetimes and start adding relations.
583
-        $cloned_tickets = array();
584
-        foreach ($orig_datetimes as $orig_dtt) {
585
-            if (! $orig_dtt instanceof EE_Datetime) {
586
-                continue;
587
-            }
588
-            $new_dtt   = clone $orig_dtt;
589
-            $orig_tkts = $orig_dtt->tickets();
590
-            //save new dtt then add to event
591
-            $new_dtt->set('DTT_ID', 0);
592
-            $new_dtt->set('DTT_sold', 0);
593
-            $new_dtt->set_reserved(0);
594
-            $new_dtt->save();
595
-            $new_event->_add_relation_to($new_dtt, 'Datetime');
596
-            $new_event->save();
597
-            //now let's get the ticket relations setup.
598
-            foreach ((array)$orig_tkts as $orig_tkt) {
599
-                //it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
600
-                if (! $orig_tkt instanceof EE_Ticket) {
601
-                    continue;
602
-                }
603
-                //is this ticket archived?  If it is then let's skip
604
-                if ($orig_tkt->get('TKT_deleted')) {
605
-                    continue;
606
-                }
607
-                // does this original ticket already exist in the clone_tickets cache?
608
-                //  If so we'll just use the new ticket from it.
609
-                if (isset($cloned_tickets[$orig_tkt->ID()])) {
610
-                    $new_tkt = $cloned_tickets[$orig_tkt->ID()];
611
-                } else {
612
-                    $new_tkt = clone $orig_tkt;
613
-                    //get relations on the $orig_tkt that we need to setup.
614
-                    $orig_prices = $orig_tkt->prices();
615
-                    $new_tkt->set('TKT_ID', 0);
616
-                    $new_tkt->set('TKT_sold', 0);
617
-                    $new_tkt->set('TKT_reserved', 0);
618
-                    $new_tkt->save(); //make sure new ticket has ID.
619
-                    //price relations on new ticket need to be setup.
620
-                    foreach ($orig_prices as $orig_price) {
621
-                        $new_price = clone $orig_price;
622
-                        $new_price->set('PRC_ID', 0);
623
-                        $new_price->save();
624
-                        $new_tkt->_add_relation_to($new_price, 'Price');
625
-                        $new_tkt->save();
626
-                    }
627
-
628
-                    do_action(
629
-                        'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
630
-                        $orig_tkt,
631
-                        $new_tkt,
632
-                        $orig_prices,
633
-                        $orig_event,
634
-                        $orig_dtt,
635
-                        $new_dtt
636
-                    );
637
-                }
638
-                // k now we can add the new ticket as a relation to the new datetime
639
-                // and make sure its added to our cached $cloned_tickets array
640
-                // for use with later datetimes that have the same ticket.
641
-                $new_dtt->_add_relation_to($new_tkt, 'Ticket');
642
-                $new_dtt->save();
643
-                $cloned_tickets[$orig_tkt->ID()] = $new_tkt;
644
-            }
645
-        }
646
-        //clone taxonomy information
647
-        $taxonomies_to_clone_with = apply_filters(
648
-            'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
649
-            array('espresso_event_categories', 'espresso_event_type', 'post_tag')
650
-        );
651
-        //get terms for original event (notice)
652
-        $orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
653
-        //loop through terms and add them to new event.
654
-        foreach ($orig_terms as $term) {
655
-            wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
656
-        }
657
-
658
-        //duplicate other core WP_Post items for this event.
659
-        //post thumbnail (feature image).
660
-        $feature_image_id = get_post_thumbnail_id($orig_event->ID());
661
-        if ($feature_image_id) {
662
-            update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
663
-        }
664
-
665
-        //duplicate page_template setting
666
-        $page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
667
-        if ($page_template) {
668
-            update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
669
-        }
670
-
671
-        do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
672
-        //now let's redirect to the edit page for this duplicated event if we have a new event id.
673
-        if ($new_event->ID()) {
674
-            $redirect_args = array(
675
-                'post'   => $new_event->ID(),
676
-                'action' => 'edit',
677
-            );
678
-            EE_Error::add_success(
679
-                esc_html__(
680
-                    'Event successfully duplicated.  Please review the details below and make any necessary edits',
681
-                    'event_espresso'
682
-                )
683
-            );
684
-        } else {
685
-            $redirect_args = array(
686
-                'action' => 'default',
687
-            );
688
-            EE_Error::add_error(
689
-                esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
690
-                __FILE__,
691
-                __FUNCTION__,
692
-                __LINE__
693
-            );
694
-        }
695
-        $this->_redirect_after_action(false, '', '', $redirect_args, true);
696
-    }
697
-
698
-
699
-    /**
700
-     * Generates output for the import page.
701
-     * @throws DomainException
702
-     */
703
-    protected function _import_page()
704
-    {
705
-        $title                                      = esc_html__('Import', 'event_espresso');
706
-        $intro                                      = esc_html__(
707
-            'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
708
-            'event_espresso'
709
-        );
710
-        $form_url                                   = EVENTS_ADMIN_URL;
711
-        $action                                     = 'import_events';
712
-        $type                                       = 'csv';
713
-        $this->_template_args['form']               = EE_Import::instance()->upload_form(
714
-            $title, $intro, $form_url, $action, $type
715
-        );
716
-        $this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
717
-            array('action' => 'sample_export_file'),
718
-            $this->_admin_base_url
719
-        );
720
-        $content                                    = EEH_Template::display_template(
721
-            EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
722
-            $this->_template_args,
723
-            true
724
-        );
725
-        $this->_template_args['admin_page_content'] = $content;
726
-        $this->display_admin_page_with_sidebar();
727
-    }
728
-
729
-
730
-    /**
731
-     * _import_events
732
-     * This handles displaying the screen and running imports for importing events.
733
-     *
734
-     * @return void
735
-     */
736
-    protected function _import_events()
737
-    {
738
-        require_once(EE_CLASSES . 'EE_Import.class.php');
739
-        $success = EE_Import::instance()->import();
740
-        $this->_redirect_after_action($success, 'Import File', 'ran', array('action' => 'import_page'), true);
741
-    }
742
-
743
-
744
-    /**
745
-     * _events_export
746
-     * Will export all (or just the given event) to a Excel compatible file.
747
-     *
748
-     * @access protected
749
-     * @return void
750
-     */
751
-    protected function _events_export()
752
-    {
753
-        if (isset($this->_req_data['EVT_ID'])) {
754
-            $event_ids = $this->_req_data['EVT_ID'];
755
-        } elseif (isset($this->_req_data['EVT_IDs'])) {
756
-            $event_ids = $this->_req_data['EVT_IDs'];
757
-        } else {
758
-            $event_ids = null;
759
-        }
760
-        //todo: I don't like doing this but it'll do until we modify EE_Export Class.
761
-        $new_request_args = array(
762
-            'export' => 'report',
763
-            'action' => 'all_event_data',
764
-            'EVT_ID' => $event_ids,
765
-        );
766
-        $this->_req_data  = array_merge($this->_req_data, $new_request_args);
767
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
768
-            require_once(EE_CLASSES . 'EE_Export.class.php');
769
-            $EE_Export = EE_Export::instance($this->_req_data);
770
-            $EE_Export->export();
771
-        }
772
-    }
773
-
774
-
775
-    /**
776
-     * handle category exports()
777
-     *
778
-     * @return void
779
-     */
780
-    protected function _categories_export()
781
-    {
782
-        //todo: I don't like doing this but it'll do until we modify EE_Export Class.
783
-        $new_request_args = array(
784
-            'export'       => 'report',
785
-            'action'       => 'categories',
786
-            'category_ids' => $this->_req_data['EVT_CAT_ID'],
787
-        );
788
-        $this->_req_data  = array_merge($this->_req_data, $new_request_args);
789
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
790
-            require_once(EE_CLASSES . 'EE_Export.class.php');
791
-            $EE_Export = EE_Export::instance($this->_req_data);
792
-            $EE_Export->export();
793
-        }
794
-    }
795
-
796
-
797
-    /**
798
-     * Creates a sample CSV file for importing
799
-     */
800
-    protected function _sample_export_file()
801
-    {
802
-        //		require_once(EE_CLASSES . 'EE_Export.class.php');
803
-        EE_Export::instance()->export_sample();
804
-    }
805
-
806
-
807
-    /*************        Template Settings        *************/
808
-    /**
809
-     * Generates template settings page output
810
-     * @throws DomainException
811
-     * @throws EE_Error
812
-     */
813
-    protected function _template_settings()
814
-    {
815
-        $this->_template_args['values'] = $this->_yes_no_values;
816
-        /**
817
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
818
-         * from General_Settings_Admin_Page to here.
819
-         */
820
-        $this->_template_args = apply_filters(
821
-            'FHEE__General_Settings_Admin_Page__template_settings__template_args',
822
-            $this->_template_args
823
-        );
824
-        $this->_set_add_edit_form_tags('update_template_settings');
825
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
826
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
827
-            EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
828
-            $this->_template_args,
829
-            true
830
-        );
831
-        $this->display_admin_page_with_sidebar();
832
-    }
833
-
834
-
835
-    /**
836
-     * Handler for updating template settings.
837
-     */
838
-    protected function _update_template_settings()
839
-    {
840
-        /**
841
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
842
-         * from General_Settings_Admin_Page to here.
843
-         */
844
-        EE_Registry::instance()->CFG->template_settings = apply_filters(
845
-            'FHEE__General_Settings_Admin_Page__update_template_settings__data',
846
-            EE_Registry::instance()->CFG->template_settings,
847
-            $this->_req_data
848
-        );
849
-        //update custom post type slugs and detect if we need to flush rewrite rules
850
-        $old_slug                                          = EE_Registry::instance()->CFG->core->event_cpt_slug;
851
-        EE_Registry::instance()->CFG->core->event_cpt_slug = empty($this->_req_data['event_cpt_slug'])
852
-            ? EE_Registry::instance()->CFG->core->event_cpt_slug
853
-            : sanitize_title_with_dashes($this->_req_data['event_cpt_slug']);
854
-        $what                                              = 'Template Settings';
855
-        $success                                           = $this->_update_espresso_configuration(
856
-            $what,
857
-            EE_Registry::instance()->CFG->template_settings,
858
-            __FILE__,
859
-            __FUNCTION__,
860
-            __LINE__
861
-        );
862
-        if (EE_Registry::instance()->CFG->core->event_cpt_slug != $old_slug) {
863
-            update_option('ee_flush_rewrite_rules', true);
864
-        }
865
-        $this->_redirect_after_action($success, $what, 'updated', array('action' => 'template_settings'));
866
-    }
867
-
868
-
869
-    /**
870
-     * _premium_event_editor_meta_boxes
871
-     * add all metaboxes related to the event_editor
872
-     *
873
-     * @access protected
874
-     * @return void
875
-     * @throws EE_Error
876
-     */
877
-    protected function _premium_event_editor_meta_boxes()
878
-    {
879
-        $this->verify_cpt_object();
880
-        add_meta_box(
881
-            'espresso_event_editor_event_options',
882
-            esc_html__('Event Registration Options', 'event_espresso'),
883
-            array($this, 'registration_options_meta_box'),
884
-            $this->page_slug,
885
-            'side',
886
-            'core'
887
-        );
888
-    }
889
-
890
-
891
-    /**
892
-     * override caf metabox
893
-     *
894
-     * @return void
895
-     * @throws DomainException
896
-     */
897
-    public function registration_options_meta_box()
898
-    {
899
-        $yes_no_values                                    = array(
900
-            array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
901
-            array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
902
-        );
903
-        $default_reg_status_values                        = EEM_Registration::reg_status_array(
904
-            array(
905
-                EEM_Registration::status_id_cancelled,
906
-                EEM_Registration::status_id_declined,
907
-                EEM_Registration::status_id_incomplete,
908
-                EEM_Registration::status_id_wait_list,
909
-            ),
910
-            true
911
-        );
912
-        $template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
913
-        $template_args['_event']                          = $this->_cpt_model_obj;
914
-        $template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
915
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
916
-            'default_reg_status',
917
-            $default_reg_status_values,
918
-            $this->_cpt_model_obj->default_registration_status()
919
-        );
920
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
921
-            'display_desc',
922
-            $yes_no_values,
923
-            $this->_cpt_model_obj->display_description()
924
-        );
925
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
926
-            'display_ticket_selector',
927
-            $yes_no_values,
928
-            $this->_cpt_model_obj->display_ticket_selector(),
929
-            '',
930
-            '',
931
-            false
932
-        );
933
-        $template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
934
-            'EVT_default_registration_status',
935
-            $default_reg_status_values,
936
-            $this->_cpt_model_obj->default_registration_status()
937
-        );
938
-        $template_args['additional_registration_options'] = apply_filters(
939
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
940
-            '',
941
-            $template_args,
942
-            $yes_no_values,
943
-            $default_reg_status_values
944
-        );
945
-        EEH_Template::display_template(
946
-            EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
947
-            $template_args
948
-        );
949
-    }
950
-
951
-
952
-
953
-    /**
954
-     * wp_list_table_mods for caf
955
-     * ============================
956
-     */
957
-    /**
958
-     * hook into list table filters and provide filters for caffeinated list table
959
-     *
960
-     * @param  array $old_filters    any existing filters present
961
-     * @param  array $list_table_obj the list table object
962
-     * @return array                  new filters
963
-     */
964
-    public function list_table_filters($old_filters, $list_table_obj)
965
-    {
966
-        $filters = array();
967
-        //first month/year filters
968
-        $filters[] = $this->espresso_event_months_dropdown();
969
-        $status    = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
970
-        //active status dropdown
971
-        if ($status !== 'draft') {
972
-            $filters[] = $this->active_status_dropdown(
973
-                isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : ''
974
-            );
975
-        }
976
-        //category filter
977
-        $filters[] = $this->category_dropdown();
978
-        return array_merge($old_filters, $filters);
979
-    }
980
-
981
-
982
-    /**
983
-     * espresso_event_months_dropdown
984
-     *
985
-     * @access public
986
-     * @return string                dropdown listing month/year selections for events.
987
-     */
988
-    public function espresso_event_months_dropdown()
989
-    {
990
-        // what we need to do is get all PRIMARY datetimes for all events to filter on.
991
-        // Note we need to include any other filters that are set!
992
-        $status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
993
-        //categories?
994
-        $category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
995
-            ? $this->_req_data['EVT_CAT']
996
-            : null;
997
-        //active status?
998
-        $active_status = isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : null;
999
-        $cur_date      = isset($this->_req_data['month_range']) ? $this->_req_data['month_range'] : '';
1000
-        return EEH_Form_Fields::generate_event_months_dropdown($cur_date, $status, $category, $active_status);
1001
-    }
1002
-
1003
-
1004
-    /**
1005
-     * returns a list of "active" statuses on the event
1006
-     *
1007
-     * @param  string $current_value whatever the current active status is
1008
-     * @return string
1009
-     */
1010
-    public function active_status_dropdown($current_value = '')
1011
-    {
1012
-        $select_name = 'active_status';
1013
-        $values      = array(
1014
-            'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1015
-            'active'   => esc_html__('Active', 'event_espresso'),
1016
-            'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1017
-            'expired'  => esc_html__('Expired', 'event_espresso'),
1018
-            'inactive' => esc_html__('Inactive', 'event_espresso'),
1019
-        );
1020
-        $id          = 'id="espresso-active-status-dropdown-filter"';
1021
-        $class       = 'wide';
1022
-        return EEH_Form_Fields::select_input($select_name, $values, $current_value, $id, $class);
1023
-    }
1024
-
1025
-
1026
-    /**
1027
-     * output a dropdown of the categories for the category filter on the event admin list table
1028
-     *
1029
-     * @access  public
1030
-     * @return string html
1031
-     */
1032
-    public function category_dropdown()
1033
-    {
1034
-        $cur_cat = isset($this->_req_data['EVT_CAT']) ? $this->_req_data['EVT_CAT'] : -1;
1035
-        return EEH_Form_Fields::generate_event_category_dropdown($cur_cat);
1036
-    }
1037
-
1038
-
1039
-    /**
1040
-     * get total number of events today
1041
-     *
1042
-     * @access public
1043
-     * @return int
1044
-     * @throws EE_Error
1045
-     */
1046
-    public function total_events_today()
1047
-    {
1048
-        $start = EEM_Datetime::instance()->convert_datetime_for_query(
1049
-            'DTT_EVT_start',
1050
-            date('Y-m-d') . ' 00:00:00',
1051
-            'Y-m-d H:i:s',
1052
-            'UTC'
1053
-        );
1054
-        $end   = EEM_Datetime::instance()->convert_datetime_for_query(
1055
-            'DTT_EVT_start',
1056
-            date('Y-m-d') . ' 23:59:59',
1057
-            'Y-m-d H:i:s',
1058
-            'UTC'
1059
-        );
1060
-        $where = array(
1061
-            'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1062
-        );
1063
-        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1064
-        return $count;
1065
-    }
1066
-
1067
-
1068
-    /**
1069
-     * get total number of events this month
1070
-     *
1071
-     * @access public
1072
-     * @return int
1073
-     * @throws EE_Error
1074
-     */
1075
-    public function total_events_this_month()
1076
-    {
1077
-        //Dates
1078
-        $this_year_r     = date('Y');
1079
-        $this_month_r    = date('m');
1080
-        $days_this_month = date('t');
1081
-        $start           = EEM_Datetime::instance()->convert_datetime_for_query(
1082
-            'DTT_EVT_start',
1083
-            $this_year_r . '-' . $this_month_r . '-01 00:00:00',
1084
-            'Y-m-d H:i:s',
1085
-            'UTC'
1086
-        );
1087
-        $end             = EEM_Datetime::instance()->convert_datetime_for_query(
1088
-            'DTT_EVT_start',
1089
-            $this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1090
-            'Y-m-d H:i:s',
1091
-            'UTC'
1092
-        );
1093
-        $where           = array(
1094
-            'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1095
-        );
1096
-        $count           = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1097
-        return $count;
1098
-    }
1099
-
1100
-
1101
-    /** DEFAULT TICKETS STUFF **/
1102
-
1103
-    /**
1104
-     * Output default tickets list table view.
1105
-     */
1106
-    public function _tickets_overview_list_table()
1107
-    {
1108
-        $this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1109
-        $this->display_admin_list_table_page_with_no_sidebar();
1110
-    }
1111
-
1112
-
1113
-    /**
1114
-     * @param int  $per_page
1115
-     * @param bool $count
1116
-     * @param bool $trashed
1117
-     * @return \EE_Soft_Delete_Base_Class[]|int
1118
-     */
1119
-    public function get_default_tickets($per_page = 10, $count = false, $trashed = false)
1120
-    {
1121
-        $orderby = empty($this->_req_data['orderby']) ? 'TKT_name' : $this->_req_data['orderby'];
1122
-        $order   = empty($this->_req_data['order']) ? 'ASC' : $this->_req_data['order'];
1123
-        switch ($orderby) {
1124
-            case 'TKT_name':
1125
-                $orderby = array('TKT_name' => $order);
1126
-                break;
1127
-            case 'TKT_price':
1128
-                $orderby = array('TKT_price' => $order);
1129
-                break;
1130
-            case 'TKT_uses':
1131
-                $orderby = array('TKT_uses' => $order);
1132
-                break;
1133
-            case 'TKT_min':
1134
-                $orderby = array('TKT_min' => $order);
1135
-                break;
1136
-            case 'TKT_max':
1137
-                $orderby = array('TKT_max' => $order);
1138
-                break;
1139
-            case 'TKT_qty':
1140
-                $orderby = array('TKT_qty' => $order);
1141
-                break;
1142
-        }
1143
-        $current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
1144
-            ? $this->_req_data['paged']
1145
-            : 1;
1146
-        $per_page     = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
1147
-            ? $this->_req_data['perpage']
1148
-            : $per_page;
1149
-        $_where       = array(
1150
-            'TKT_is_default' => 1,
1151
-            'TKT_deleted'    => $trashed,
1152
-        );
1153
-        $offset       = ($current_page - 1) * $per_page;
1154
-        $limit        = array($offset, $per_page);
1155
-        if (isset($this->_req_data['s'])) {
1156
-            $sstr         = '%' . $this->_req_data['s'] . '%';
1157
-            $_where['OR'] = array(
1158
-                'TKT_name'        => array('LIKE', $sstr),
1159
-                'TKT_description' => array('LIKE', $sstr),
1160
-            );
1161
-        }
1162
-        $query_params = array(
1163
-            $_where,
1164
-            'order_by' => $orderby,
1165
-            'limit'    => $limit,
1166
-            'group_by' => 'TKT_ID',
1167
-        );
1168
-        if ($count) {
1169
-            return EEM_Ticket::instance()->count_deleted_and_undeleted(array($_where));
1170
-        } else {
1171
-            return EEM_Ticket::instance()->get_all_deleted_and_undeleted($query_params);
1172
-        }
1173
-    }
1174
-
1175
-
1176
-    /**
1177
-     * @param bool $trash
1178
-     * @throws EE_Error
1179
-     */
1180
-    protected function _trash_or_restore_ticket($trash = false)
1181
-    {
1182
-        $success = 1;
1183
-        $TKT     = EEM_Ticket::instance();
1184
-        //checkboxes?
1185
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1186
-            //if array has more than one element then success message should be plural
1187
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1188
-            //cycle thru the boxes
1189
-            while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1190
-                if ($trash) {
1191
-                    if (! $TKT->delete_by_ID($TKT_ID)) {
1192
-                        $success = 0;
1193
-                    }
1194
-                } else {
1195
-                    if (! $TKT->restore_by_ID($TKT_ID)) {
1196
-                        $success = 0;
1197
-                    }
1198
-                }
1199
-            }
1200
-        } else {
1201
-            //grab single id and trash
1202
-            $TKT_ID = absint($this->_req_data['TKT_ID']);
1203
-            if ($trash) {
1204
-                if (! $TKT->delete_by_ID($TKT_ID)) {
1205
-                    $success = 0;
1206
-                }
1207
-            } else {
1208
-                if (! $TKT->restore_by_ID($TKT_ID)) {
1209
-                    $success = 0;
1210
-                }
1211
-            }
1212
-        }
1213
-        $action_desc = $trash ? 'moved to the trash' : 'restored';
1214
-        $query_args  = array(
1215
-            'action' => 'ticket_list_table',
1216
-            'status' => $trash ? '' : 'trashed',
1217
-        );
1218
-        $this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1219
-    }
1220
-
1221
-
1222
-    /**
1223
-     * Handles trashing default ticket.
1224
-     */
1225
-    protected function _delete_ticket()
1226
-    {
1227
-        $success = 1;
1228
-        //checkboxes?
1229
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1230
-            //if array has more than one element then success message should be plural
1231
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1232
-            //cycle thru the boxes
1233
-            while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1234
-                //delete
1235
-                if (! $this->_delete_the_ticket($TKT_ID)) {
1236
-                    $success = 0;
1237
-                }
1238
-            }
1239
-        } else {
1240
-            //grab single id and trash
1241
-            $TKT_ID = absint($this->_req_data['TKT_ID']);
1242
-            if (! $this->_delete_the_ticket($TKT_ID)) {
1243
-                $success = 0;
1244
-            }
1245
-        }
1246
-        $action_desc = 'deleted';
1247
-        $query_args  = array(
1248
-            'action' => 'ticket_list_table',
1249
-            'status' => 'trashed',
1250
-        );
1251
-        //fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1252
-        if (EEM_Ticket::instance()->count_deleted_and_undeleted(
1253
-            array(array('TKT_is_default' => 1)),
1254
-            'TKT_ID',
1255
-            true
1256
-        )
1257
-        ) {
1258
-            $query_args = array();
1259
-        }
1260
-        $this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1261
-    }
1262
-
1263
-
1264
-    /**
1265
-     * @param int $TKT_ID
1266
-     * @return bool|int
1267
-     * @throws EE_Error
1268
-     */
1269
-    protected function _delete_the_ticket($TKT_ID)
1270
-    {
1271
-        $tkt = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1272
-        $tkt->_remove_relations('Datetime');
1273
-        //delete all related prices first
1274
-        $tkt->delete_related_permanently('Price');
1275
-        return $tkt->delete_permanently();
1276
-    }
17
+	/**
18
+	 * Extend_Events_Admin_Page constructor.
19
+	 *
20
+	 * @param bool $routing
21
+	 */
22
+	public function __construct($routing = true)
23
+	{
24
+		parent::__construct($routing);
25
+		if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
26
+			define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
27
+			define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
28
+			define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
29
+		}
30
+	}
31
+
32
+
33
+	/**
34
+	 * Sets routes.
35
+	 */
36
+	protected function _extend_page_config()
37
+	{
38
+		$this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
39
+		//is there a evt_id in the request?
40
+		$evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
41
+			? $this->_req_data['EVT_ID']
42
+			: 0;
43
+		$evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
44
+		//tkt_id?
45
+		$tkt_id             = ! empty($this->_req_data['TKT_ID']) && ! is_array($this->_req_data['TKT_ID'])
46
+			? $this->_req_data['TKT_ID']
47
+			: 0;
48
+		$new_page_routes    = array(
49
+			'duplicate_event'          => array(
50
+				'func'       => '_duplicate_event',
51
+				'capability' => 'ee_edit_event',
52
+				'obj_id'     => $evt_id,
53
+				'noheader'   => true,
54
+			),
55
+			'ticket_list_table'        => array(
56
+				'func'       => '_tickets_overview_list_table',
57
+				'capability' => 'ee_read_default_tickets',
58
+			),
59
+			'trash_ticket'             => array(
60
+				'func'       => '_trash_or_restore_ticket',
61
+				'capability' => 'ee_delete_default_ticket',
62
+				'obj_id'     => $tkt_id,
63
+				'noheader'   => true,
64
+				'args'       => array('trash' => true),
65
+			),
66
+			'trash_tickets'            => array(
67
+				'func'       => '_trash_or_restore_ticket',
68
+				'capability' => 'ee_delete_default_tickets',
69
+				'noheader'   => true,
70
+				'args'       => array('trash' => true),
71
+			),
72
+			'restore_ticket'           => array(
73
+				'func'       => '_trash_or_restore_ticket',
74
+				'capability' => 'ee_delete_default_ticket',
75
+				'obj_id'     => $tkt_id,
76
+				'noheader'   => true,
77
+			),
78
+			'restore_tickets'          => array(
79
+				'func'       => '_trash_or_restore_ticket',
80
+				'capability' => 'ee_delete_default_tickets',
81
+				'noheader'   => true,
82
+			),
83
+			'delete_ticket'            => array(
84
+				'func'       => '_delete_ticket',
85
+				'capability' => 'ee_delete_default_ticket',
86
+				'obj_id'     => $tkt_id,
87
+				'noheader'   => true,
88
+			),
89
+			'delete_tickets'           => array(
90
+				'func'       => '_delete_ticket',
91
+				'capability' => 'ee_delete_default_tickets',
92
+				'noheader'   => true,
93
+			),
94
+			'import_page'              => array(
95
+				'func'       => '_import_page',
96
+				'capability' => 'import',
97
+			),
98
+			'import'                   => array(
99
+				'func'       => '_import_events',
100
+				'capability' => 'import',
101
+				'noheader'   => true,
102
+			),
103
+			'import_events'            => array(
104
+				'func'       => '_import_events',
105
+				'capability' => 'import',
106
+				'noheader'   => true,
107
+			),
108
+			'export_events'            => array(
109
+				'func'       => '_events_export',
110
+				'capability' => 'export',
111
+				'noheader'   => true,
112
+			),
113
+			'export_categories'        => array(
114
+				'func'       => '_categories_export',
115
+				'capability' => 'export',
116
+				'noheader'   => true,
117
+			),
118
+			'sample_export_file'       => array(
119
+				'func'       => '_sample_export_file',
120
+				'capability' => 'export',
121
+				'noheader'   => true,
122
+			),
123
+			'update_template_settings' => array(
124
+				'func'       => '_update_template_settings',
125
+				'capability' => 'manage_options',
126
+				'noheader'   => true,
127
+			),
128
+		);
129
+		$this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
130
+		//partial route/config override
131
+		$this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
132
+		$this->_page_config['create_new']['metaboxes'][]  = '_premium_event_editor_meta_boxes';
133
+		$this->_page_config['create_new']['qtips'][]      = 'EE_Event_Editor_Tips';
134
+		$this->_page_config['edit']['qtips'][]            = 'EE_Event_Editor_Tips';
135
+		$this->_page_config['edit']['metaboxes'][]        = '_premium_event_editor_meta_boxes';
136
+		$this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
137
+		//add tickets tab but only if there are more than one default ticket!
138
+		$tkt_count = EEM_Ticket::instance()->count_deleted_and_undeleted(
139
+			array(array('TKT_is_default' => 1)),
140
+			'TKT_ID',
141
+			true
142
+		);
143
+		if ($tkt_count > 1) {
144
+			$new_page_config = array(
145
+				'ticket_list_table' => array(
146
+					'nav'           => array(
147
+						'label' => esc_html__('Default Tickets', 'event_espresso'),
148
+						'order' => 60,
149
+					),
150
+					'list_table'    => 'Tickets_List_Table',
151
+					'require_nonce' => false,
152
+				),
153
+			);
154
+		}
155
+		//template settings
156
+		$new_page_config['template_settings'] = array(
157
+			'nav'           => array(
158
+				'label' => esc_html__('Templates', 'event_espresso'),
159
+				'order' => 30,
160
+			),
161
+			'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
162
+			'help_tabs'     => array(
163
+				'general_settings_templates_help_tab' => array(
164
+					'title'    => esc_html__('Templates', 'event_espresso'),
165
+					'filename' => 'general_settings_templates',
166
+				),
167
+			),
168
+			'help_tour'     => array('Templates_Help_Tour'),
169
+			'require_nonce' => false,
170
+		);
171
+		$this->_page_config                   = array_merge($this->_page_config, $new_page_config);
172
+		//add filters and actions
173
+		//modifying _views
174
+		add_filter(
175
+			'FHEE_event_datetime_metabox_add_additional_date_time_template',
176
+			array($this, 'add_additional_datetime_button'),
177
+			10,
178
+			2
179
+		);
180
+		add_filter(
181
+			'FHEE_event_datetime_metabox_clone_button_template',
182
+			array($this, 'add_datetime_clone_button'),
183
+			10,
184
+			2
185
+		);
186
+		add_filter(
187
+			'FHEE_event_datetime_metabox_timezones_template',
188
+			array($this, 'datetime_timezones_template'),
189
+			10,
190
+			2
191
+		);
192
+		//filters for event list table
193
+		add_filter('FHEE__Extend_Events_Admin_List_Table__filters', array($this, 'list_table_filters'), 10, 2);
194
+		add_filter(
195
+			'FHEE__Events_Admin_List_Table__column_actions__action_links',
196
+			array($this, 'extra_list_table_actions'),
197
+			10,
198
+			2
199
+		);
200
+		//legend item
201
+		add_filter('FHEE__Events_Admin_Page___event_legend_items__items', array($this, 'additional_legend_items'));
202
+		add_action('admin_init', array($this, 'admin_init'));
203
+		//heartbeat stuff
204
+		add_filter('heartbeat_received', array($this, 'heartbeat_response'), 10, 2);
205
+	}
206
+
207
+
208
+	/**
209
+	 * admin_init
210
+	 */
211
+	public function admin_init()
212
+	{
213
+		EE_Registry::$i18n_js_strings = array_merge(
214
+			EE_Registry::$i18n_js_strings,
215
+			array(
216
+				'image_confirm'          => esc_html__(
217
+					'Do you really want to delete this image? Please remember to update your event to complete the removal.',
218
+					'event_espresso'
219
+				),
220
+				'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
221
+				'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
222
+				'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
223
+				'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
224
+				'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
225
+			)
226
+		);
227
+	}
228
+
229
+
230
+	/**
231
+	 * This will be used to listen for any heartbeat data packages coming via the WordPress heartbeat API and handle
232
+	 * accordingly.
233
+	 *
234
+	 * @param array $response The existing heartbeat response array.
235
+	 * @param array $data     The incoming data package.
236
+	 * @return array  possibly appended response.
237
+	 */
238
+	public function heartbeat_response($response, $data)
239
+	{
240
+		/**
241
+		 * check whether count of tickets is approaching the potential
242
+		 * limits for the server.
243
+		 */
244
+		if (! empty($data['input_count'])) {
245
+			$response['max_input_vars_check'] = EE_Registry::instance()->CFG->environment->max_input_vars_limit_check(
246
+				$data['input_count']
247
+			);
248
+		}
249
+		return $response;
250
+	}
251
+
252
+
253
+	/**
254
+	 * Add per page screen options to the default ticket list table view.
255
+	 */
256
+	protected function _add_screen_options_ticket_list_table()
257
+	{
258
+		$this->_per_page_screen_option();
259
+	}
260
+
261
+
262
+	/**
263
+	 * @param string $return
264
+	 * @param int    $id
265
+	 * @param string $new_title
266
+	 * @param string $new_slug
267
+	 * @return string
268
+	 */
269
+	public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
270
+	{
271
+		$return = parent::extra_permalink_field_buttons($return, $id, $new_title, $new_slug);
272
+		//make sure this is only when editing
273
+		if (! empty($id)) {
274
+			$href   = EE_Admin_Page::add_query_args_and_nonce(
275
+				array('action' => 'duplicate_event', 'EVT_ID' => $id),
276
+				$this->_admin_base_url
277
+			);
278
+			$title  = esc_attr__('Duplicate Event', 'event_espresso');
279
+			$return .= '<a href="'
280
+					   . $href
281
+					   . '" title="'
282
+					   . $title
283
+					   . '" id="ee-duplicate-event-button" class="button button-small"  value="duplicate_event">'
284
+					   . $title
285
+					   . '</button>';
286
+		}
287
+		return $return;
288
+	}
289
+
290
+
291
+	/**
292
+	 * Set the list table views for the default ticket list table view.
293
+	 */
294
+	public function _set_list_table_views_ticket_list_table()
295
+	{
296
+		$this->_views = array(
297
+			'all'     => array(
298
+				'slug'        => 'all',
299
+				'label'       => esc_html__('All', 'event_espresso'),
300
+				'count'       => 0,
301
+				'bulk_action' => array(
302
+					'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
303
+				),
304
+			),
305
+			'trashed' => array(
306
+				'slug'        => 'trashed',
307
+				'label'       => esc_html__('Trash', 'event_espresso'),
308
+				'count'       => 0,
309
+				'bulk_action' => array(
310
+					'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
311
+					'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
312
+				),
313
+			),
314
+		);
315
+	}
316
+
317
+
318
+	/**
319
+	 * Enqueue scripts and styles for the event editor.
320
+	 */
321
+	public function load_scripts_styles_edit()
322
+	{
323
+		wp_register_script(
324
+			'ee-event-editor-heartbeat',
325
+			EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
326
+			array('ee_admin_js', 'heartbeat'),
327
+			EVENT_ESPRESSO_VERSION,
328
+			true
329
+		);
330
+		wp_enqueue_script('ee-accounting');
331
+		//styles
332
+		wp_enqueue_style('espresso-ui-theme');
333
+		wp_enqueue_script('event_editor_js');
334
+		wp_enqueue_script('ee-event-editor-heartbeat');
335
+	}
336
+
337
+
338
+	/**
339
+	 * Returns template for the additional datetime.
340
+	 * @param $template
341
+	 * @param $template_args
342
+	 * @return mixed
343
+	 * @throws DomainException
344
+	 */
345
+	public function add_additional_datetime_button($template, $template_args)
346
+	{
347
+		return EEH_Template::display_template(
348
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php',
349
+			$template_args,
350
+			true
351
+		);
352
+	}
353
+
354
+
355
+	/**
356
+	 * Returns the template for cloning a datetime.
357
+	 * @param $template
358
+	 * @param $template_args
359
+	 * @return mixed
360
+	 * @throws DomainException
361
+	 */
362
+	public function add_datetime_clone_button($template, $template_args)
363
+	{
364
+		return EEH_Template::display_template(
365
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php',
366
+			$template_args,
367
+			true
368
+		);
369
+	}
370
+
371
+
372
+	/**
373
+	 * Returns the template for datetime timezones.
374
+	 * @param $template
375
+	 * @param $template_args
376
+	 * @return mixed
377
+	 * @throws DomainException
378
+	 */
379
+	public function datetime_timezones_template($template, $template_args)
380
+	{
381
+		return EEH_Template::display_template(
382
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php',
383
+			$template_args,
384
+			true
385
+		);
386
+	}
387
+
388
+
389
+	/**
390
+	 * Sets the views for the default list table view.
391
+	 */
392
+	protected function _set_list_table_views_default()
393
+	{
394
+		parent::_set_list_table_views_default();
395
+		$new_views    = array(
396
+			'today' => array(
397
+				'slug'        => 'today',
398
+				'label'       => esc_html__('Today', 'event_espresso'),
399
+				'count'       => $this->total_events_today(),
400
+				'bulk_action' => array(
401
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
402
+				),
403
+			),
404
+			'month' => array(
405
+				'slug'        => 'month',
406
+				'label'       => esc_html__('This Month', 'event_espresso'),
407
+				'count'       => $this->total_events_this_month(),
408
+				'bulk_action' => array(
409
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
410
+				),
411
+			),
412
+		);
413
+		$this->_views = array_merge($this->_views, $new_views);
414
+	}
415
+
416
+
417
+	/**
418
+	 * Returns the extra action links for the default list table view.
419
+	 * @param array     $action_links
420
+	 * @param \EE_Event $event
421
+	 * @return array
422
+	 * @throws EE_Error
423
+	 */
424
+	public function extra_list_table_actions(array $action_links, \EE_Event $event)
425
+	{
426
+		if (EE_Registry::instance()->CAP->current_user_can(
427
+			'ee_read_registrations',
428
+			'espresso_registrations_reports',
429
+			$event->ID()
430
+		)
431
+		) {
432
+			$reports_query_args = array(
433
+				'action' => 'reports',
434
+				'EVT_ID' => $event->ID(),
435
+			);
436
+			$reports_link       = EE_Admin_Page::add_query_args_and_nonce($reports_query_args, REG_ADMIN_URL);
437
+			$action_links[]     = '<a href="'
438
+								  . $reports_link
439
+								  . '" title="'
440
+								  . esc_attr__('View Report', 'event_espresso')
441
+								  . '"><div class="dashicons dashicons-chart-bar"></div></a>'
442
+								  . "\n\t";
443
+		}
444
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
445
+			EE_Registry::instance()->load_helper('MSG_Template');
446
+			$action_links[] = EEH_MSG_Template::get_message_action_link(
447
+				'see_notifications_for',
448
+				null,
449
+				array('EVT_ID' => $event->ID())
450
+			);
451
+		}
452
+		return $action_links;
453
+	}
454
+
455
+
456
+	/**
457
+	 * @param $items
458
+	 * @return mixed
459
+	 */
460
+	public function additional_legend_items($items)
461
+	{
462
+		if (EE_Registry::instance()->CAP->current_user_can(
463
+			'ee_read_registrations',
464
+			'espresso_registrations_reports'
465
+		)
466
+		) {
467
+			$items['reports'] = array(
468
+				'class' => 'dashicons dashicons-chart-bar',
469
+				'desc'  => esc_html__('Event Reports', 'event_espresso'),
470
+			);
471
+		}
472
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
473
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
474
+			if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
475
+				$items['view_related_messages'] = array(
476
+					'class' => $related_for_icon['css_class'],
477
+					'desc'  => $related_for_icon['label'],
478
+				);
479
+			}
480
+		}
481
+		return $items;
482
+	}
483
+
484
+
485
+	/**
486
+	 * This is the callback method for the duplicate event route
487
+	 * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
488
+	 * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
489
+	 * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
490
+	 * After duplication the redirect is to the new event edit page.
491
+	 *
492
+	 * @return void
493
+	 * @access protected
494
+	 * @throws EE_Error If EE_Event is not available with given ID
495
+	 */
496
+	protected function _duplicate_event()
497
+	{
498
+		// first make sure the ID for the event is in the request.
499
+		//  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
500
+		if (! isset($this->_req_data['EVT_ID'])) {
501
+			EE_Error::add_error(
502
+				esc_html__(
503
+					'In order to duplicate an event an Event ID is required.  None was given.',
504
+					'event_espresso'
505
+				),
506
+				__FILE__,
507
+				__FUNCTION__,
508
+				__LINE__
509
+			);
510
+			$this->_redirect_after_action(false, '', '', array(), true);
511
+			return;
512
+		}
513
+		//k we've got EVT_ID so let's use that to get the event we'll duplicate
514
+		$orig_event = EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID']);
515
+		if (! $orig_event instanceof EE_Event) {
516
+			throw new EE_Error(
517
+				sprintf(
518
+					esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
519
+					$this->_req_data['EVT_ID']
520
+				)
521
+			);
522
+		}
523
+		//k now let's clone the $orig_event before getting relations
524
+		$new_event = clone $orig_event;
525
+		//original datetimes
526
+		$orig_datetimes = $orig_event->get_many_related('Datetime');
527
+		//other original relations
528
+		$orig_ven = $orig_event->get_many_related('Venue');
529
+		//reset the ID and modify other details to make it clear this is a dupe
530
+		$new_event->set('EVT_ID', 0);
531
+		$new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
532
+		$new_event->set('EVT_name', $new_name);
533
+		$new_event->set(
534
+			'EVT_slug',
535
+			wp_unique_post_slug(
536
+				sanitize_title($orig_event->name()),
537
+				0,
538
+				'publish',
539
+				'espresso_events',
540
+				0
541
+			)
542
+		);
543
+		$new_event->set('status', 'draft');
544
+		//duplicate discussion settings
545
+		$new_event->set('comment_status', $orig_event->get('comment_status'));
546
+		$new_event->set('ping_status', $orig_event->get('ping_status'));
547
+		//save the new event
548
+		$new_event->save();
549
+		//venues
550
+		foreach ($orig_ven as $ven) {
551
+			$new_event->_add_relation_to($ven, 'Venue');
552
+		}
553
+		$new_event->save();
554
+		//now we need to get the question group relations and handle that
555
+		//first primary question groups
556
+		$orig_primary_qgs = $orig_event->get_many_related(
557
+			'Question_Group',
558
+			array(array('Event_Question_Group.EQG_primary' => 1))
559
+		);
560
+		if (! empty($orig_primary_qgs)) {
561
+			foreach ($orig_primary_qgs as $id => $obj) {
562
+				if ($obj instanceof EE_Question_Group) {
563
+					$new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 1));
564
+				}
565
+			}
566
+		}
567
+		//next additional attendee question groups
568
+		$orig_additional_qgs = $orig_event->get_many_related(
569
+			'Question_Group',
570
+			array(array('Event_Question_Group.EQG_primary' => 0))
571
+		);
572
+		if (! empty($orig_additional_qgs)) {
573
+			foreach ($orig_additional_qgs as $id => $obj) {
574
+				if ($obj instanceof EE_Question_Group) {
575
+					$new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 0));
576
+				}
577
+			}
578
+		}
579
+
580
+		$new_event->save();
581
+
582
+		//k now that we have the new event saved we can loop through the datetimes and start adding relations.
583
+		$cloned_tickets = array();
584
+		foreach ($orig_datetimes as $orig_dtt) {
585
+			if (! $orig_dtt instanceof EE_Datetime) {
586
+				continue;
587
+			}
588
+			$new_dtt   = clone $orig_dtt;
589
+			$orig_tkts = $orig_dtt->tickets();
590
+			//save new dtt then add to event
591
+			$new_dtt->set('DTT_ID', 0);
592
+			$new_dtt->set('DTT_sold', 0);
593
+			$new_dtt->set_reserved(0);
594
+			$new_dtt->save();
595
+			$new_event->_add_relation_to($new_dtt, 'Datetime');
596
+			$new_event->save();
597
+			//now let's get the ticket relations setup.
598
+			foreach ((array)$orig_tkts as $orig_tkt) {
599
+				//it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
600
+				if (! $orig_tkt instanceof EE_Ticket) {
601
+					continue;
602
+				}
603
+				//is this ticket archived?  If it is then let's skip
604
+				if ($orig_tkt->get('TKT_deleted')) {
605
+					continue;
606
+				}
607
+				// does this original ticket already exist in the clone_tickets cache?
608
+				//  If so we'll just use the new ticket from it.
609
+				if (isset($cloned_tickets[$orig_tkt->ID()])) {
610
+					$new_tkt = $cloned_tickets[$orig_tkt->ID()];
611
+				} else {
612
+					$new_tkt = clone $orig_tkt;
613
+					//get relations on the $orig_tkt that we need to setup.
614
+					$orig_prices = $orig_tkt->prices();
615
+					$new_tkt->set('TKT_ID', 0);
616
+					$new_tkt->set('TKT_sold', 0);
617
+					$new_tkt->set('TKT_reserved', 0);
618
+					$new_tkt->save(); //make sure new ticket has ID.
619
+					//price relations on new ticket need to be setup.
620
+					foreach ($orig_prices as $orig_price) {
621
+						$new_price = clone $orig_price;
622
+						$new_price->set('PRC_ID', 0);
623
+						$new_price->save();
624
+						$new_tkt->_add_relation_to($new_price, 'Price');
625
+						$new_tkt->save();
626
+					}
627
+
628
+					do_action(
629
+						'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
630
+						$orig_tkt,
631
+						$new_tkt,
632
+						$orig_prices,
633
+						$orig_event,
634
+						$orig_dtt,
635
+						$new_dtt
636
+					);
637
+				}
638
+				// k now we can add the new ticket as a relation to the new datetime
639
+				// and make sure its added to our cached $cloned_tickets array
640
+				// for use with later datetimes that have the same ticket.
641
+				$new_dtt->_add_relation_to($new_tkt, 'Ticket');
642
+				$new_dtt->save();
643
+				$cloned_tickets[$orig_tkt->ID()] = $new_tkt;
644
+			}
645
+		}
646
+		//clone taxonomy information
647
+		$taxonomies_to_clone_with = apply_filters(
648
+			'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
649
+			array('espresso_event_categories', 'espresso_event_type', 'post_tag')
650
+		);
651
+		//get terms for original event (notice)
652
+		$orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
653
+		//loop through terms and add them to new event.
654
+		foreach ($orig_terms as $term) {
655
+			wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
656
+		}
657
+
658
+		//duplicate other core WP_Post items for this event.
659
+		//post thumbnail (feature image).
660
+		$feature_image_id = get_post_thumbnail_id($orig_event->ID());
661
+		if ($feature_image_id) {
662
+			update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
663
+		}
664
+
665
+		//duplicate page_template setting
666
+		$page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
667
+		if ($page_template) {
668
+			update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
669
+		}
670
+
671
+		do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
672
+		//now let's redirect to the edit page for this duplicated event if we have a new event id.
673
+		if ($new_event->ID()) {
674
+			$redirect_args = array(
675
+				'post'   => $new_event->ID(),
676
+				'action' => 'edit',
677
+			);
678
+			EE_Error::add_success(
679
+				esc_html__(
680
+					'Event successfully duplicated.  Please review the details below and make any necessary edits',
681
+					'event_espresso'
682
+				)
683
+			);
684
+		} else {
685
+			$redirect_args = array(
686
+				'action' => 'default',
687
+			);
688
+			EE_Error::add_error(
689
+				esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
690
+				__FILE__,
691
+				__FUNCTION__,
692
+				__LINE__
693
+			);
694
+		}
695
+		$this->_redirect_after_action(false, '', '', $redirect_args, true);
696
+	}
697
+
698
+
699
+	/**
700
+	 * Generates output for the import page.
701
+	 * @throws DomainException
702
+	 */
703
+	protected function _import_page()
704
+	{
705
+		$title                                      = esc_html__('Import', 'event_espresso');
706
+		$intro                                      = esc_html__(
707
+			'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
708
+			'event_espresso'
709
+		);
710
+		$form_url                                   = EVENTS_ADMIN_URL;
711
+		$action                                     = 'import_events';
712
+		$type                                       = 'csv';
713
+		$this->_template_args['form']               = EE_Import::instance()->upload_form(
714
+			$title, $intro, $form_url, $action, $type
715
+		);
716
+		$this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
717
+			array('action' => 'sample_export_file'),
718
+			$this->_admin_base_url
719
+		);
720
+		$content                                    = EEH_Template::display_template(
721
+			EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
722
+			$this->_template_args,
723
+			true
724
+		);
725
+		$this->_template_args['admin_page_content'] = $content;
726
+		$this->display_admin_page_with_sidebar();
727
+	}
728
+
729
+
730
+	/**
731
+	 * _import_events
732
+	 * This handles displaying the screen and running imports for importing events.
733
+	 *
734
+	 * @return void
735
+	 */
736
+	protected function _import_events()
737
+	{
738
+		require_once(EE_CLASSES . 'EE_Import.class.php');
739
+		$success = EE_Import::instance()->import();
740
+		$this->_redirect_after_action($success, 'Import File', 'ran', array('action' => 'import_page'), true);
741
+	}
742
+
743
+
744
+	/**
745
+	 * _events_export
746
+	 * Will export all (or just the given event) to a Excel compatible file.
747
+	 *
748
+	 * @access protected
749
+	 * @return void
750
+	 */
751
+	protected function _events_export()
752
+	{
753
+		if (isset($this->_req_data['EVT_ID'])) {
754
+			$event_ids = $this->_req_data['EVT_ID'];
755
+		} elseif (isset($this->_req_data['EVT_IDs'])) {
756
+			$event_ids = $this->_req_data['EVT_IDs'];
757
+		} else {
758
+			$event_ids = null;
759
+		}
760
+		//todo: I don't like doing this but it'll do until we modify EE_Export Class.
761
+		$new_request_args = array(
762
+			'export' => 'report',
763
+			'action' => 'all_event_data',
764
+			'EVT_ID' => $event_ids,
765
+		);
766
+		$this->_req_data  = array_merge($this->_req_data, $new_request_args);
767
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
768
+			require_once(EE_CLASSES . 'EE_Export.class.php');
769
+			$EE_Export = EE_Export::instance($this->_req_data);
770
+			$EE_Export->export();
771
+		}
772
+	}
773
+
774
+
775
+	/**
776
+	 * handle category exports()
777
+	 *
778
+	 * @return void
779
+	 */
780
+	protected function _categories_export()
781
+	{
782
+		//todo: I don't like doing this but it'll do until we modify EE_Export Class.
783
+		$new_request_args = array(
784
+			'export'       => 'report',
785
+			'action'       => 'categories',
786
+			'category_ids' => $this->_req_data['EVT_CAT_ID'],
787
+		);
788
+		$this->_req_data  = array_merge($this->_req_data, $new_request_args);
789
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
790
+			require_once(EE_CLASSES . 'EE_Export.class.php');
791
+			$EE_Export = EE_Export::instance($this->_req_data);
792
+			$EE_Export->export();
793
+		}
794
+	}
795
+
796
+
797
+	/**
798
+	 * Creates a sample CSV file for importing
799
+	 */
800
+	protected function _sample_export_file()
801
+	{
802
+		//		require_once(EE_CLASSES . 'EE_Export.class.php');
803
+		EE_Export::instance()->export_sample();
804
+	}
805
+
806
+
807
+	/*************        Template Settings        *************/
808
+	/**
809
+	 * Generates template settings page output
810
+	 * @throws DomainException
811
+	 * @throws EE_Error
812
+	 */
813
+	protected function _template_settings()
814
+	{
815
+		$this->_template_args['values'] = $this->_yes_no_values;
816
+		/**
817
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
818
+		 * from General_Settings_Admin_Page to here.
819
+		 */
820
+		$this->_template_args = apply_filters(
821
+			'FHEE__General_Settings_Admin_Page__template_settings__template_args',
822
+			$this->_template_args
823
+		);
824
+		$this->_set_add_edit_form_tags('update_template_settings');
825
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
826
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
827
+			EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
828
+			$this->_template_args,
829
+			true
830
+		);
831
+		$this->display_admin_page_with_sidebar();
832
+	}
833
+
834
+
835
+	/**
836
+	 * Handler for updating template settings.
837
+	 */
838
+	protected function _update_template_settings()
839
+	{
840
+		/**
841
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
842
+		 * from General_Settings_Admin_Page to here.
843
+		 */
844
+		EE_Registry::instance()->CFG->template_settings = apply_filters(
845
+			'FHEE__General_Settings_Admin_Page__update_template_settings__data',
846
+			EE_Registry::instance()->CFG->template_settings,
847
+			$this->_req_data
848
+		);
849
+		//update custom post type slugs and detect if we need to flush rewrite rules
850
+		$old_slug                                          = EE_Registry::instance()->CFG->core->event_cpt_slug;
851
+		EE_Registry::instance()->CFG->core->event_cpt_slug = empty($this->_req_data['event_cpt_slug'])
852
+			? EE_Registry::instance()->CFG->core->event_cpt_slug
853
+			: sanitize_title_with_dashes($this->_req_data['event_cpt_slug']);
854
+		$what                                              = 'Template Settings';
855
+		$success                                           = $this->_update_espresso_configuration(
856
+			$what,
857
+			EE_Registry::instance()->CFG->template_settings,
858
+			__FILE__,
859
+			__FUNCTION__,
860
+			__LINE__
861
+		);
862
+		if (EE_Registry::instance()->CFG->core->event_cpt_slug != $old_slug) {
863
+			update_option('ee_flush_rewrite_rules', true);
864
+		}
865
+		$this->_redirect_after_action($success, $what, 'updated', array('action' => 'template_settings'));
866
+	}
867
+
868
+
869
+	/**
870
+	 * _premium_event_editor_meta_boxes
871
+	 * add all metaboxes related to the event_editor
872
+	 *
873
+	 * @access protected
874
+	 * @return void
875
+	 * @throws EE_Error
876
+	 */
877
+	protected function _premium_event_editor_meta_boxes()
878
+	{
879
+		$this->verify_cpt_object();
880
+		add_meta_box(
881
+			'espresso_event_editor_event_options',
882
+			esc_html__('Event Registration Options', 'event_espresso'),
883
+			array($this, 'registration_options_meta_box'),
884
+			$this->page_slug,
885
+			'side',
886
+			'core'
887
+		);
888
+	}
889
+
890
+
891
+	/**
892
+	 * override caf metabox
893
+	 *
894
+	 * @return void
895
+	 * @throws DomainException
896
+	 */
897
+	public function registration_options_meta_box()
898
+	{
899
+		$yes_no_values                                    = array(
900
+			array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
901
+			array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
902
+		);
903
+		$default_reg_status_values                        = EEM_Registration::reg_status_array(
904
+			array(
905
+				EEM_Registration::status_id_cancelled,
906
+				EEM_Registration::status_id_declined,
907
+				EEM_Registration::status_id_incomplete,
908
+				EEM_Registration::status_id_wait_list,
909
+			),
910
+			true
911
+		);
912
+		$template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
913
+		$template_args['_event']                          = $this->_cpt_model_obj;
914
+		$template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
915
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
916
+			'default_reg_status',
917
+			$default_reg_status_values,
918
+			$this->_cpt_model_obj->default_registration_status()
919
+		);
920
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
921
+			'display_desc',
922
+			$yes_no_values,
923
+			$this->_cpt_model_obj->display_description()
924
+		);
925
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
926
+			'display_ticket_selector',
927
+			$yes_no_values,
928
+			$this->_cpt_model_obj->display_ticket_selector(),
929
+			'',
930
+			'',
931
+			false
932
+		);
933
+		$template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
934
+			'EVT_default_registration_status',
935
+			$default_reg_status_values,
936
+			$this->_cpt_model_obj->default_registration_status()
937
+		);
938
+		$template_args['additional_registration_options'] = apply_filters(
939
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
940
+			'',
941
+			$template_args,
942
+			$yes_no_values,
943
+			$default_reg_status_values
944
+		);
945
+		EEH_Template::display_template(
946
+			EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
947
+			$template_args
948
+		);
949
+	}
950
+
951
+
952
+
953
+	/**
954
+	 * wp_list_table_mods for caf
955
+	 * ============================
956
+	 */
957
+	/**
958
+	 * hook into list table filters and provide filters for caffeinated list table
959
+	 *
960
+	 * @param  array $old_filters    any existing filters present
961
+	 * @param  array $list_table_obj the list table object
962
+	 * @return array                  new filters
963
+	 */
964
+	public function list_table_filters($old_filters, $list_table_obj)
965
+	{
966
+		$filters = array();
967
+		//first month/year filters
968
+		$filters[] = $this->espresso_event_months_dropdown();
969
+		$status    = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
970
+		//active status dropdown
971
+		if ($status !== 'draft') {
972
+			$filters[] = $this->active_status_dropdown(
973
+				isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : ''
974
+			);
975
+		}
976
+		//category filter
977
+		$filters[] = $this->category_dropdown();
978
+		return array_merge($old_filters, $filters);
979
+	}
980
+
981
+
982
+	/**
983
+	 * espresso_event_months_dropdown
984
+	 *
985
+	 * @access public
986
+	 * @return string                dropdown listing month/year selections for events.
987
+	 */
988
+	public function espresso_event_months_dropdown()
989
+	{
990
+		// what we need to do is get all PRIMARY datetimes for all events to filter on.
991
+		// Note we need to include any other filters that are set!
992
+		$status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
993
+		//categories?
994
+		$category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
995
+			? $this->_req_data['EVT_CAT']
996
+			: null;
997
+		//active status?
998
+		$active_status = isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : null;
999
+		$cur_date      = isset($this->_req_data['month_range']) ? $this->_req_data['month_range'] : '';
1000
+		return EEH_Form_Fields::generate_event_months_dropdown($cur_date, $status, $category, $active_status);
1001
+	}
1002
+
1003
+
1004
+	/**
1005
+	 * returns a list of "active" statuses on the event
1006
+	 *
1007
+	 * @param  string $current_value whatever the current active status is
1008
+	 * @return string
1009
+	 */
1010
+	public function active_status_dropdown($current_value = '')
1011
+	{
1012
+		$select_name = 'active_status';
1013
+		$values      = array(
1014
+			'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1015
+			'active'   => esc_html__('Active', 'event_espresso'),
1016
+			'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1017
+			'expired'  => esc_html__('Expired', 'event_espresso'),
1018
+			'inactive' => esc_html__('Inactive', 'event_espresso'),
1019
+		);
1020
+		$id          = 'id="espresso-active-status-dropdown-filter"';
1021
+		$class       = 'wide';
1022
+		return EEH_Form_Fields::select_input($select_name, $values, $current_value, $id, $class);
1023
+	}
1024
+
1025
+
1026
+	/**
1027
+	 * output a dropdown of the categories for the category filter on the event admin list table
1028
+	 *
1029
+	 * @access  public
1030
+	 * @return string html
1031
+	 */
1032
+	public function category_dropdown()
1033
+	{
1034
+		$cur_cat = isset($this->_req_data['EVT_CAT']) ? $this->_req_data['EVT_CAT'] : -1;
1035
+		return EEH_Form_Fields::generate_event_category_dropdown($cur_cat);
1036
+	}
1037
+
1038
+
1039
+	/**
1040
+	 * get total number of events today
1041
+	 *
1042
+	 * @access public
1043
+	 * @return int
1044
+	 * @throws EE_Error
1045
+	 */
1046
+	public function total_events_today()
1047
+	{
1048
+		$start = EEM_Datetime::instance()->convert_datetime_for_query(
1049
+			'DTT_EVT_start',
1050
+			date('Y-m-d') . ' 00:00:00',
1051
+			'Y-m-d H:i:s',
1052
+			'UTC'
1053
+		);
1054
+		$end   = EEM_Datetime::instance()->convert_datetime_for_query(
1055
+			'DTT_EVT_start',
1056
+			date('Y-m-d') . ' 23:59:59',
1057
+			'Y-m-d H:i:s',
1058
+			'UTC'
1059
+		);
1060
+		$where = array(
1061
+			'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1062
+		);
1063
+		$count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1064
+		return $count;
1065
+	}
1066
+
1067
+
1068
+	/**
1069
+	 * get total number of events this month
1070
+	 *
1071
+	 * @access public
1072
+	 * @return int
1073
+	 * @throws EE_Error
1074
+	 */
1075
+	public function total_events_this_month()
1076
+	{
1077
+		//Dates
1078
+		$this_year_r     = date('Y');
1079
+		$this_month_r    = date('m');
1080
+		$days_this_month = date('t');
1081
+		$start           = EEM_Datetime::instance()->convert_datetime_for_query(
1082
+			'DTT_EVT_start',
1083
+			$this_year_r . '-' . $this_month_r . '-01 00:00:00',
1084
+			'Y-m-d H:i:s',
1085
+			'UTC'
1086
+		);
1087
+		$end             = EEM_Datetime::instance()->convert_datetime_for_query(
1088
+			'DTT_EVT_start',
1089
+			$this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1090
+			'Y-m-d H:i:s',
1091
+			'UTC'
1092
+		);
1093
+		$where           = array(
1094
+			'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1095
+		);
1096
+		$count           = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1097
+		return $count;
1098
+	}
1099
+
1100
+
1101
+	/** DEFAULT TICKETS STUFF **/
1102
+
1103
+	/**
1104
+	 * Output default tickets list table view.
1105
+	 */
1106
+	public function _tickets_overview_list_table()
1107
+	{
1108
+		$this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1109
+		$this->display_admin_list_table_page_with_no_sidebar();
1110
+	}
1111
+
1112
+
1113
+	/**
1114
+	 * @param int  $per_page
1115
+	 * @param bool $count
1116
+	 * @param bool $trashed
1117
+	 * @return \EE_Soft_Delete_Base_Class[]|int
1118
+	 */
1119
+	public function get_default_tickets($per_page = 10, $count = false, $trashed = false)
1120
+	{
1121
+		$orderby = empty($this->_req_data['orderby']) ? 'TKT_name' : $this->_req_data['orderby'];
1122
+		$order   = empty($this->_req_data['order']) ? 'ASC' : $this->_req_data['order'];
1123
+		switch ($orderby) {
1124
+			case 'TKT_name':
1125
+				$orderby = array('TKT_name' => $order);
1126
+				break;
1127
+			case 'TKT_price':
1128
+				$orderby = array('TKT_price' => $order);
1129
+				break;
1130
+			case 'TKT_uses':
1131
+				$orderby = array('TKT_uses' => $order);
1132
+				break;
1133
+			case 'TKT_min':
1134
+				$orderby = array('TKT_min' => $order);
1135
+				break;
1136
+			case 'TKT_max':
1137
+				$orderby = array('TKT_max' => $order);
1138
+				break;
1139
+			case 'TKT_qty':
1140
+				$orderby = array('TKT_qty' => $order);
1141
+				break;
1142
+		}
1143
+		$current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
1144
+			? $this->_req_data['paged']
1145
+			: 1;
1146
+		$per_page     = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
1147
+			? $this->_req_data['perpage']
1148
+			: $per_page;
1149
+		$_where       = array(
1150
+			'TKT_is_default' => 1,
1151
+			'TKT_deleted'    => $trashed,
1152
+		);
1153
+		$offset       = ($current_page - 1) * $per_page;
1154
+		$limit        = array($offset, $per_page);
1155
+		if (isset($this->_req_data['s'])) {
1156
+			$sstr         = '%' . $this->_req_data['s'] . '%';
1157
+			$_where['OR'] = array(
1158
+				'TKT_name'        => array('LIKE', $sstr),
1159
+				'TKT_description' => array('LIKE', $sstr),
1160
+			);
1161
+		}
1162
+		$query_params = array(
1163
+			$_where,
1164
+			'order_by' => $orderby,
1165
+			'limit'    => $limit,
1166
+			'group_by' => 'TKT_ID',
1167
+		);
1168
+		if ($count) {
1169
+			return EEM_Ticket::instance()->count_deleted_and_undeleted(array($_where));
1170
+		} else {
1171
+			return EEM_Ticket::instance()->get_all_deleted_and_undeleted($query_params);
1172
+		}
1173
+	}
1174
+
1175
+
1176
+	/**
1177
+	 * @param bool $trash
1178
+	 * @throws EE_Error
1179
+	 */
1180
+	protected function _trash_or_restore_ticket($trash = false)
1181
+	{
1182
+		$success = 1;
1183
+		$TKT     = EEM_Ticket::instance();
1184
+		//checkboxes?
1185
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1186
+			//if array has more than one element then success message should be plural
1187
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1188
+			//cycle thru the boxes
1189
+			while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1190
+				if ($trash) {
1191
+					if (! $TKT->delete_by_ID($TKT_ID)) {
1192
+						$success = 0;
1193
+					}
1194
+				} else {
1195
+					if (! $TKT->restore_by_ID($TKT_ID)) {
1196
+						$success = 0;
1197
+					}
1198
+				}
1199
+			}
1200
+		} else {
1201
+			//grab single id and trash
1202
+			$TKT_ID = absint($this->_req_data['TKT_ID']);
1203
+			if ($trash) {
1204
+				if (! $TKT->delete_by_ID($TKT_ID)) {
1205
+					$success = 0;
1206
+				}
1207
+			} else {
1208
+				if (! $TKT->restore_by_ID($TKT_ID)) {
1209
+					$success = 0;
1210
+				}
1211
+			}
1212
+		}
1213
+		$action_desc = $trash ? 'moved to the trash' : 'restored';
1214
+		$query_args  = array(
1215
+			'action' => 'ticket_list_table',
1216
+			'status' => $trash ? '' : 'trashed',
1217
+		);
1218
+		$this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1219
+	}
1220
+
1221
+
1222
+	/**
1223
+	 * Handles trashing default ticket.
1224
+	 */
1225
+	protected function _delete_ticket()
1226
+	{
1227
+		$success = 1;
1228
+		//checkboxes?
1229
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1230
+			//if array has more than one element then success message should be plural
1231
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1232
+			//cycle thru the boxes
1233
+			while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1234
+				//delete
1235
+				if (! $this->_delete_the_ticket($TKT_ID)) {
1236
+					$success = 0;
1237
+				}
1238
+			}
1239
+		} else {
1240
+			//grab single id and trash
1241
+			$TKT_ID = absint($this->_req_data['TKT_ID']);
1242
+			if (! $this->_delete_the_ticket($TKT_ID)) {
1243
+				$success = 0;
1244
+			}
1245
+		}
1246
+		$action_desc = 'deleted';
1247
+		$query_args  = array(
1248
+			'action' => 'ticket_list_table',
1249
+			'status' => 'trashed',
1250
+		);
1251
+		//fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1252
+		if (EEM_Ticket::instance()->count_deleted_and_undeleted(
1253
+			array(array('TKT_is_default' => 1)),
1254
+			'TKT_ID',
1255
+			true
1256
+		)
1257
+		) {
1258
+			$query_args = array();
1259
+		}
1260
+		$this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1261
+	}
1262
+
1263
+
1264
+	/**
1265
+	 * @param int $TKT_ID
1266
+	 * @return bool|int
1267
+	 * @throws EE_Error
1268
+	 */
1269
+	protected function _delete_the_ticket($TKT_ID)
1270
+	{
1271
+		$tkt = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1272
+		$tkt->_remove_relations('Datetime');
1273
+		//delete all related prices first
1274
+		$tkt->delete_related_permanently('Price');
1275
+		return $tkt->delete_permanently();
1276
+	}
1277 1277
 }
Please login to merge, or discard this patch.