Completed
Branch BUG-10489-non-trashed-regs-onl... (a7561f)
by
unknown
46:07 queued 34:09
created
core/db_models/EEM_Question_Option.model.php 1 patch
Spacing   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -21,8 +21,8 @@  discard block
 block discarded – undo
21 21
  *
22 22
  * ------------------------------------------------------------------------
23 23
  */
24
-require_once ( EE_MODELS . 'EEM_Soft_Delete_Base.model.php' );
25
-require_once( EE_CLASSES . 'EE_Question_Option.class.php');
24
+require_once (EE_MODELS.'EEM_Soft_Delete_Base.model.php');
25
+require_once(EE_CLASSES.'EE_Question_Option.class.php');
26 26
 
27 27
 
28 28
 class EEM_Question_Option extends EEM_Soft_Delete_Base {
@@ -30,22 +30,22 @@  discard block
 block discarded – undo
30 30
   	// private instance of the Attendee object
31 31
 	protected static $_instance = NULL;
32 32
 
33
-	protected function __construct( $timezone = NULL ) {
34
-		$this->singular_item = __('Question Option','event_espresso');
35
-		$this->plural_item = __('Question Options','event_espresso');
33
+	protected function __construct($timezone = NULL) {
34
+		$this->singular_item = __('Question Option', 'event_espresso');
35
+		$this->plural_item = __('Question Options', 'event_espresso');
36 36
 
37 37
 		$this->_tables = array(
38
-			'Question_Option'=>new EE_Primary_Table('esp_question_option','QSO_ID')
38
+			'Question_Option'=>new EE_Primary_Table('esp_question_option', 'QSO_ID')
39 39
 		);
40 40
 		$this->_fields = array(
41 41
 			'Question_Option'=>array(
42
-					'QSO_ID'=>new EE_Primary_Key_Int_Field('QSO_ID', __('Question Option ID','event_espresso')),
43
-					'QST_ID'=>new EE_Foreign_Key_Int_Field('QST_ID', __('Question ID','event_espresso'), false, 0, 'Question'),
44
-					'QSO_value'=>new EE_Plain_Text_Field('QSO_value',  __("Question Option Value", "event_espresso"),false,''),
45
-					'QSO_desc'=>new EE_Post_Content_Field('QSO_desc', __('Question Option Description','event_espresso'), false, ''),
46
-					'QSO_order' => new EE_Integer_Field('QSO_order', __('Question Option Order', 'event_espresso' ), false, 0 ),
47
-					'QSO_system'=>new EE_Plain_Text_Field('QSO_system', __('Internal string ID for question option','event_espresso'), TRUE, NULL ),
48
-					'QSO_deleted'=>new EE_Trashed_Flag_Field('QSO_deleted', __('Flag indicating Option was trashed','event_espresso'), false, false)
42
+					'QSO_ID'=>new EE_Primary_Key_Int_Field('QSO_ID', __('Question Option ID', 'event_espresso')),
43
+					'QST_ID'=>new EE_Foreign_Key_Int_Field('QST_ID', __('Question ID', 'event_espresso'), false, 0, 'Question'),
44
+					'QSO_value'=>new EE_Plain_Text_Field('QSO_value', __("Question Option Value", "event_espresso"), false, ''),
45
+					'QSO_desc'=>new EE_Post_Content_Field('QSO_desc', __('Question Option Description', 'event_espresso'), false, ''),
46
+					'QSO_order' => new EE_Integer_Field('QSO_order', __('Question Option Order', 'event_espresso'), false, 0),
47
+					'QSO_system'=>new EE_Plain_Text_Field('QSO_system', __('Internal string ID for question option', 'event_espresso'), TRUE, NULL),
48
+					'QSO_deleted'=>new EE_Trashed_Flag_Field('QSO_deleted', __('Flag indicating Option was trashed', 'event_espresso'), false, false)
49 49
 				)
50 50
 		);
51 51
 		$this->_model_relations = array(
@@ -54,12 +54,12 @@  discard block
 block discarded – undo
54 54
 
55 55
 		$this->_model_chain_to_wp_user = 'Question';
56 56
 		//this model is generally available for reading
57
-		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
58
-		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Reg_Form('QSO_system');
59
-		$this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Reg_Form('QSO_system');
60
-		$this->_cap_restriction_generators[ EEM_Base::caps_delete ] = new EE_Restriction_Generator_Reg_Form('QSO_system');
57
+		$this->_cap_restriction_generators[EEM_Base::caps_read] = new EE_Restriction_Generator_Public();
58
+		$this->_cap_restriction_generators[EEM_Base::caps_read_admin] = new EE_Restriction_Generator_Reg_Form('QSO_system');
59
+		$this->_cap_restriction_generators[EEM_Base::caps_edit] = new EE_Restriction_Generator_Reg_Form('QSO_system');
60
+		$this->_cap_restriction_generators[EEM_Base::caps_delete] = new EE_Restriction_Generator_Reg_Form('QSO_system');
61 61
 		$this->_caps_slug = 'questions';
62
-		parent::__construct( $timezone );
62
+		parent::__construct($timezone);
63 63
 	}
64 64
 
65 65
 
Please login to merge, or discard this patch.
core/libraries/rest_api/ModelDataTranslator.php 3 patches
Unused Use Statements   -2 removed lines patch added patch discarded remove patch
@@ -1,11 +1,9 @@
 block discarded – undo
1 1
 <?php
2 2
 namespace EventEspresso\core\libraries\rest_api;
3 3
 
4
-use EE_Capabilities;
5 4
 use EE_Datetime_Field;
6 5
 use EE_Error;
7 6
 use EE_Infinite_Integer_Field;
8
-use EE_Maybe_Serialized_Simple_HTML_Field;
9 7
 use EE_Model_Field_Base;
10 8
 use EE_Serialized_Text_Field;
11 9
 use EEM_Base;
Please login to merge, or discard this patch.
Indentation   +789 added lines, -789 removed lines patch added patch discarded remove patch
@@ -11,7 +11,7 @@  discard block
 block discarded – undo
11 11
 use EEM_Base;
12 12
 
13 13
 if (! defined('EVENT_ESPRESSO_VERSION')) {
14
-    exit('No direct script access allowed');
14
+	exit('No direct script access allowed');
15 15
 }
16 16
 
17 17
 
@@ -36,792 +36,792 @@  discard block
 block discarded – undo
36 36
 class ModelDataTranslator
37 37
 {
38 38
 
39
-    /**
40
-     * We used to use -1 for infinity in the rest api, but that's ambiguous for
41
-     * fields that COULD contain -1; so we use null
42
-     */
43
-    const EE_INF_IN_REST = null;
44
-
45
-
46
-
47
-    /**
48
-     * Prepares a possible array of input values from JSON for use by the models
49
-     *
50
-     * @param EE_Model_Field_Base $field_obj
51
-     * @param mixed                $original_value_maybe_array
52
-     * @param string               $requested_version
53
-     * @param string               $timezone_string treat values as being in this timezone
54
-     * @return mixed
55
-     * @throws RestException
56
-     */
57
-    public static function prepareFieldValuesFromJson(
58
-        $field_obj,
59
-        $original_value_maybe_array,
60
-        $requested_version,
61
-        $timezone_string = 'UTC'
62
-    ) {
63
-        if (is_array($original_value_maybe_array)
64
-            && ! $field_obj instanceof EE_Serialized_Text_Field
65
-        ) {
66
-            $new_value_maybe_array = array();
67
-            foreach ($original_value_maybe_array as $array_key => $array_item) {
68
-                $new_value_maybe_array[$array_key] = ModelDataTranslator::prepareFieldValueFromJson(
69
-                    $field_obj,
70
-                    $array_item,
71
-                    $requested_version,
72
-                    $timezone_string
73
-                );
74
-            }
75
-        } else {
76
-            $new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
77
-                $field_obj,
78
-                $original_value_maybe_array,
79
-                $requested_version,
80
-                $timezone_string
81
-            );
82
-        }
83
-        return $new_value_maybe_array;
84
-    }
85
-
86
-
87
-
88
-    /**
89
-     * Prepares an array of field values FOR use in JSON/REST API
90
-     *
91
-     * @param EE_Model_Field_Base $field_obj
92
-     * @param mixed                $original_value_maybe_array
93
-     * @param string               $request_version (eg 4.8.36)
94
-     * @return array
95
-     */
96
-    public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
97
-    {
98
-        if (is_array($original_value_maybe_array)) {
99
-            $new_value = array();
100
-            foreach ($original_value_maybe_array as $key => $value) {
101
-                $new_value[$key] = ModelDataTranslator::prepareFieldValuesForJson($field_obj, $value, $request_version);
102
-            }
103
-        } else {
104
-            $new_value = ModelDataTranslator::prepareFieldValueForJson(
105
-                $field_obj,
106
-                $original_value_maybe_array,
107
-                $request_version
108
-            );
109
-        }
110
-        return $new_value;
111
-    }
112
-
113
-
114
-
115
-    /**
116
-     * Prepares incoming data from the json or $_REQUEST parameters for the models'
117
-     * "$query_params".
118
-     *
119
-     * @param EE_Model_Field_Base $field_obj
120
-     * @param mixed                $original_value
121
-     * @param string               $requested_version
122
-     * @param string               $timezone_string treat values as being in this timezone
123
-     * @return mixed
124
-     * @throws RestException
125
-     */
126
-    public static function prepareFieldValueFromJson(
127
-        $field_obj,
128
-        $original_value,
129
-        $requested_version,
130
-        $timezone_string = 'UTC' // UTC
131
-    ) {
132
-        //check if they accidentally submitted an error value. If so throw an exception
133
-        if (is_array($original_value)
134
-            && isset($original_value['error_code'], $original_value['error_message'])) {
135
-            throw new RestException(
136
-                'rest_submitted_error_value',
137
-                sprintf(
138
-                    esc_html__(
139
-                        'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
140
-                        'event_espresso'
141
-                    ),
142
-                    $field_obj->get_name()
143
-                ),
144
-                array(
145
-                    'status' => 400,
146
-                )
147
-            );
148
-        }
149
-        //double-check for serialized PHP. We never accept serialized PHP. No way Jose.
150
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
151
-        $timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
152
-        $new_value = null;
153
-        //walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
154
-        // way Jose.
155
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
156
-        if ($field_obj instanceof EE_Infinite_Integer_Field
157
-            && in_array($original_value, array(null, ''), true)
158
-        ) {
159
-            $new_value = EE_INF;
160
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
161
-            list($offset_sign, $offset_secs) = ModelDataTranslator::parseTimezoneOffset(
162
-                $field_obj->get_timezone_offset(
163
-                    new \DateTimeZone($timezone_string),
164
-                    $original_value
165
-                )
166
-            );
167
-            $offset_string =
168
-                str_pad(
169
-                    floor($offset_secs / HOUR_IN_SECONDS),
170
-                    2,
171
-                    '0',
172
-                    STR_PAD_LEFT
173
-                )
174
-                . ':'
175
-                . str_pad(
176
-                    ($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
177
-                    2,
178
-                    '0',
179
-                    STR_PAD_LEFT
180
-                );
181
-            $new_value = rest_parse_date($original_value . $offset_sign . $offset_string);
182
-        } else {
183
-            $new_value = $original_value;
184
-        }
185
-        return $new_value;
186
-    }
187
-
188
-
189
-
190
-    /**
191
-     * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
192
-     * think that can happen). If $data is an array, recurses into its keys and values
193
-     * @param mixed $data
194
-     * @throws RestException
195
-     * @return void
196
-     */
197
-    public static function throwExceptionIfContainsSerializedData($data)
198
-    {
199
-        if (is_array($data)) {
200
-            foreach ($data as $key => $value) {
201
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
202
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
203
-            }
204
-        } else {
205
-            if (is_serialized($data) || is_object($data)) {
206
-                throw new RestException(
207
-                    'serialized_data_submission_prohibited',
208
-                    esc_html__(
209
-                        // @codingStandardsIgnoreStart
210
-                        'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
211
-                        // @codingStandardsIgnoreEnd
212
-                        'event_espresso'
213
-                    )
214
-                );
215
-            }
216
-        }
217
-    }
218
-
219
-
220
-
221
-    /**
222
-     * determines what's going on with them timezone strings
223
-     *
224
-     * @param int $timezone_offset
225
-     * @return array
226
-     */
227
-    private static function parseTimezoneOffset($timezone_offset)
228
-    {
229
-        $first_char = substr((string)$timezone_offset, 0, 1);
230
-        if ($first_char === '+' || $first_char === '-') {
231
-            $offset_sign = $first_char;
232
-            $offset_secs = substr((string)$timezone_offset, 1);
233
-        } else {
234
-            $offset_sign = '+';
235
-            $offset_secs = $timezone_offset;
236
-        }
237
-        return array($offset_sign, $offset_secs);
238
-    }
239
-
240
-
241
-
242
-    /**
243
-     * Prepares a field's value for display in the API
244
-     *
245
-     * @param EE_Model_Field_Base $field_obj
246
-     * @param mixed                $original_value
247
-     * @param string               $requested_version
248
-     * @return mixed
249
-     */
250
-    public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
251
-    {
252
-        if ($original_value === EE_INF) {
253
-            $new_value = ModelDataTranslator::EE_INF_IN_REST;
254
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
255
-            if (is_string($original_value)) {
256
-                //did they submit a string of a unix timestamp?
257
-                if (is_numeric($original_value)) {
258
-                    $datetime_obj = new \DateTime();
259
-                    $datetime_obj->setTimestamp((int)$original_value);
260
-                } else {
261
-                    //first, check if its a MySQL timestamp in GMT
262
-                    $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
263
-                }
264
-                if (! $datetime_obj instanceof \DateTime) {
265
-                    //so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
266
-                    $datetime_obj = $field_obj->prepare_for_set($original_value);
267
-                }
268
-                $original_value = $datetime_obj;
269
-            }
270
-            if ($original_value instanceof \DateTime) {
271
-                $new_value = $original_value->format('Y-m-d H:i:s');
272
-            } elseif (is_int($original_value)) {
273
-                $new_value = date('Y-m-d H:i:s', $original_value);
274
-            } elseif($original_value === null || $original_value === '') {
275
-                $new_value = null;
276
-            } else {
277
-                //so it's not a datetime object, unix timestamp (as string or int),
278
-                //MySQL timestamp, or even a string in the field object's format. So no idea what it is
279
-                throw new \EE_Error(
280
-                    sprintf(
281
-                        esc_html__(
282
-                        // @codingStandardsIgnoreStart
283
-                            '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".',
284
-                            // @codingStandardsIgnoreEnd
285
-                            'event_espressso'
286
-                        ),
287
-                        $original_value,
288
-                        $field_obj->get_name(),
289
-                        $field_obj->get_model_name(),
290
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
291
-                    )
292
-                );
293
-            }
294
-            $new_value = mysql_to_rfc3339($new_value);
295
-        } else {
296
-            $new_value = $original_value;
297
-        }
298
-        //are we about to send an object? just don't. We have no good way to represent it in JSON.
299
-        // can't just check using is_object() because that missed PHP incomplete objects
300
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
301
-            $new_value = array(
302
-                'error_code' => 'php_object_not_return',
303
-                'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso')
304
-            );
305
-        }
306
-        return apply_filters(
307
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
308
-            $new_value,
309
-            $field_obj,
310
-            $original_value,
311
-            $requested_version
312
-        );
313
-    }
314
-
315
-
316
-
317
-    /**
318
-     * Prepares condition-query-parameters (like what's in where and having) from
319
-     * the format expected in the API to use in the models
320
-     *
321
-     * @param array     $inputted_query_params_of_this_type
322
-     * @param EEM_Base $model
323
-     * @param string    $requested_version
324
-     * @param boolean $writing whether this data will be written to the DB, or if we're just building a query.
325
-     *                         If we're writing to the DB, we don't expect any operators, or any logic query parameters,
326
-     *                         and we also won't accept serialized data unless the current user has unfiltered_html.
327
-     * @return array
328
-     * @throws \DomainException
329
-     * @throws RestException
330
-     * @throws EE_Error
331
-     */
332
-    public static function prepareConditionsQueryParamsForModels(
333
-        $inputted_query_params_of_this_type,
334
-        EEM_Base $model,
335
-        $requested_version,
336
-        $writing = false
337
-    ) {
338
-        $query_param_for_models = array();
339
-        $valid_operators = $model->valid_operators();
340
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
341
-            $is_gmt_datetime_field = false;
342
-            $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
343
-                $query_param_key
344
-            );
345
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
346
-                $query_param_sans_stars,
347
-                $model
348
-            );
349
-            //double-check is it a *_gmt field?
350
-            if (! $field instanceof EE_Model_Field_Base
351
-                && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
352
-            ) {
353
-                //yep, take off '_gmt', and find the field
354
-                $query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars);
355
-                $field = ModelDataTranslator::deduceFieldFromQueryParam(
356
-                    $query_param_key,
357
-                    $model
358
-                );
359
-                $timezone = 'UTC';
360
-                $is_gmt_datetime_field = true;
361
-            } elseif ($field instanceof EE_Datetime_Field) {
362
-                //so it's not a GMT field. Set the timezone on the model to the default
363
-                $timezone = \EEH_DTT_Helper::get_valid_timezone_string();
364
-            } else {
365
-                //just keep using what's already set for the timezone
366
-                $timezone = $model->get_timezone();
367
-            }
368
-            if ($field instanceof EE_Model_Field_Base) {
369
-                if (! $writing && is_array($query_param_value)) {
370
-                    if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
371
-                        if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
372
-                            throw new RestException(
373
-                                'numerically_indexed_array_of_values_only',
374
-                                sprintf(
375
-                                    esc_html__(
376
-                                        'The array provided for the parameter "%1$s" should be numerically indexed.',
377
-                                        'event_espresso'
378
-                                    ),
379
-                                    $query_param_key
380
-                                ),
381
-                                array(
382
-                                    'status' => 400,
383
-                                )
384
-                            );
385
-                        }
386
-                    }
387
-                    //did they specify an operator?
388
-                    if (isset($query_param_value[0])
389
-                        && isset($valid_operators[$query_param_value[0]])
390
-                    ) {
391
-                        $op = $query_param_value[0];
392
-                        $translated_value = array($op);
393
-                        if (array_key_exists($op, $model->valid_in_style_operators())
394
-                            && isset($query_param_value[1])
395
-                            && ! isset($query_param_value[2])
396
-                        ) {
397
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
398
-                                $field,
399
-                                $query_param_value[1],
400
-                                $requested_version,
401
-                                $timezone
402
-                            );
403
-                        } elseif (array_key_exists($op, $model->valid_between_style_operators())
404
-                            && isset($query_param_value[1], $query_param_value[2])
405
-                            && !isset($query_param_value[3])
406
-                        ) {
407
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
408
-                                $field,
409
-                                $query_param_value[1],
410
-                                $requested_version,
411
-                                $timezone
412
-                            );
413
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
414
-                                $field,
415
-                                $query_param_value[2],
416
-                                $requested_version,
417
-                                $timezone
418
-                            );
419
-                        } elseif (array_key_exists($op, $model->valid_like_style_operators())
420
-                            && isset($query_param_value[1])
421
-                            && ! isset($query_param_value[2])
422
-                        ) {
423
-                            //we want to leave this value mostly-as-is (eg don't force it to be a float
424
-                            //or a boolean or an enum value. Leave it as-is with wildcards etc)
425
-                            //but do verify it at least doesn't have any serialized data
426
-                            ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
427
-                            $translated_value[] = $query_param_value[1];
428
-                        } elseif (array_key_exists($op, $model->valid_null_style_operators())
429
-                            && !isset($query_param_value[1])) {
430
-                            //no arguments should have been provided, so don't look for any
431
-                        } elseif (isset($query_param_value[1])
432
-                            && !isset($query_param_value[2])
433
-                            && ! array_key_exists(
434
-                                $op,
435
-                                array_merge(
436
-                                    $model->valid_in_style_operators(),
437
-                                    $model->valid_null_style_operators(),
438
-                                    $model->valid_like_style_operators(),
439
-                                    $model->valid_between_style_operators()
440
-                                )
441
-                            )
442
-                        ) {
443
-                            //it's a valid operator, but none of the exceptions. Treat it normally.
444
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
445
-                                $field,
446
-                                $query_param_value[1],
447
-                                $requested_version,
448
-                                $timezone
449
-                            );
450
-                        } else {
451
-                            //so they provided a valid operator, but wrong number of arguments
452
-                            if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
453
-                                throw new RestException(
454
-                                    'wrong_number_of_arguments',
455
-                                    sprintf(
456
-                                        esc_html__(
457
-                                            'The operator you provided, "%1$s" had the wrong number of arguments',
458
-                                            'event_espresso'
459
-                                        ),
460
-                                        $op
461
-                                    ),
462
-                                    array(
463
-                                        'status' => 400,
464
-                                    )
465
-                                );
466
-                            }
467
-                            $translated_value = null;
468
-                        }
469
-                    } else {
470
-                        //so they didn't provide a valid operator
471
-                        if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
472
-                            throw new RestException(
473
-                                'invalid_operator',
474
-                                sprintf(
475
-                                    esc_html__(
476
-                                        'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
477
-                                        'event_espresso'
478
-                                    ),
479
-                                    $query_param_key,
480
-                                    $query_param_value
481
-                                ),
482
-                                array(
483
-                                    'status' => 400,
484
-                                )
485
-                            );
486
-                        }
487
-                        //if we aren't in debug mode, then just try our best to fulfill the user's request
488
-                        $translated_value = null;
489
-                    }
490
-                } else {
491
-                    $translated_value = ModelDataTranslator::prepareFieldValueFromJson(
492
-                        $field,
493
-                        $query_param_value,
494
-                        $requested_version,
495
-                        $timezone
496
-                    );
497
-                }
498
-                if (
499
-                    (isset($query_param_for_models[$query_param_key]) && $is_gmt_datetime_field)
500
-                    ||
501
-                    $translated_value === null
502
-                ) {
503
-                    //they have already provided a non-gmt field, ignore the gmt one. That's what WP core
504
-                    //currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
505
-                    //OR we couldn't create a translated value from their input
506
-                    continue;
507
-                }
508
-                $query_param_for_models[$query_param_key] = $translated_value;
509
-            } else {
510
-                //so this param doesn't correspond to a field eh?
511
-                if ($writing) {
512
-                    //always tell API clients about invalid parameters when they're creating data. Otherwise,
513
-                    //they are probably going to create invalid data
514
-                    throw new RestException(
515
-                        'invalid_field',
516
-                        sprintf(
517
-                            esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
518
-                            $query_param_key
519
-                        )
520
-                    );
521
-                } else {
522
-                    //so it's not for a field, is it a logic query param key?
523
-                    if (in_array(
524
-                        $query_param_sans_stars,
525
-                        $model->logic_query_param_keys()
526
-                    )) {
527
-                        $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
528
-                            $query_param_value,
529
-                            $model,
530
-                            $requested_version
531
-                        );
532
-                    } elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
533
-                        //only tell API clients they got it wrong if we're in debug mode
534
-                        //otherwise try our best ot fulfill their request by ignoring this invalid data
535
-                        throw new RestException(
536
-                            'invalid_parameter',
537
-                            sprintf(
538
-                                esc_html__(
539
-                                    'You provided an invalid parameter, with key "%1$s"',
540
-                                    'event_espresso'
541
-                                ),
542
-                                $query_param_sans_stars
543
-                            ),
544
-                            array(
545
-                                'status' => 400,
546
-                            )
547
-                        );
548
-                    }
549
-                }
550
-            }
551
-        }
552
-        return $query_param_for_models;
553
-    }
554
-
555
-
556
-
557
-    /**
558
-     * Mostly checks if the last 4 characters are "_gmt", indicating its a
559
-     * gmt date field name
560
-     *
561
-     * @param string $field_name
562
-     * @return boolean
563
-     */
564
-    public static function isGmtDateFieldName($field_name)
565
-    {
566
-        return substr(
567
-            ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
568
-            -4,
569
-            4
570
-        ) === '_gmt';
571
-    }
572
-
573
-
574
-
575
-    /**
576
-     * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
577
-     *
578
-     * @param string $field_name
579
-     * @return string
580
-     */
581
-    public static function removeGmtFromFieldName($field_name)
582
-    {
583
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
584
-            return $field_name;
585
-        }
586
-        $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
587
-            $field_name
588
-        );
589
-        $query_param_sans_gmt_and_sans_stars = substr(
590
-            $query_param_sans_stars,
591
-            0,
592
-            strrpos(
593
-                $field_name,
594
-                '_gmt'
595
-            )
596
-        );
597
-        return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
598
-    }
599
-
600
-
601
-
602
-    /**
603
-     * Takes a field name from the REST API and prepares it for the model querying
604
-     *
605
-     * @param string $field_name
606
-     * @return string
607
-     */
608
-    public static function prepareFieldNameFromJson($field_name)
609
-    {
610
-        if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
611
-            return ModelDataTranslator::removeGmtFromFieldName($field_name);
612
-        }
613
-        return $field_name;
614
-    }
615
-
616
-
617
-
618
-    /**
619
-     * Takes array of field names from REST API and prepares for models
620
-     *
621
-     * @param array $field_names
622
-     * @return array of field names (possibly include model prefixes)
623
-     */
624
-    public static function prepareFieldNamesFromJson(array $field_names)
625
-    {
626
-        $new_array = array();
627
-        foreach ($field_names as $key => $field_name) {
628
-            $new_array[$key] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
629
-        }
630
-        return $new_array;
631
-    }
632
-
633
-
634
-
635
-    /**
636
-     * Takes array where array keys are field names (possibly with model path prefixes)
637
-     * from the REST API and prepares them for model querying
638
-     *
639
-     * @param array $field_names_as_keys
640
-     * @return array
641
-     */
642
-    public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
643
-    {
644
-        $new_array = array();
645
-        foreach ($field_names_as_keys as $field_name => $value) {
646
-            $new_array[ModelDataTranslator::prepareFieldNameFromJson($field_name)] = $value;
647
-        }
648
-        return $new_array;
649
-    }
650
-
651
-
652
-
653
-    /**
654
-     * Prepares an array of model query params for use in the REST API
655
-     *
656
-     * @param array     $model_query_params
657
-     * @param EEM_Base $model
658
-     * @param string    $requested_version eg "4.8.36". If null is provided, defaults to the latest release of the EE4
659
-     *                                     REST API
660
-     * @return array which can be passed into the EE4 REST API when querying a model resource
661
-     * @throws EE_Error
662
-     */
663
-    public static function prepareQueryParamsForRestApi(
664
-        array $model_query_params,
665
-        EEM_Base $model,
666
-        $requested_version = null
667
-    ) {
668
-        if ($requested_version === null) {
669
-            $requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
670
-        }
671
-        $rest_query_params = $model_query_params;
672
-        if (isset($model_query_params[0])) {
673
-            $rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
674
-                $model_query_params[0],
675
-                $model,
676
-                $requested_version
677
-            );
678
-            unset($rest_query_params[0]);
679
-        }
680
-        if (isset($model_query_params['having'])) {
681
-            $rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
682
-                $model_query_params['having'],
683
-                $model,
684
-                $requested_version
685
-            );
686
-        }
687
-        return apply_filters(
688
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
689
-            $rest_query_params,
690
-            $model_query_params,
691
-            $model,
692
-            $requested_version
693
-        );
694
-    }
695
-
696
-
697
-
698
-    /**
699
-     * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
700
-     *
701
-     * @param array     $inputted_query_params_of_this_type eg like the "where" or "having" conditions query params
702
-     *                                                      passed into EEM_Base::get_all()
703
-     * @param EEM_Base $model
704
-     * @param string    $requested_version                  eg "4.8.36"
705
-     * @return array ready for use in the rest api query params
706
-     * @throws EE_Error
707
-     * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
708
-     *                                     (which would be really unusual)
709
-     */
710
-    public static function prepareConditionsQueryParamsForRestApi(
711
-        $inputted_query_params_of_this_type,
712
-        EEM_Base $model,
713
-        $requested_version
714
-    ) {
715
-        $query_param_for_models = array();
716
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
717
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
718
-                ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
719
-                $model
720
-            );
721
-            if ($field instanceof EE_Model_Field_Base) {
722
-                //did they specify an operator?
723
-                if (is_array($query_param_value)) {
724
-                    $op = $query_param_value[0];
725
-                    $translated_value = array($op);
726
-                    if (isset($query_param_value[1])) {
727
-                        $value = $query_param_value[1];
728
-                        $translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
729
-                            $field,
730
-                            $value,
731
-                            $requested_version
732
-                        );
733
-                    }
734
-                } else {
735
-                    $translated_value = ModelDataTranslator::prepareFieldValueForJson(
736
-                        $field,
737
-                        $query_param_value,
738
-                        $requested_version
739
-                    );
740
-                }
741
-                $query_param_for_models[$query_param_key] = $translated_value;
742
-            } else {
743
-                //so it's not for a field, assume it's a logic query param key
744
-                $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
745
-                    $query_param_value,
746
-                    $model,
747
-                    $requested_version
748
-                );
749
-            }
750
-        }
751
-        return $query_param_for_models;
752
-    }
753
-
754
-
755
-
756
-    /**
757
-     * @param $condition_query_param_key
758
-     * @return string
759
-     */
760
-    public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
761
-    {
762
-        $pos_of_star = strpos($condition_query_param_key, '*');
763
-        if ($pos_of_star === false) {
764
-            return $condition_query_param_key;
765
-        } else {
766
-            $condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
767
-            return $condition_query_param_sans_star;
768
-        }
769
-    }
770
-
771
-
772
-
773
-    /**
774
-     * Takes the input parameter and finds the model field that it indicates.
775
-     *
776
-     * @param string    $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
777
-     * @param EEM_Base $model
778
-     * @return EE_Model_Field_Base
779
-     * @throws EE_Error
780
-     */
781
-    public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
782
-    {
783
-        //ok, now proceed with deducing which part is the model's name, and which is the field's name
784
-        //which will help us find the database table and column
785
-        $query_param_parts = explode('.', $query_param_name);
786
-        if (empty($query_param_parts)) {
787
-            throw new EE_Error(
788
-                sprintf(
789
-                    __(
790
-                        '_extract_column_name is empty when trying to extract column and table name from %s',
791
-                        'event_espresso'
792
-                    ),
793
-                    $query_param_name
794
-                )
795
-            );
796
-        }
797
-        $number_of_parts = count($query_param_parts);
798
-        $last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
799
-        if ($number_of_parts === 1) {
800
-            $field_name = $last_query_param_part;
801
-        } else {// $number_of_parts >= 2
802
-            //the last part is the column name, and there are only 2parts. therefore...
803
-            $field_name = $last_query_param_part;
804
-            $model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]);
805
-        }
806
-        try {
807
-            return $model->field_settings_for($field_name, false);
808
-        } catch (EE_Error $e) {
809
-            return null;
810
-        }
811
-    }
812
-
813
-
814
-
815
-    /**
816
-     * Returns true if $data can be easily represented in JSON.
817
-     * Basically, objects and resources can't be represented in JSON easily.
818
-     * @param mixed $data
819
-     * @return bool
820
-     */
821
-    protected static function isRepresentableInJson($data)
822
-    {
823
-        return is_scalar($data)
824
-               || is_array($data)
825
-               || is_null($data);
826
-    }
39
+	/**
40
+	 * We used to use -1 for infinity in the rest api, but that's ambiguous for
41
+	 * fields that COULD contain -1; so we use null
42
+	 */
43
+	const EE_INF_IN_REST = null;
44
+
45
+
46
+
47
+	/**
48
+	 * Prepares a possible array of input values from JSON for use by the models
49
+	 *
50
+	 * @param EE_Model_Field_Base $field_obj
51
+	 * @param mixed                $original_value_maybe_array
52
+	 * @param string               $requested_version
53
+	 * @param string               $timezone_string treat values as being in this timezone
54
+	 * @return mixed
55
+	 * @throws RestException
56
+	 */
57
+	public static function prepareFieldValuesFromJson(
58
+		$field_obj,
59
+		$original_value_maybe_array,
60
+		$requested_version,
61
+		$timezone_string = 'UTC'
62
+	) {
63
+		if (is_array($original_value_maybe_array)
64
+			&& ! $field_obj instanceof EE_Serialized_Text_Field
65
+		) {
66
+			$new_value_maybe_array = array();
67
+			foreach ($original_value_maybe_array as $array_key => $array_item) {
68
+				$new_value_maybe_array[$array_key] = ModelDataTranslator::prepareFieldValueFromJson(
69
+					$field_obj,
70
+					$array_item,
71
+					$requested_version,
72
+					$timezone_string
73
+				);
74
+			}
75
+		} else {
76
+			$new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
77
+				$field_obj,
78
+				$original_value_maybe_array,
79
+				$requested_version,
80
+				$timezone_string
81
+			);
82
+		}
83
+		return $new_value_maybe_array;
84
+	}
85
+
86
+
87
+
88
+	/**
89
+	 * Prepares an array of field values FOR use in JSON/REST API
90
+	 *
91
+	 * @param EE_Model_Field_Base $field_obj
92
+	 * @param mixed                $original_value_maybe_array
93
+	 * @param string               $request_version (eg 4.8.36)
94
+	 * @return array
95
+	 */
96
+	public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
97
+	{
98
+		if (is_array($original_value_maybe_array)) {
99
+			$new_value = array();
100
+			foreach ($original_value_maybe_array as $key => $value) {
101
+				$new_value[$key] = ModelDataTranslator::prepareFieldValuesForJson($field_obj, $value, $request_version);
102
+			}
103
+		} else {
104
+			$new_value = ModelDataTranslator::prepareFieldValueForJson(
105
+				$field_obj,
106
+				$original_value_maybe_array,
107
+				$request_version
108
+			);
109
+		}
110
+		return $new_value;
111
+	}
112
+
113
+
114
+
115
+	/**
116
+	 * Prepares incoming data from the json or $_REQUEST parameters for the models'
117
+	 * "$query_params".
118
+	 *
119
+	 * @param EE_Model_Field_Base $field_obj
120
+	 * @param mixed                $original_value
121
+	 * @param string               $requested_version
122
+	 * @param string               $timezone_string treat values as being in this timezone
123
+	 * @return mixed
124
+	 * @throws RestException
125
+	 */
126
+	public static function prepareFieldValueFromJson(
127
+		$field_obj,
128
+		$original_value,
129
+		$requested_version,
130
+		$timezone_string = 'UTC' // UTC
131
+	) {
132
+		//check if they accidentally submitted an error value. If so throw an exception
133
+		if (is_array($original_value)
134
+			&& isset($original_value['error_code'], $original_value['error_message'])) {
135
+			throw new RestException(
136
+				'rest_submitted_error_value',
137
+				sprintf(
138
+					esc_html__(
139
+						'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
140
+						'event_espresso'
141
+					),
142
+					$field_obj->get_name()
143
+				),
144
+				array(
145
+					'status' => 400,
146
+				)
147
+			);
148
+		}
149
+		//double-check for serialized PHP. We never accept serialized PHP. No way Jose.
150
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
151
+		$timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
152
+		$new_value = null;
153
+		//walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
154
+		// way Jose.
155
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
156
+		if ($field_obj instanceof EE_Infinite_Integer_Field
157
+			&& in_array($original_value, array(null, ''), true)
158
+		) {
159
+			$new_value = EE_INF;
160
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
161
+			list($offset_sign, $offset_secs) = ModelDataTranslator::parseTimezoneOffset(
162
+				$field_obj->get_timezone_offset(
163
+					new \DateTimeZone($timezone_string),
164
+					$original_value
165
+				)
166
+			);
167
+			$offset_string =
168
+				str_pad(
169
+					floor($offset_secs / HOUR_IN_SECONDS),
170
+					2,
171
+					'0',
172
+					STR_PAD_LEFT
173
+				)
174
+				. ':'
175
+				. str_pad(
176
+					($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
177
+					2,
178
+					'0',
179
+					STR_PAD_LEFT
180
+				);
181
+			$new_value = rest_parse_date($original_value . $offset_sign . $offset_string);
182
+		} else {
183
+			$new_value = $original_value;
184
+		}
185
+		return $new_value;
186
+	}
187
+
188
+
189
+
190
+	/**
191
+	 * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
192
+	 * think that can happen). If $data is an array, recurses into its keys and values
193
+	 * @param mixed $data
194
+	 * @throws RestException
195
+	 * @return void
196
+	 */
197
+	public static function throwExceptionIfContainsSerializedData($data)
198
+	{
199
+		if (is_array($data)) {
200
+			foreach ($data as $key => $value) {
201
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
202
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
203
+			}
204
+		} else {
205
+			if (is_serialized($data) || is_object($data)) {
206
+				throw new RestException(
207
+					'serialized_data_submission_prohibited',
208
+					esc_html__(
209
+						// @codingStandardsIgnoreStart
210
+						'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
211
+						// @codingStandardsIgnoreEnd
212
+						'event_espresso'
213
+					)
214
+				);
215
+			}
216
+		}
217
+	}
218
+
219
+
220
+
221
+	/**
222
+	 * determines what's going on with them timezone strings
223
+	 *
224
+	 * @param int $timezone_offset
225
+	 * @return array
226
+	 */
227
+	private static function parseTimezoneOffset($timezone_offset)
228
+	{
229
+		$first_char = substr((string)$timezone_offset, 0, 1);
230
+		if ($first_char === '+' || $first_char === '-') {
231
+			$offset_sign = $first_char;
232
+			$offset_secs = substr((string)$timezone_offset, 1);
233
+		} else {
234
+			$offset_sign = '+';
235
+			$offset_secs = $timezone_offset;
236
+		}
237
+		return array($offset_sign, $offset_secs);
238
+	}
239
+
240
+
241
+
242
+	/**
243
+	 * Prepares a field's value for display in the API
244
+	 *
245
+	 * @param EE_Model_Field_Base $field_obj
246
+	 * @param mixed                $original_value
247
+	 * @param string               $requested_version
248
+	 * @return mixed
249
+	 */
250
+	public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
251
+	{
252
+		if ($original_value === EE_INF) {
253
+			$new_value = ModelDataTranslator::EE_INF_IN_REST;
254
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
255
+			if (is_string($original_value)) {
256
+				//did they submit a string of a unix timestamp?
257
+				if (is_numeric($original_value)) {
258
+					$datetime_obj = new \DateTime();
259
+					$datetime_obj->setTimestamp((int)$original_value);
260
+				} else {
261
+					//first, check if its a MySQL timestamp in GMT
262
+					$datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
263
+				}
264
+				if (! $datetime_obj instanceof \DateTime) {
265
+					//so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
266
+					$datetime_obj = $field_obj->prepare_for_set($original_value);
267
+				}
268
+				$original_value = $datetime_obj;
269
+			}
270
+			if ($original_value instanceof \DateTime) {
271
+				$new_value = $original_value->format('Y-m-d H:i:s');
272
+			} elseif (is_int($original_value)) {
273
+				$new_value = date('Y-m-d H:i:s', $original_value);
274
+			} elseif($original_value === null || $original_value === '') {
275
+				$new_value = null;
276
+			} else {
277
+				//so it's not a datetime object, unix timestamp (as string or int),
278
+				//MySQL timestamp, or even a string in the field object's format. So no idea what it is
279
+				throw new \EE_Error(
280
+					sprintf(
281
+						esc_html__(
282
+						// @codingStandardsIgnoreStart
283
+							'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".',
284
+							// @codingStandardsIgnoreEnd
285
+							'event_espressso'
286
+						),
287
+						$original_value,
288
+						$field_obj->get_name(),
289
+						$field_obj->get_model_name(),
290
+						$field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
291
+					)
292
+				);
293
+			}
294
+			$new_value = mysql_to_rfc3339($new_value);
295
+		} else {
296
+			$new_value = $original_value;
297
+		}
298
+		//are we about to send an object? just don't. We have no good way to represent it in JSON.
299
+		// can't just check using is_object() because that missed PHP incomplete objects
300
+		if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
301
+			$new_value = array(
302
+				'error_code' => 'php_object_not_return',
303
+				'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso')
304
+			);
305
+		}
306
+		return apply_filters(
307
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
308
+			$new_value,
309
+			$field_obj,
310
+			$original_value,
311
+			$requested_version
312
+		);
313
+	}
314
+
315
+
316
+
317
+	/**
318
+	 * Prepares condition-query-parameters (like what's in where and having) from
319
+	 * the format expected in the API to use in the models
320
+	 *
321
+	 * @param array     $inputted_query_params_of_this_type
322
+	 * @param EEM_Base $model
323
+	 * @param string    $requested_version
324
+	 * @param boolean $writing whether this data will be written to the DB, or if we're just building a query.
325
+	 *                         If we're writing to the DB, we don't expect any operators, or any logic query parameters,
326
+	 *                         and we also won't accept serialized data unless the current user has unfiltered_html.
327
+	 * @return array
328
+	 * @throws \DomainException
329
+	 * @throws RestException
330
+	 * @throws EE_Error
331
+	 */
332
+	public static function prepareConditionsQueryParamsForModels(
333
+		$inputted_query_params_of_this_type,
334
+		EEM_Base $model,
335
+		$requested_version,
336
+		$writing = false
337
+	) {
338
+		$query_param_for_models = array();
339
+		$valid_operators = $model->valid_operators();
340
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
341
+			$is_gmt_datetime_field = false;
342
+			$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
343
+				$query_param_key
344
+			);
345
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
346
+				$query_param_sans_stars,
347
+				$model
348
+			);
349
+			//double-check is it a *_gmt field?
350
+			if (! $field instanceof EE_Model_Field_Base
351
+				&& ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
352
+			) {
353
+				//yep, take off '_gmt', and find the field
354
+				$query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars);
355
+				$field = ModelDataTranslator::deduceFieldFromQueryParam(
356
+					$query_param_key,
357
+					$model
358
+				);
359
+				$timezone = 'UTC';
360
+				$is_gmt_datetime_field = true;
361
+			} elseif ($field instanceof EE_Datetime_Field) {
362
+				//so it's not a GMT field. Set the timezone on the model to the default
363
+				$timezone = \EEH_DTT_Helper::get_valid_timezone_string();
364
+			} else {
365
+				//just keep using what's already set for the timezone
366
+				$timezone = $model->get_timezone();
367
+			}
368
+			if ($field instanceof EE_Model_Field_Base) {
369
+				if (! $writing && is_array($query_param_value)) {
370
+					if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
371
+						if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
372
+							throw new RestException(
373
+								'numerically_indexed_array_of_values_only',
374
+								sprintf(
375
+									esc_html__(
376
+										'The array provided for the parameter "%1$s" should be numerically indexed.',
377
+										'event_espresso'
378
+									),
379
+									$query_param_key
380
+								),
381
+								array(
382
+									'status' => 400,
383
+								)
384
+							);
385
+						}
386
+					}
387
+					//did they specify an operator?
388
+					if (isset($query_param_value[0])
389
+						&& isset($valid_operators[$query_param_value[0]])
390
+					) {
391
+						$op = $query_param_value[0];
392
+						$translated_value = array($op);
393
+						if (array_key_exists($op, $model->valid_in_style_operators())
394
+							&& isset($query_param_value[1])
395
+							&& ! isset($query_param_value[2])
396
+						) {
397
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
398
+								$field,
399
+								$query_param_value[1],
400
+								$requested_version,
401
+								$timezone
402
+							);
403
+						} elseif (array_key_exists($op, $model->valid_between_style_operators())
404
+							&& isset($query_param_value[1], $query_param_value[2])
405
+							&& !isset($query_param_value[3])
406
+						) {
407
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
408
+								$field,
409
+								$query_param_value[1],
410
+								$requested_version,
411
+								$timezone
412
+							);
413
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
414
+								$field,
415
+								$query_param_value[2],
416
+								$requested_version,
417
+								$timezone
418
+							);
419
+						} elseif (array_key_exists($op, $model->valid_like_style_operators())
420
+							&& isset($query_param_value[1])
421
+							&& ! isset($query_param_value[2])
422
+						) {
423
+							//we want to leave this value mostly-as-is (eg don't force it to be a float
424
+							//or a boolean or an enum value. Leave it as-is with wildcards etc)
425
+							//but do verify it at least doesn't have any serialized data
426
+							ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
427
+							$translated_value[] = $query_param_value[1];
428
+						} elseif (array_key_exists($op, $model->valid_null_style_operators())
429
+							&& !isset($query_param_value[1])) {
430
+							//no arguments should have been provided, so don't look for any
431
+						} elseif (isset($query_param_value[1])
432
+							&& !isset($query_param_value[2])
433
+							&& ! array_key_exists(
434
+								$op,
435
+								array_merge(
436
+									$model->valid_in_style_operators(),
437
+									$model->valid_null_style_operators(),
438
+									$model->valid_like_style_operators(),
439
+									$model->valid_between_style_operators()
440
+								)
441
+							)
442
+						) {
443
+							//it's a valid operator, but none of the exceptions. Treat it normally.
444
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
445
+								$field,
446
+								$query_param_value[1],
447
+								$requested_version,
448
+								$timezone
449
+							);
450
+						} else {
451
+							//so they provided a valid operator, but wrong number of arguments
452
+							if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
453
+								throw new RestException(
454
+									'wrong_number_of_arguments',
455
+									sprintf(
456
+										esc_html__(
457
+											'The operator you provided, "%1$s" had the wrong number of arguments',
458
+											'event_espresso'
459
+										),
460
+										$op
461
+									),
462
+									array(
463
+										'status' => 400,
464
+									)
465
+								);
466
+							}
467
+							$translated_value = null;
468
+						}
469
+					} else {
470
+						//so they didn't provide a valid operator
471
+						if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
472
+							throw new RestException(
473
+								'invalid_operator',
474
+								sprintf(
475
+									esc_html__(
476
+										'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
477
+										'event_espresso'
478
+									),
479
+									$query_param_key,
480
+									$query_param_value
481
+								),
482
+								array(
483
+									'status' => 400,
484
+								)
485
+							);
486
+						}
487
+						//if we aren't in debug mode, then just try our best to fulfill the user's request
488
+						$translated_value = null;
489
+					}
490
+				} else {
491
+					$translated_value = ModelDataTranslator::prepareFieldValueFromJson(
492
+						$field,
493
+						$query_param_value,
494
+						$requested_version,
495
+						$timezone
496
+					);
497
+				}
498
+				if (
499
+					(isset($query_param_for_models[$query_param_key]) && $is_gmt_datetime_field)
500
+					||
501
+					$translated_value === null
502
+				) {
503
+					//they have already provided a non-gmt field, ignore the gmt one. That's what WP core
504
+					//currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
505
+					//OR we couldn't create a translated value from their input
506
+					continue;
507
+				}
508
+				$query_param_for_models[$query_param_key] = $translated_value;
509
+			} else {
510
+				//so this param doesn't correspond to a field eh?
511
+				if ($writing) {
512
+					//always tell API clients about invalid parameters when they're creating data. Otherwise,
513
+					//they are probably going to create invalid data
514
+					throw new RestException(
515
+						'invalid_field',
516
+						sprintf(
517
+							esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
518
+							$query_param_key
519
+						)
520
+					);
521
+				} else {
522
+					//so it's not for a field, is it a logic query param key?
523
+					if (in_array(
524
+						$query_param_sans_stars,
525
+						$model->logic_query_param_keys()
526
+					)) {
527
+						$query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
528
+							$query_param_value,
529
+							$model,
530
+							$requested_version
531
+						);
532
+					} elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
533
+						//only tell API clients they got it wrong if we're in debug mode
534
+						//otherwise try our best ot fulfill their request by ignoring this invalid data
535
+						throw new RestException(
536
+							'invalid_parameter',
537
+							sprintf(
538
+								esc_html__(
539
+									'You provided an invalid parameter, with key "%1$s"',
540
+									'event_espresso'
541
+								),
542
+								$query_param_sans_stars
543
+							),
544
+							array(
545
+								'status' => 400,
546
+							)
547
+						);
548
+					}
549
+				}
550
+			}
551
+		}
552
+		return $query_param_for_models;
553
+	}
554
+
555
+
556
+
557
+	/**
558
+	 * Mostly checks if the last 4 characters are "_gmt", indicating its a
559
+	 * gmt date field name
560
+	 *
561
+	 * @param string $field_name
562
+	 * @return boolean
563
+	 */
564
+	public static function isGmtDateFieldName($field_name)
565
+	{
566
+		return substr(
567
+			ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
568
+			-4,
569
+			4
570
+		) === '_gmt';
571
+	}
572
+
573
+
574
+
575
+	/**
576
+	 * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
577
+	 *
578
+	 * @param string $field_name
579
+	 * @return string
580
+	 */
581
+	public static function removeGmtFromFieldName($field_name)
582
+	{
583
+		if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
584
+			return $field_name;
585
+		}
586
+		$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
587
+			$field_name
588
+		);
589
+		$query_param_sans_gmt_and_sans_stars = substr(
590
+			$query_param_sans_stars,
591
+			0,
592
+			strrpos(
593
+				$field_name,
594
+				'_gmt'
595
+			)
596
+		);
597
+		return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
598
+	}
599
+
600
+
601
+
602
+	/**
603
+	 * Takes a field name from the REST API and prepares it for the model querying
604
+	 *
605
+	 * @param string $field_name
606
+	 * @return string
607
+	 */
608
+	public static function prepareFieldNameFromJson($field_name)
609
+	{
610
+		if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
611
+			return ModelDataTranslator::removeGmtFromFieldName($field_name);
612
+		}
613
+		return $field_name;
614
+	}
615
+
616
+
617
+
618
+	/**
619
+	 * Takes array of field names from REST API and prepares for models
620
+	 *
621
+	 * @param array $field_names
622
+	 * @return array of field names (possibly include model prefixes)
623
+	 */
624
+	public static function prepareFieldNamesFromJson(array $field_names)
625
+	{
626
+		$new_array = array();
627
+		foreach ($field_names as $key => $field_name) {
628
+			$new_array[$key] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
629
+		}
630
+		return $new_array;
631
+	}
632
+
633
+
634
+
635
+	/**
636
+	 * Takes array where array keys are field names (possibly with model path prefixes)
637
+	 * from the REST API and prepares them for model querying
638
+	 *
639
+	 * @param array $field_names_as_keys
640
+	 * @return array
641
+	 */
642
+	public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
643
+	{
644
+		$new_array = array();
645
+		foreach ($field_names_as_keys as $field_name => $value) {
646
+			$new_array[ModelDataTranslator::prepareFieldNameFromJson($field_name)] = $value;
647
+		}
648
+		return $new_array;
649
+	}
650
+
651
+
652
+
653
+	/**
654
+	 * Prepares an array of model query params for use in the REST API
655
+	 *
656
+	 * @param array     $model_query_params
657
+	 * @param EEM_Base $model
658
+	 * @param string    $requested_version eg "4.8.36". If null is provided, defaults to the latest release of the EE4
659
+	 *                                     REST API
660
+	 * @return array which can be passed into the EE4 REST API when querying a model resource
661
+	 * @throws EE_Error
662
+	 */
663
+	public static function prepareQueryParamsForRestApi(
664
+		array $model_query_params,
665
+		EEM_Base $model,
666
+		$requested_version = null
667
+	) {
668
+		if ($requested_version === null) {
669
+			$requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
670
+		}
671
+		$rest_query_params = $model_query_params;
672
+		if (isset($model_query_params[0])) {
673
+			$rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
674
+				$model_query_params[0],
675
+				$model,
676
+				$requested_version
677
+			);
678
+			unset($rest_query_params[0]);
679
+		}
680
+		if (isset($model_query_params['having'])) {
681
+			$rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
682
+				$model_query_params['having'],
683
+				$model,
684
+				$requested_version
685
+			);
686
+		}
687
+		return apply_filters(
688
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
689
+			$rest_query_params,
690
+			$model_query_params,
691
+			$model,
692
+			$requested_version
693
+		);
694
+	}
695
+
696
+
697
+
698
+	/**
699
+	 * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
700
+	 *
701
+	 * @param array     $inputted_query_params_of_this_type eg like the "where" or "having" conditions query params
702
+	 *                                                      passed into EEM_Base::get_all()
703
+	 * @param EEM_Base $model
704
+	 * @param string    $requested_version                  eg "4.8.36"
705
+	 * @return array ready for use in the rest api query params
706
+	 * @throws EE_Error
707
+	 * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
708
+	 *                                     (which would be really unusual)
709
+	 */
710
+	public static function prepareConditionsQueryParamsForRestApi(
711
+		$inputted_query_params_of_this_type,
712
+		EEM_Base $model,
713
+		$requested_version
714
+	) {
715
+		$query_param_for_models = array();
716
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
717
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
718
+				ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
719
+				$model
720
+			);
721
+			if ($field instanceof EE_Model_Field_Base) {
722
+				//did they specify an operator?
723
+				if (is_array($query_param_value)) {
724
+					$op = $query_param_value[0];
725
+					$translated_value = array($op);
726
+					if (isset($query_param_value[1])) {
727
+						$value = $query_param_value[1];
728
+						$translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
729
+							$field,
730
+							$value,
731
+							$requested_version
732
+						);
733
+					}
734
+				} else {
735
+					$translated_value = ModelDataTranslator::prepareFieldValueForJson(
736
+						$field,
737
+						$query_param_value,
738
+						$requested_version
739
+					);
740
+				}
741
+				$query_param_for_models[$query_param_key] = $translated_value;
742
+			} else {
743
+				//so it's not for a field, assume it's a logic query param key
744
+				$query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
745
+					$query_param_value,
746
+					$model,
747
+					$requested_version
748
+				);
749
+			}
750
+		}
751
+		return $query_param_for_models;
752
+	}
753
+
754
+
755
+
756
+	/**
757
+	 * @param $condition_query_param_key
758
+	 * @return string
759
+	 */
760
+	public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
761
+	{
762
+		$pos_of_star = strpos($condition_query_param_key, '*');
763
+		if ($pos_of_star === false) {
764
+			return $condition_query_param_key;
765
+		} else {
766
+			$condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
767
+			return $condition_query_param_sans_star;
768
+		}
769
+	}
770
+
771
+
772
+
773
+	/**
774
+	 * Takes the input parameter and finds the model field that it indicates.
775
+	 *
776
+	 * @param string    $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
777
+	 * @param EEM_Base $model
778
+	 * @return EE_Model_Field_Base
779
+	 * @throws EE_Error
780
+	 */
781
+	public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
782
+	{
783
+		//ok, now proceed with deducing which part is the model's name, and which is the field's name
784
+		//which will help us find the database table and column
785
+		$query_param_parts = explode('.', $query_param_name);
786
+		if (empty($query_param_parts)) {
787
+			throw new EE_Error(
788
+				sprintf(
789
+					__(
790
+						'_extract_column_name is empty when trying to extract column and table name from %s',
791
+						'event_espresso'
792
+					),
793
+					$query_param_name
794
+				)
795
+			);
796
+		}
797
+		$number_of_parts = count($query_param_parts);
798
+		$last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
799
+		if ($number_of_parts === 1) {
800
+			$field_name = $last_query_param_part;
801
+		} else {// $number_of_parts >= 2
802
+			//the last part is the column name, and there are only 2parts. therefore...
803
+			$field_name = $last_query_param_part;
804
+			$model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]);
805
+		}
806
+		try {
807
+			return $model->field_settings_for($field_name, false);
808
+		} catch (EE_Error $e) {
809
+			return null;
810
+		}
811
+	}
812
+
813
+
814
+
815
+	/**
816
+	 * Returns true if $data can be easily represented in JSON.
817
+	 * Basically, objects and resources can't be represented in JSON easily.
818
+	 * @param mixed $data
819
+	 * @return bool
820
+	 */
821
+	protected static function isRepresentableInJson($data)
822
+	{
823
+		return is_scalar($data)
824
+			   || is_array($data)
825
+			   || is_null($data);
826
+	}
827 827
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -10,7 +10,7 @@  discard block
 block discarded – undo
10 10
 use EE_Serialized_Text_Field;
11 11
 use EEM_Base;
12 12
 
13
-if (! defined('EVENT_ESPRESSO_VERSION')) {
13
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
14 14
     exit('No direct script access allowed');
15 15
 }
16 16
 
@@ -178,7 +178,7 @@  discard block
 block discarded – undo
178 178
                     '0',
179 179
                     STR_PAD_LEFT
180 180
                 );
181
-            $new_value = rest_parse_date($original_value . $offset_sign . $offset_string);
181
+            $new_value = rest_parse_date($original_value.$offset_sign.$offset_string);
182 182
         } else {
183 183
             $new_value = $original_value;
184 184
         }
@@ -226,10 +226,10 @@  discard block
 block discarded – undo
226 226
      */
227 227
     private static function parseTimezoneOffset($timezone_offset)
228 228
     {
229
-        $first_char = substr((string)$timezone_offset, 0, 1);
229
+        $first_char = substr((string) $timezone_offset, 0, 1);
230 230
         if ($first_char === '+' || $first_char === '-') {
231 231
             $offset_sign = $first_char;
232
-            $offset_secs = substr((string)$timezone_offset, 1);
232
+            $offset_secs = substr((string) $timezone_offset, 1);
233 233
         } else {
234 234
             $offset_sign = '+';
235 235
             $offset_secs = $timezone_offset;
@@ -256,12 +256,12 @@  discard block
 block discarded – undo
256 256
                 //did they submit a string of a unix timestamp?
257 257
                 if (is_numeric($original_value)) {
258 258
                     $datetime_obj = new \DateTime();
259
-                    $datetime_obj->setTimestamp((int)$original_value);
259
+                    $datetime_obj->setTimestamp((int) $original_value);
260 260
                 } else {
261 261
                     //first, check if its a MySQL timestamp in GMT
262 262
                     $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
263 263
                 }
264
-                if (! $datetime_obj instanceof \DateTime) {
264
+                if ( ! $datetime_obj instanceof \DateTime) {
265 265
                     //so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
266 266
                     $datetime_obj = $field_obj->prepare_for_set($original_value);
267 267
                 }
@@ -271,7 +271,7 @@  discard block
 block discarded – undo
271 271
                 $new_value = $original_value->format('Y-m-d H:i:s');
272 272
             } elseif (is_int($original_value)) {
273 273
                 $new_value = date('Y-m-d H:i:s', $original_value);
274
-            } elseif($original_value === null || $original_value === '') {
274
+            } elseif ($original_value === null || $original_value === '') {
275 275
                 $new_value = null;
276 276
             } else {
277 277
                 //so it's not a datetime object, unix timestamp (as string or int),
@@ -287,7 +287,7 @@  discard block
 block discarded – undo
287 287
                         $original_value,
288 288
                         $field_obj->get_name(),
289 289
                         $field_obj->get_model_name(),
290
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
290
+                        $field_obj->get_time_format().' '.$field_obj->get_time_format()
291 291
                     )
292 292
                 );
293 293
             }
@@ -297,7 +297,7 @@  discard block
 block discarded – undo
297 297
         }
298 298
         //are we about to send an object? just don't. We have no good way to represent it in JSON.
299 299
         // can't just check using is_object() because that missed PHP incomplete objects
300
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
300
+        if ( ! ModelDataTranslator::isRepresentableInJson($new_value)) {
301 301
             $new_value = array(
302 302
                 'error_code' => 'php_object_not_return',
303 303
                 'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso')
@@ -347,7 +347,7 @@  discard block
 block discarded – undo
347 347
                 $model
348 348
             );
349 349
             //double-check is it a *_gmt field?
350
-            if (! $field instanceof EE_Model_Field_Base
350
+            if ( ! $field instanceof EE_Model_Field_Base
351 351
                 && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
352 352
             ) {
353 353
                 //yep, take off '_gmt', and find the field
@@ -366,8 +366,8 @@  discard block
 block discarded – undo
366 366
                 $timezone = $model->get_timezone();
367 367
             }
368 368
             if ($field instanceof EE_Model_Field_Base) {
369
-                if (! $writing && is_array($query_param_value)) {
370
-                    if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
369
+                if ( ! $writing && is_array($query_param_value)) {
370
+                    if ( ! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
371 371
                         if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
372 372
                             throw new RestException(
373 373
                                 'numerically_indexed_array_of_values_only',
@@ -402,7 +402,7 @@  discard block
 block discarded – undo
402 402
                             );
403 403
                         } elseif (array_key_exists($op, $model->valid_between_style_operators())
404 404
                             && isset($query_param_value[1], $query_param_value[2])
405
-                            && !isset($query_param_value[3])
405
+                            && ! isset($query_param_value[3])
406 406
                         ) {
407 407
                             $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
408 408
                                 $field,
@@ -426,10 +426,10 @@  discard block
 block discarded – undo
426 426
                             ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
427 427
                             $translated_value[] = $query_param_value[1];
428 428
                         } elseif (array_key_exists($op, $model->valid_null_style_operators())
429
-                            && !isset($query_param_value[1])) {
429
+                            && ! isset($query_param_value[1])) {
430 430
                             //no arguments should have been provided, so don't look for any
431 431
                         } elseif (isset($query_param_value[1])
432
-                            && !isset($query_param_value[2])
432
+                            && ! isset($query_param_value[2])
433 433
                             && ! array_key_exists(
434 434
                                 $op,
435 435
                                 array_merge(
@@ -580,7 +580,7 @@  discard block
 block discarded – undo
580 580
      */
581 581
     public static function removeGmtFromFieldName($field_name)
582 582
     {
583
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
583
+        if ( ! ModelDataTranslator::isGmtDateFieldName($field_name)) {
584 584
             return $field_name;
585 585
         }
586 586
         $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
Please login to merge, or discard this patch.
core/exceptions/InvalidEntityException.php 2 patches
Indentation   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -3,7 +3,7 @@  discard block
 block discarded – undo
3 3
 namespace EventEspresso\core\exceptions;
4 4
 
5 5
 if (! defined('EVENT_ESPRESSO_VERSION')) {
6
-    exit('No direct script access allowed');
6
+	exit('No direct script access allowed');
7 7
 }
8 8
 
9 9
 
@@ -18,32 +18,32 @@  discard block
 block discarded – undo
18 18
 class InvalidEntityException extends \InvalidArgumentException
19 19
 {
20 20
 
21
-    /**
22
-     * InvalidInterfaceException constructor.
23
-     *
24
-     * @param string     $actual   classname of what we got
25
-     * @param string     $expected classname of the entity we wanted
26
-     * @param string     $message
27
-     * @param int        $code
28
-     * @param \Exception $previous
29
-     */
30
-    public function __construct($actual, $expected, $message = '', $code = 0, \Exception $previous = null)
31
-    {
32
-        if (empty($message)) {
33
-            $message = sprintf(
34
-                __(
35
-                    'The supplied entity is an instance of "%1$s", but an instance of "%2$s" was expected. Object: %3$s',
36
-                    'event_espresso'
37
-                ),
38
-                is_object($actual)
39
-                    ? get_class($actual)
40
-                    : gettype($actual),
41
-                $expected,
42
-                var_export($actual, true)
43
-            );
44
-        }
45
-        parent::__construct($message, $code, $previous);
46
-    }
21
+	/**
22
+	 * InvalidInterfaceException constructor.
23
+	 *
24
+	 * @param string     $actual   classname of what we got
25
+	 * @param string     $expected classname of the entity we wanted
26
+	 * @param string     $message
27
+	 * @param int        $code
28
+	 * @param \Exception $previous
29
+	 */
30
+	public function __construct($actual, $expected, $message = '', $code = 0, \Exception $previous = null)
31
+	{
32
+		if (empty($message)) {
33
+			$message = sprintf(
34
+				__(
35
+					'The supplied entity is an instance of "%1$s", but an instance of "%2$s" was expected. Object: %3$s',
36
+					'event_espresso'
37
+				),
38
+				is_object($actual)
39
+					? get_class($actual)
40
+					: gettype($actual),
41
+				$expected,
42
+				var_export($actual, true)
43
+			);
44
+		}
45
+		parent::__construct($message, $code, $previous);
46
+	}
47 47
 
48 48
 }
49 49
 // End of file InvalidEntityException.php
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -2,7 +2,7 @@
 block discarded – undo
2 2
 
3 3
 namespace EventEspresso\core\exceptions;
4 4
 
5
-if (! defined('EVENT_ESPRESSO_VERSION')) {
5
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
6 6
     exit('No direct script access allowed');
7 7
 }
8 8
 
Please login to merge, or discard this patch.
core/libraries/form_sections/inputs/EE_Email_Input.input.php 1 patch
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -6,22 +6,22 @@
 block discarded – undo
6 6
  * @subpackage
7 7
  * @author				Mike Nelson
8 8
  */
9
-class EE_Email_Input extends EE_Form_Input_Base{
9
+class EE_Email_Input extends EE_Form_Input_Base {
10 10
 
11 11
 	/**
12 12
 	 * @param array $input_settings
13 13
 	 */
14
-	public function __construct( $input_settings = array() ){
15
-		$this->_set_display_strategy( new EE_Text_Input_Display_Strategy('email') );
16
-		$this->_set_normalization_strategy( new EE_Text_Normalization() );
14
+	public function __construct($input_settings = array()) {
15
+		$this->_set_display_strategy(new EE_Text_Input_Display_Strategy('email'));
16
+		$this->_set_normalization_strategy(new EE_Text_Normalization());
17 17
 		$this->_add_validation_strategy(
18 18
 			new EE_Email_Validation_Strategy(
19
-				isset( $input_settings[ 'validation_error_message' ] )
20
-					? $input_settings[ 'validation_error_message' ]
19
+				isset($input_settings['validation_error_message'])
20
+					? $input_settings['validation_error_message']
21 21
 					: NULL
22 22
 			)
23 23
 		);
24
-		parent::__construct( $input_settings );
25
-		$this->set_html_class( $this->html_class() . ' email' );
24
+		parent::__construct($input_settings);
25
+		$this->set_html_class($this->html_class().' email');
26 26
 	}
27 27
 }
Please login to merge, or discard this patch.
admin_pages/transactions/EE_Admin_Transactions_List_Table.class.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -102,7 +102,7 @@  discard block
 block discarded – undo
102 102
      *
103 103
      * @abstract
104 104
      * @access protected
105
-     * @return array
105
+     * @return string[]
106 106
      */
107 107
     protected function _get_table_filters()
108 108
     {
@@ -265,7 +265,7 @@  discard block
 block discarded – undo
265 265
      *    column_TXN_paid
266 266
      *
267 267
      * @param \EE_Transaction $transaction
268
-     * @return mixed|string
268
+     * @return string
269 269
      * @throws \EE_Error
270 270
      */
271 271
     public function column_TXN_paid(EE_Transaction $transaction)
Please login to merge, or discard this patch.
Indentation   +606 added lines, -606 removed lines patch added patch discarded remove patch
@@ -13,114 +13,114 @@  discard block
 block discarded – undo
13 13
 class EE_Admin_Transactions_List_Table extends EE_Admin_List_Table
14 14
 {
15 15
 
16
-    private $_status;
17
-
18
-
19
-    /**
20
-     * @param \Transactions_Admin_Page $admin_page
21
-     */
22
-    public function __construct(\Transactions_Admin_Page $admin_page)
23
-    {
24
-        parent::__construct($admin_page);
25
-        $this->_status = $this->_admin_page->get_transaction_status_array();
26
-    }
27
-
28
-
29
-    /**
30
-     *_setup_data
31
-     */
32
-    protected function _setup_data()
33
-    {
34
-        $this->_data           = $this->_admin_page->get_transactions($this->_per_page);
35
-        $status                = ! empty($this->_req_data['status']) ? $this->_req_data['status'] : 'all';
36
-        $this->_all_data_count = $this->_admin_page->get_transactions($this->_per_page, true, $status);
37
-    }
38
-
39
-
40
-    /**
41
-     *_set_properties
42
-     */
43
-    protected function _set_properties()
44
-    {
45
-        $this->_wp_list_args = array(
46
-            'singular' => __('transaction', 'event_espresso'),
47
-            'plural'   => __('transactions', 'event_espresso'),
48
-            'ajax'     => true,
49
-            'screen'   => $this->_admin_page->get_current_screen()->id,
50
-        );
51
-        $ID_column_name      = __('ID', 'event_espresso');
52
-        $ID_column_name      .= ' : <span class="show-on-mobile-view-only" style="float:none">';
53
-        $ID_column_name      .= __('Transaction Date', 'event_espresso');
54
-        $ID_column_name      .= '</span> ';
55
-        $this->_columns      = array(
56
-            'TXN_ID'        => $ID_column_name,
57
-            'TXN_timestamp' => __('Transaction Date', 'event_espresso'),
58
-            'TXN_total'     => __('Total', 'event_espresso'),
59
-            'TXN_paid'      => __('Paid', 'event_espresso'),
60
-            'ATT_fname'     => __('Primary Registrant', 'event_espresso'),
61
-            'event_name'    => __('Event', 'event_espresso'),
62
-            'actions'       => __('Actions', 'event_espresso'),
63
-        );
64
-
65
-        $this->_sortable_columns = array(
66
-            'TXN_ID'        => array('TXN_ID' => false),
67
-            'event_name'    => array('event_name' => false),
68
-            'ATT_fname'     => array('ATT_fname' => false),
69
-            'TXN_timestamp' => array('TXN_timestamp' => true) //true means its already sorted
70
-        );
71
-
72
-        $this->_primary_column = 'TXN_ID';
73
-
74
-        $this->_hidden_columns = array();
75
-    }
76
-
77
-
78
-    /**
79
-     * This simply sets up the row class for the table rows.
80
-     * Allows for easier overriding of child methods for setting up sorting.
81
-     *
82
-     * @param  EE_Transaction $transaction the current item
83
-     * @return string
84
-     * @throws \EE_Error
85
-     */
86
-    protected function _get_row_class($transaction)
87
-    {
88
-        $class = parent::_get_row_class($transaction);
89
-        //add status class
90
-        $class .= ' ee-status-strip txn-status-' . $transaction->status_ID();
91
-        if ($this->_has_checkbox_column) {
92
-            $class .= ' has-checkbox-column';
93
-        }
94
-        return $class;
95
-    }
96
-
97
-
98
-    /**
99
-     * _get_table_filters
100
-     * We use this to assemble and return any filters that are associated with this table that help further refine what
101
-     * get's shown in the table.
102
-     *
103
-     * @abstract
104
-     * @access protected
105
-     * @return array
106
-     */
107
-    protected function _get_table_filters()
108
-    {
109
-        $filters    = array();
110
-        $start_date = isset($this->_req_data['txn-filter-start-date'])
111
-            ? wp_strip_all_tags($this->_req_data['txn-filter-start-date'])
112
-            : date(
113
-                'm/d/Y',
114
-                strtotime('-10 year')
115
-            );
116
-        $end_date   = isset($this->_req_data['txn-filter-end-date'])
117
-            ? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
118
-            : date(
119
-                'm/d/Y',
120
-                current_time('timestamp')
121
-            );
122
-        ob_start();
123
-        ?>
16
+	private $_status;
17
+
18
+
19
+	/**
20
+	 * @param \Transactions_Admin_Page $admin_page
21
+	 */
22
+	public function __construct(\Transactions_Admin_Page $admin_page)
23
+	{
24
+		parent::__construct($admin_page);
25
+		$this->_status = $this->_admin_page->get_transaction_status_array();
26
+	}
27
+
28
+
29
+	/**
30
+	 *_setup_data
31
+	 */
32
+	protected function _setup_data()
33
+	{
34
+		$this->_data           = $this->_admin_page->get_transactions($this->_per_page);
35
+		$status                = ! empty($this->_req_data['status']) ? $this->_req_data['status'] : 'all';
36
+		$this->_all_data_count = $this->_admin_page->get_transactions($this->_per_page, true, $status);
37
+	}
38
+
39
+
40
+	/**
41
+	 *_set_properties
42
+	 */
43
+	protected function _set_properties()
44
+	{
45
+		$this->_wp_list_args = array(
46
+			'singular' => __('transaction', 'event_espresso'),
47
+			'plural'   => __('transactions', 'event_espresso'),
48
+			'ajax'     => true,
49
+			'screen'   => $this->_admin_page->get_current_screen()->id,
50
+		);
51
+		$ID_column_name      = __('ID', 'event_espresso');
52
+		$ID_column_name      .= ' : <span class="show-on-mobile-view-only" style="float:none">';
53
+		$ID_column_name      .= __('Transaction Date', 'event_espresso');
54
+		$ID_column_name      .= '</span> ';
55
+		$this->_columns      = array(
56
+			'TXN_ID'        => $ID_column_name,
57
+			'TXN_timestamp' => __('Transaction Date', 'event_espresso'),
58
+			'TXN_total'     => __('Total', 'event_espresso'),
59
+			'TXN_paid'      => __('Paid', 'event_espresso'),
60
+			'ATT_fname'     => __('Primary Registrant', 'event_espresso'),
61
+			'event_name'    => __('Event', 'event_espresso'),
62
+			'actions'       => __('Actions', 'event_espresso'),
63
+		);
64
+
65
+		$this->_sortable_columns = array(
66
+			'TXN_ID'        => array('TXN_ID' => false),
67
+			'event_name'    => array('event_name' => false),
68
+			'ATT_fname'     => array('ATT_fname' => false),
69
+			'TXN_timestamp' => array('TXN_timestamp' => true) //true means its already sorted
70
+		);
71
+
72
+		$this->_primary_column = 'TXN_ID';
73
+
74
+		$this->_hidden_columns = array();
75
+	}
76
+
77
+
78
+	/**
79
+	 * This simply sets up the row class for the table rows.
80
+	 * Allows for easier overriding of child methods for setting up sorting.
81
+	 *
82
+	 * @param  EE_Transaction $transaction the current item
83
+	 * @return string
84
+	 * @throws \EE_Error
85
+	 */
86
+	protected function _get_row_class($transaction)
87
+	{
88
+		$class = parent::_get_row_class($transaction);
89
+		//add status class
90
+		$class .= ' ee-status-strip txn-status-' . $transaction->status_ID();
91
+		if ($this->_has_checkbox_column) {
92
+			$class .= ' has-checkbox-column';
93
+		}
94
+		return $class;
95
+	}
96
+
97
+
98
+	/**
99
+	 * _get_table_filters
100
+	 * We use this to assemble and return any filters that are associated with this table that help further refine what
101
+	 * get's shown in the table.
102
+	 *
103
+	 * @abstract
104
+	 * @access protected
105
+	 * @return array
106
+	 */
107
+	protected function _get_table_filters()
108
+	{
109
+		$filters    = array();
110
+		$start_date = isset($this->_req_data['txn-filter-start-date'])
111
+			? wp_strip_all_tags($this->_req_data['txn-filter-start-date'])
112
+			: date(
113
+				'm/d/Y',
114
+				strtotime('-10 year')
115
+			);
116
+		$end_date   = isset($this->_req_data['txn-filter-end-date'])
117
+			? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
118
+			: date(
119
+				'm/d/Y',
120
+				current_time('timestamp')
121
+			);
122
+		ob_start();
123
+		?>
124 124
         <label for="txn-filter-start-date">Display Transactions from </label>
125 125
         <input id="txn-filter-start-date" class="datepicker" type="text" value="<?php echo $start_date; ?>"
126 126
                name="txn-filter-start-date" size="15"/>
@@ -128,534 +128,534 @@  discard block
 block discarded – undo
128 128
         <input id="txn-filter-end-date" class="datepicker" type="text" value="<?php echo $end_date; ?>"
129 129
                name="txn-filter-end-date" size="15"/>
130 130
         <?php
131
-        $filters[] = ob_get_contents();
132
-        ob_end_clean();
133
-        return $filters;
134
-    }
135
-
136
-
137
-    /**
138
-     *_add_view_counts
139
-     */
140
-    protected function _add_view_counts()
141
-    {
142
-        $this->_views['all']['count']       = $this->_admin_page->get_transactions($this->_per_page, true, 'all');
143
-        $this->_views['abandoned']['count'] = $this->_admin_page->get_transactions($this->_per_page, true, 'abandoned');
144
-        $this->_views['failed']['count']    = $this->_admin_page->get_transactions($this->_per_page, true, 'failed');
145
-    }
146
-
147
-
148
-    /**
149
-     *    column TXN_ID
150
-     *
151
-     * @param \EE_Transaction $transaction
152
-     * @return string
153
-     * @throws \EE_Error
154
-     */
155
-    public function column_TXN_ID(EE_Transaction $transaction)
156
-    {
157
-        $view_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
158
-            'action' => 'view_transaction',
159
-            'TXN_ID' => $transaction->ID(),
160
-        ), TXN_ADMIN_URL);
161
-        $content      = '<a href="' . $view_lnk_url . '"'
162
-                        . ' title="' . esc_attr__('Go to Transaction Details', 'event_espresso') . '">'
163
-                        . $transaction->ID()
164
-                        . '</a>';
165
-
166
-        //txn timestamp
167
-        $content .= '  <span class="show-on-mobile-view-only">' . $this->_get_txn_timestamp($transaction) . '</span>';
168
-        return $content;
169
-    }
170
-
171
-
172
-    /**
173
-     * @param \EE_Transaction $transaction
174
-     * @return string
175
-     * @throws \EE_Error
176
-     */
177
-    protected function _get_txn_timestamp(EE_Transaction $transaction)
178
-    {
179
-        //txn timestamp
180
-        // is TXN less than 2 hours old ?
181
-        if (($transaction->failed() || $transaction->is_abandoned())
182
-            && (
183
-                (time() - EE_Registry::instance()->SSN->lifespan()) < $transaction->datetime(false, true)
184
-            )
185
-        ) {
186
-            $timestamp = esc_html__('TXN in progress...', 'event_espresso');
187
-        } else {
188
-            $timestamp = $transaction->get_i18n_datetime('TXN_timestamp');
189
-        }
190
-        return $timestamp;
191
-    }
192
-
193
-
194
-    /**
195
-     *    column_cb
196
-     *
197
-     * @param \EE_Transaction $transaction
198
-     * @return string
199
-     * @throws \EE_Error
200
-     */
201
-    public function column_cb($transaction)
202
-    {
203
-        return sprintf(
204
-            '<input type="checkbox" name="%1$s[]" value="%2$s" />',
205
-            $this->_wp_list_args['singular'],
206
-            $transaction->ID()
207
-        );
208
-    }
209
-
210
-
211
-    /**
212
-     *    column_TXN_timestamp
213
-     *
214
-     * @param \EE_Transaction $transaction
215
-     * @return string
216
-     * @throws \EE_Error
217
-     */
218
-    public function column_TXN_timestamp(EE_Transaction $transaction)
219
-    {
220
-        $view_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
221
-            'action' => 'view_transaction',
222
-            'TXN_ID' => $transaction->ID(),
223
-        ), TXN_ADMIN_URL);
224
-        $txn_date     = '<a href="' . $view_lnk_url . '"'
225
-                        . ' title="'
226
-                        . esc_attr__('View Transaction Details for TXN #', 'event_espresso') . $transaction->ID() . '">'
227
-                        . $this->_get_txn_timestamp($transaction)
228
-                        . '</a>';
229
-        //status
230
-        $txn_date .= '<br><span class="ee-status-text-small">'
231
-                     . EEH_Template::pretty_status(
232
-                         $transaction->status_ID(),
233
-                         false,
234
-                         'sentence'
235
-                     )
236
-                     . '</span>';
237
-        return $txn_date;
238
-    }
239
-
240
-
241
-    /**
242
-     *    column_TXN_total
243
-     *
244
-     * @param \EE_Transaction $transaction
245
-     * @return string
246
-     * @throws \EE_Error
247
-     */
248
-    public function column_TXN_total(EE_Transaction $transaction)
249
-    {
250
-        if ($transaction->get('TXN_total') > 0) {
251
-            return '<span class="txn-pad-rght">'
252
-                   . apply_filters(
253
-                       'FHEE__EE_Admin_Transactions_List_Table__column_TXN_total__TXN_total',
254
-                       $transaction->get_pretty('TXN_total'),
255
-                       $transaction
256
-                   )
257
-                   . '</span>';
258
-        } else {
259
-            return '<span class="txn-overview-free-event-spn">' . esc_html__('free', 'event_espresso') . '</span>';
260
-        }
261
-    }
262
-
263
-
264
-    /**
265
-     *    column_TXN_paid
266
-     *
267
-     * @param \EE_Transaction $transaction
268
-     * @return mixed|string
269
-     * @throws \EE_Error
270
-     */
271
-    public function column_TXN_paid(EE_Transaction $transaction)
272
-    {
273
-        $transaction_total = $transaction->get('TXN_total');
274
-        $transaction_paid  = $transaction->get('TXN_paid');
275
-
276
-        if (\EEH_Money::compare_floats($transaction_total, 0, '>')) {
277
-            // monies owing
278
-            $span_class = 'txn-overview-part-payment-spn';
279
-            if (\EEH_Money::compare_floats($transaction_paid, $transaction_total, '>=')) {
280
-                // paid in full
281
-                $span_class = 'txn-overview-full-payment-spn';
282
-            } elseif (\EEH_Money::compare_floats($transaction_paid, 0, '==')) {
283
-                // no payments made
284
-                $span_class = 'txn-overview-no-payment-spn';
285
-            }
286
-        } else {
287
-            $span_class       = 'txn-overview-free-event-spn';
288
-            $transaction_paid = 0;
289
-        }
290
-
291
-        $payment_method      = $transaction->payment_method();
292
-        $payment_method_name = $payment_method instanceof EE_Payment_Method
293
-            ? $payment_method->admin_name()
294
-            : esc_html__('Unknown', 'event_espresso');
295
-        $transaction_paid_content = $transaction_paid !== 0 ? $transaction->get_pretty('TXN_paid') : $transaction_paid;
296
-
297
-        $content = '<span class="' . $span_class . ' txn-pad-rght">'
298
-                   . $transaction_paid_content
299
-                   . '</span>';
300
-        if ($transaction_paid > 0) {
301
-            $content .= '<br><span class="ee-status-text-small">'
302
-                        . sprintf(
303
-                            esc_html__('...via %s', 'event_espresso'),
304
-                            $payment_method_name
305
-                        )
306
-                        . '</span>';
307
-        }
308
-        return $content;
309
-    }
310
-
311
-
312
-    /**
313
-     *    column_ATT_fname
314
-     *
315
-     * @param \EE_Transaction $transaction
316
-     * @return string
317
-     * @throws \EE_Error
318
-     */
319
-    public function column_ATT_fname(EE_Transaction $transaction)
320
-    {
321
-        $primary_reg = $transaction->primary_registration();
322
-        $attendee    = $primary_reg->get_first_related('Attendee');
323
-        if ($attendee instanceof EE_Attendee) {
324
-            $edit_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
325
-                'action'  => 'view_registration',
326
-                '_REG_ID' => $primary_reg->ID(),
327
-            ), REG_ADMIN_URL);
328
-            $content      = EE_Registry::instance()->CAP->current_user_can(
329
-                'ee_read_registration',
330
-                'espresso_registrations_view_registration',
331
-                $primary_reg->ID()
332
-            )
333
-                ? '<a href="' . $edit_lnk_url . '"'
334
-                    . ' title="' . esc_attr__('View Registration Details', 'event_espresso') . '">'
335
-                    . $attendee->full_name()
336
-                    . '</a>'
337
-                : $attendee->full_name();
338
-            $content      .= '<br>' . $attendee->email();
339
-            return $content;
340
-        }
341
-        return $transaction->failed() || $transaction->is_abandoned()
342
-            ? esc_html__('no contact record.', 'event_espresso')
343
-            : esc_html__(
344
-                'No contact record, because the transaction was abandoned or the registration process failed.',
345
-                'event_espresso'
346
-            );
347
-    }
348
-
349
-
350
-    /**
351
-     *    column_ATT_email
352
-     *
353
-     * @param \EE_Transaction $transaction
354
-     * @return string
355
-     * @throws \EE_Error
356
-     */
357
-    public function column_ATT_email(EE_Transaction $transaction)
358
-    {
359
-        $attendee = $transaction->primary_registration()->get_first_related('Attendee');
360
-        if (! empty($attendee)) {
361
-            return '<a href="mailto:' . $attendee->get('ATT_email') . '">'
362
-                   . $attendee->get('ATT_email')
363
-                   . '</a>';
364
-        } else {
365
-            return $transaction->failed() || $transaction->is_abandoned()
366
-                ? esc_html__('no contact record.', 'event_espresso')
367
-                : esc_html__(
368
-                    'No contact record, because the transaction was abandoned or the registration process failed.',
369
-                    'event_espresso'
370
-                );
371
-        }
372
-    }
373
-
374
-
375
-    /**
376
-     *    column_event_name
377
-     *
378
-     * @param \EE_Transaction $transaction
379
-     * @return string
380
-     * @throws \EE_Error
381
-     */
382
-    public function column_event_name(EE_Transaction $transaction)
383
-    {
384
-        $actions = array();
385
-        $event   = $transaction->primary_registration()->get_first_related('Event');
386
-        if (! empty($event)) {
387
-            $edit_event_url = EE_Admin_Page::add_query_args_and_nonce(
388
-                array('action' => 'edit', 'post' => $event->ID()),
389
-                EVENTS_ADMIN_URL
390
-            );
391
-            $event_name     = $event->get('EVT_name');
392
-
393
-            //filter this view by transactions for this event
394
-            $txn_by_event_lnk = EE_Admin_Page::add_query_args_and_nonce(array(
395
-                'action' => 'default',
396
-                'EVT_ID' => $event->ID(),
397
-            ));
398
-            if (EE_Registry::instance()->CAP->current_user_can(
399
-                'ee_edit_event',
400
-                'espresso_events_edit',
401
-                $event->ID()
402
-            )) {
403
-                $actions['filter_by_event'] = '<a href="' . $txn_by_event_lnk . '"'
404
-                        . ' title="' . esc_attr__('Filter transactions by this event', 'event_espresso') . '">'
405
-                        . esc_html__('View Transactions for this event', 'event_espresso')
406
-                        . '</a>';
407
-            }
408
-
409
-            return sprintf(
410
-                '%1$s %2$s',
411
-                EE_Registry::instance()->CAP->current_user_can(
412
-                    'ee_edit_event',
413
-                    'espresso_events_edit',
414
-                    $event->ID()
415
-                )
416
-                    ? '<a href="' . $edit_event_url . '"'
417
-                        . ' title="'
418
-                        . sprintf(
419
-                            esc_attr__('Edit Event: %s', 'event_espresso'),
420
-                            $event->get('EVT_name')
421
-                        )
422
-                        . '">'
423
-                        . wp_trim_words(
424
-                            $event_name,
425
-                            30,
426
-                            '...'
427
-                        )
428
-                        . '</a>'
429
-                        : wp_trim_words($event_name, 30, '...'),
430
-                $this->row_actions($actions)
431
-            );
432
-        } else {
433
-            return esc_html__(
434
-                'The event associated with this transaction via the primary registration cannot be retrieved.',
435
-                'event_espresso'
436
-            );
437
-        }
438
-    }
439
-
440
-
441
-    /**
442
-     *    column_actions
443
-     *
444
-     * @param \EE_Transaction $transaction
445
-     * @return string
446
-     * @throws \EE_Error
447
-     */
448
-    public function column_actions(EE_Transaction $transaction)
449
-    {
450
-        return $this->_action_string(
451
-            $this->get_transaction_details_link($transaction)
452
-            . $this->get_invoice_link($transaction)
453
-            . $this->get_receipt_link($transaction)
454
-            . $this->get_primary_registration_details_link($transaction)
455
-            . $this->get_send_payment_reminder_trigger_link($transaction)
456
-            . $this->get_payment_overview_link($transaction)
457
-            . $this->get_related_messages_link($transaction),
458
-            $transaction,
459
-            'ul',
460
-            'txn-overview-actions-ul'
461
-        );
462
-    }
463
-
464
-
465
-    /**
466
-     * Get the transaction details link.
467
-     * @param EE_Transaction $transaction
468
-     * @return string
469
-     * @throws EE_Error
470
-     */
471
-    protected function get_transaction_details_link(EE_Transaction $transaction)
472
-    {
473
-        $url          = EE_Admin_Page::add_query_args_and_nonce(array(
474
-            'action' => 'view_transaction',
475
-            'TXN_ID' => $transaction->ID(),
476
-        ), TXN_ADMIN_URL);
477
-        return '
131
+		$filters[] = ob_get_contents();
132
+		ob_end_clean();
133
+		return $filters;
134
+	}
135
+
136
+
137
+	/**
138
+	 *_add_view_counts
139
+	 */
140
+	protected function _add_view_counts()
141
+	{
142
+		$this->_views['all']['count']       = $this->_admin_page->get_transactions($this->_per_page, true, 'all');
143
+		$this->_views['abandoned']['count'] = $this->_admin_page->get_transactions($this->_per_page, true, 'abandoned');
144
+		$this->_views['failed']['count']    = $this->_admin_page->get_transactions($this->_per_page, true, 'failed');
145
+	}
146
+
147
+
148
+	/**
149
+	 *    column TXN_ID
150
+	 *
151
+	 * @param \EE_Transaction $transaction
152
+	 * @return string
153
+	 * @throws \EE_Error
154
+	 */
155
+	public function column_TXN_ID(EE_Transaction $transaction)
156
+	{
157
+		$view_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
158
+			'action' => 'view_transaction',
159
+			'TXN_ID' => $transaction->ID(),
160
+		), TXN_ADMIN_URL);
161
+		$content      = '<a href="' . $view_lnk_url . '"'
162
+						. ' title="' . esc_attr__('Go to Transaction Details', 'event_espresso') . '">'
163
+						. $transaction->ID()
164
+						. '</a>';
165
+
166
+		//txn timestamp
167
+		$content .= '  <span class="show-on-mobile-view-only">' . $this->_get_txn_timestamp($transaction) . '</span>';
168
+		return $content;
169
+	}
170
+
171
+
172
+	/**
173
+	 * @param \EE_Transaction $transaction
174
+	 * @return string
175
+	 * @throws \EE_Error
176
+	 */
177
+	protected function _get_txn_timestamp(EE_Transaction $transaction)
178
+	{
179
+		//txn timestamp
180
+		// is TXN less than 2 hours old ?
181
+		if (($transaction->failed() || $transaction->is_abandoned())
182
+			&& (
183
+				(time() - EE_Registry::instance()->SSN->lifespan()) < $transaction->datetime(false, true)
184
+			)
185
+		) {
186
+			$timestamp = esc_html__('TXN in progress...', 'event_espresso');
187
+		} else {
188
+			$timestamp = $transaction->get_i18n_datetime('TXN_timestamp');
189
+		}
190
+		return $timestamp;
191
+	}
192
+
193
+
194
+	/**
195
+	 *    column_cb
196
+	 *
197
+	 * @param \EE_Transaction $transaction
198
+	 * @return string
199
+	 * @throws \EE_Error
200
+	 */
201
+	public function column_cb($transaction)
202
+	{
203
+		return sprintf(
204
+			'<input type="checkbox" name="%1$s[]" value="%2$s" />',
205
+			$this->_wp_list_args['singular'],
206
+			$transaction->ID()
207
+		);
208
+	}
209
+
210
+
211
+	/**
212
+	 *    column_TXN_timestamp
213
+	 *
214
+	 * @param \EE_Transaction $transaction
215
+	 * @return string
216
+	 * @throws \EE_Error
217
+	 */
218
+	public function column_TXN_timestamp(EE_Transaction $transaction)
219
+	{
220
+		$view_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
221
+			'action' => 'view_transaction',
222
+			'TXN_ID' => $transaction->ID(),
223
+		), TXN_ADMIN_URL);
224
+		$txn_date     = '<a href="' . $view_lnk_url . '"'
225
+						. ' title="'
226
+						. esc_attr__('View Transaction Details for TXN #', 'event_espresso') . $transaction->ID() . '">'
227
+						. $this->_get_txn_timestamp($transaction)
228
+						. '</a>';
229
+		//status
230
+		$txn_date .= '<br><span class="ee-status-text-small">'
231
+					 . EEH_Template::pretty_status(
232
+						 $transaction->status_ID(),
233
+						 false,
234
+						 'sentence'
235
+					 )
236
+					 . '</span>';
237
+		return $txn_date;
238
+	}
239
+
240
+
241
+	/**
242
+	 *    column_TXN_total
243
+	 *
244
+	 * @param \EE_Transaction $transaction
245
+	 * @return string
246
+	 * @throws \EE_Error
247
+	 */
248
+	public function column_TXN_total(EE_Transaction $transaction)
249
+	{
250
+		if ($transaction->get('TXN_total') > 0) {
251
+			return '<span class="txn-pad-rght">'
252
+				   . apply_filters(
253
+					   'FHEE__EE_Admin_Transactions_List_Table__column_TXN_total__TXN_total',
254
+					   $transaction->get_pretty('TXN_total'),
255
+					   $transaction
256
+				   )
257
+				   . '</span>';
258
+		} else {
259
+			return '<span class="txn-overview-free-event-spn">' . esc_html__('free', 'event_espresso') . '</span>';
260
+		}
261
+	}
262
+
263
+
264
+	/**
265
+	 *    column_TXN_paid
266
+	 *
267
+	 * @param \EE_Transaction $transaction
268
+	 * @return mixed|string
269
+	 * @throws \EE_Error
270
+	 */
271
+	public function column_TXN_paid(EE_Transaction $transaction)
272
+	{
273
+		$transaction_total = $transaction->get('TXN_total');
274
+		$transaction_paid  = $transaction->get('TXN_paid');
275
+
276
+		if (\EEH_Money::compare_floats($transaction_total, 0, '>')) {
277
+			// monies owing
278
+			$span_class = 'txn-overview-part-payment-spn';
279
+			if (\EEH_Money::compare_floats($transaction_paid, $transaction_total, '>=')) {
280
+				// paid in full
281
+				$span_class = 'txn-overview-full-payment-spn';
282
+			} elseif (\EEH_Money::compare_floats($transaction_paid, 0, '==')) {
283
+				// no payments made
284
+				$span_class = 'txn-overview-no-payment-spn';
285
+			}
286
+		} else {
287
+			$span_class       = 'txn-overview-free-event-spn';
288
+			$transaction_paid = 0;
289
+		}
290
+
291
+		$payment_method      = $transaction->payment_method();
292
+		$payment_method_name = $payment_method instanceof EE_Payment_Method
293
+			? $payment_method->admin_name()
294
+			: esc_html__('Unknown', 'event_espresso');
295
+		$transaction_paid_content = $transaction_paid !== 0 ? $transaction->get_pretty('TXN_paid') : $transaction_paid;
296
+
297
+		$content = '<span class="' . $span_class . ' txn-pad-rght">'
298
+				   . $transaction_paid_content
299
+				   . '</span>';
300
+		if ($transaction_paid > 0) {
301
+			$content .= '<br><span class="ee-status-text-small">'
302
+						. sprintf(
303
+							esc_html__('...via %s', 'event_espresso'),
304
+							$payment_method_name
305
+						)
306
+						. '</span>';
307
+		}
308
+		return $content;
309
+	}
310
+
311
+
312
+	/**
313
+	 *    column_ATT_fname
314
+	 *
315
+	 * @param \EE_Transaction $transaction
316
+	 * @return string
317
+	 * @throws \EE_Error
318
+	 */
319
+	public function column_ATT_fname(EE_Transaction $transaction)
320
+	{
321
+		$primary_reg = $transaction->primary_registration();
322
+		$attendee    = $primary_reg->get_first_related('Attendee');
323
+		if ($attendee instanceof EE_Attendee) {
324
+			$edit_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
325
+				'action'  => 'view_registration',
326
+				'_REG_ID' => $primary_reg->ID(),
327
+			), REG_ADMIN_URL);
328
+			$content      = EE_Registry::instance()->CAP->current_user_can(
329
+				'ee_read_registration',
330
+				'espresso_registrations_view_registration',
331
+				$primary_reg->ID()
332
+			)
333
+				? '<a href="' . $edit_lnk_url . '"'
334
+					. ' title="' . esc_attr__('View Registration Details', 'event_espresso') . '">'
335
+					. $attendee->full_name()
336
+					. '</a>'
337
+				: $attendee->full_name();
338
+			$content      .= '<br>' . $attendee->email();
339
+			return $content;
340
+		}
341
+		return $transaction->failed() || $transaction->is_abandoned()
342
+			? esc_html__('no contact record.', 'event_espresso')
343
+			: esc_html__(
344
+				'No contact record, because the transaction was abandoned or the registration process failed.',
345
+				'event_espresso'
346
+			);
347
+	}
348
+
349
+
350
+	/**
351
+	 *    column_ATT_email
352
+	 *
353
+	 * @param \EE_Transaction $transaction
354
+	 * @return string
355
+	 * @throws \EE_Error
356
+	 */
357
+	public function column_ATT_email(EE_Transaction $transaction)
358
+	{
359
+		$attendee = $transaction->primary_registration()->get_first_related('Attendee');
360
+		if (! empty($attendee)) {
361
+			return '<a href="mailto:' . $attendee->get('ATT_email') . '">'
362
+				   . $attendee->get('ATT_email')
363
+				   . '</a>';
364
+		} else {
365
+			return $transaction->failed() || $transaction->is_abandoned()
366
+				? esc_html__('no contact record.', 'event_espresso')
367
+				: esc_html__(
368
+					'No contact record, because the transaction was abandoned or the registration process failed.',
369
+					'event_espresso'
370
+				);
371
+		}
372
+	}
373
+
374
+
375
+	/**
376
+	 *    column_event_name
377
+	 *
378
+	 * @param \EE_Transaction $transaction
379
+	 * @return string
380
+	 * @throws \EE_Error
381
+	 */
382
+	public function column_event_name(EE_Transaction $transaction)
383
+	{
384
+		$actions = array();
385
+		$event   = $transaction->primary_registration()->get_first_related('Event');
386
+		if (! empty($event)) {
387
+			$edit_event_url = EE_Admin_Page::add_query_args_and_nonce(
388
+				array('action' => 'edit', 'post' => $event->ID()),
389
+				EVENTS_ADMIN_URL
390
+			);
391
+			$event_name     = $event->get('EVT_name');
392
+
393
+			//filter this view by transactions for this event
394
+			$txn_by_event_lnk = EE_Admin_Page::add_query_args_and_nonce(array(
395
+				'action' => 'default',
396
+				'EVT_ID' => $event->ID(),
397
+			));
398
+			if (EE_Registry::instance()->CAP->current_user_can(
399
+				'ee_edit_event',
400
+				'espresso_events_edit',
401
+				$event->ID()
402
+			)) {
403
+				$actions['filter_by_event'] = '<a href="' . $txn_by_event_lnk . '"'
404
+						. ' title="' . esc_attr__('Filter transactions by this event', 'event_espresso') . '">'
405
+						. esc_html__('View Transactions for this event', 'event_espresso')
406
+						. '</a>';
407
+			}
408
+
409
+			return sprintf(
410
+				'%1$s %2$s',
411
+				EE_Registry::instance()->CAP->current_user_can(
412
+					'ee_edit_event',
413
+					'espresso_events_edit',
414
+					$event->ID()
415
+				)
416
+					? '<a href="' . $edit_event_url . '"'
417
+						. ' title="'
418
+						. sprintf(
419
+							esc_attr__('Edit Event: %s', 'event_espresso'),
420
+							$event->get('EVT_name')
421
+						)
422
+						. '">'
423
+						. wp_trim_words(
424
+							$event_name,
425
+							30,
426
+							'...'
427
+						)
428
+						. '</a>'
429
+						: wp_trim_words($event_name, 30, '...'),
430
+				$this->row_actions($actions)
431
+			);
432
+		} else {
433
+			return esc_html__(
434
+				'The event associated with this transaction via the primary registration cannot be retrieved.',
435
+				'event_espresso'
436
+			);
437
+		}
438
+	}
439
+
440
+
441
+	/**
442
+	 *    column_actions
443
+	 *
444
+	 * @param \EE_Transaction $transaction
445
+	 * @return string
446
+	 * @throws \EE_Error
447
+	 */
448
+	public function column_actions(EE_Transaction $transaction)
449
+	{
450
+		return $this->_action_string(
451
+			$this->get_transaction_details_link($transaction)
452
+			. $this->get_invoice_link($transaction)
453
+			. $this->get_receipt_link($transaction)
454
+			. $this->get_primary_registration_details_link($transaction)
455
+			. $this->get_send_payment_reminder_trigger_link($transaction)
456
+			. $this->get_payment_overview_link($transaction)
457
+			. $this->get_related_messages_link($transaction),
458
+			$transaction,
459
+			'ul',
460
+			'txn-overview-actions-ul'
461
+		);
462
+	}
463
+
464
+
465
+	/**
466
+	 * Get the transaction details link.
467
+	 * @param EE_Transaction $transaction
468
+	 * @return string
469
+	 * @throws EE_Error
470
+	 */
471
+	protected function get_transaction_details_link(EE_Transaction $transaction)
472
+	{
473
+		$url          = EE_Admin_Page::add_query_args_and_nonce(array(
474
+			'action' => 'view_transaction',
475
+			'TXN_ID' => $transaction->ID(),
476
+		), TXN_ADMIN_URL);
477
+		return '
478 478
 			<li>
479 479
 				<a href="' . $url . '"'
480
-                    . ' title="' . esc_attr__('View Transaction Details', 'event_espresso') . '" class="tiny-text">
480
+					. ' title="' . esc_attr__('View Transaction Details', 'event_espresso') . '" class="tiny-text">
481 481
 					<span class="dashicons dashicons-cart"></span>
482 482
 				</a>
483 483
 			</li>';
484
-    }
485
-
486
-
487
-    /**
488
-     * Get the invoice link for the given registration.
489
-     * @param EE_Transaction $transaction
490
-     * @return string
491
-     * @throws EE_Error
492
-     */
493
-    protected function get_invoice_link(EE_Transaction $transaction)
494
-    {
495
-        $registration = $transaction->primary_registration();
496
-        if ($registration instanceof EE_Registration) {
497
-            $url = $registration->invoice_url();
498
-            //only show invoice link if message type is active.
499
-            if ($registration->attendee() instanceof EE_Attendee
500
-                && EEH_MSG_Template::is_mt_active('invoice')
501
-            ) {
502
-                return '
484
+	}
485
+
486
+
487
+	/**
488
+	 * Get the invoice link for the given registration.
489
+	 * @param EE_Transaction $transaction
490
+	 * @return string
491
+	 * @throws EE_Error
492
+	 */
493
+	protected function get_invoice_link(EE_Transaction $transaction)
494
+	{
495
+		$registration = $transaction->primary_registration();
496
+		if ($registration instanceof EE_Registration) {
497
+			$url = $registration->invoice_url();
498
+			//only show invoice link if message type is active.
499
+			if ($registration->attendee() instanceof EE_Attendee
500
+				&& EEH_MSG_Template::is_mt_active('invoice')
501
+			) {
502
+				return '
503 503
                 <li>
504 504
                     <a title="' . esc_attr__('View Transaction Invoice', 'event_espresso') . '"'
505
-                       . ' target="_blank" href="' . $url . '" class="tiny-text">
505
+					   . ' target="_blank" href="' . $url . '" class="tiny-text">
506 506
                         <span class="dashicons dashicons-media-spreadsheet ee-icon-size-18"></span>
507 507
                     </a>
508 508
                 </li>';
509
-            }
510
-        }
511
-        return '';
512
-    }
513
-
514
-
515
-    /**
516
-     * Get the receipt link for the transaction.
517
-     * @param EE_Transaction $transaction
518
-     * @return string
519
-     * @throws EE_Error
520
-     */
521
-    protected function get_receipt_link(EE_Transaction $transaction)
522
-    {
523
-        $registration = $transaction->primary_registration();
524
-        if ($registration instanceof EE_Registration) {
525
-            $url = $registration->receipt_url();
526
-            //only show receipt link if message type is active.
527
-            if ($registration->attendee() instanceof EE_Attendee
528
-                && EEH_MSG_Template::is_mt_active('receipt')) {
529
-                return '
509
+			}
510
+		}
511
+		return '';
512
+	}
513
+
514
+
515
+	/**
516
+	 * Get the receipt link for the transaction.
517
+	 * @param EE_Transaction $transaction
518
+	 * @return string
519
+	 * @throws EE_Error
520
+	 */
521
+	protected function get_receipt_link(EE_Transaction $transaction)
522
+	{
523
+		$registration = $transaction->primary_registration();
524
+		if ($registration instanceof EE_Registration) {
525
+			$url = $registration->receipt_url();
526
+			//only show receipt link if message type is active.
527
+			if ($registration->attendee() instanceof EE_Attendee
528
+				&& EEH_MSG_Template::is_mt_active('receipt')) {
529
+				return '
530 530
 			<li>
531 531
 				<a title="' . esc_attr__('View Transaction Receipt', 'event_espresso') . '"'
532
-                                  . ' target="_blank" href="' . $url . '" class="tiny-text">
532
+								  . ' target="_blank" href="' . $url . '" class="tiny-text">
533 533
 					<span class="dashicons dashicons-media-default ee-icon-size-18"></span>
534 534
 				</a>
535 535
 			</li>';
536
-            }
537
-        }
538
-        return '';
539
-    }
540
-
541
-
542
-    /**
543
-     * Get the link to view the details for the primary registration.
544
-     * @param EE_Transaction $transaction
545
-     * @return string
546
-     * @throws EE_Error
547
-     */
548
-    protected function get_primary_registration_details_link(EE_Transaction $transaction)
549
-    {
550
-        $registration = $transaction->primary_registration();
551
-        if ($registration instanceof EE_Registration) {
552
-            $url      = EE_Admin_Page::add_query_args_and_nonce(array(
553
-                'action'  => 'view_registration',
554
-                '_REG_ID' => $registration->ID(),
555
-            ), REG_ADMIN_URL);
556
-            return EE_Registry::instance()->CAP->current_user_can(
557
-                'ee_read_registration',
558
-                'espresso_registrations_view_registration',
559
-                $registration->ID()
560
-            )
561
-                ? '
536
+			}
537
+		}
538
+		return '';
539
+	}
540
+
541
+
542
+	/**
543
+	 * Get the link to view the details for the primary registration.
544
+	 * @param EE_Transaction $transaction
545
+	 * @return string
546
+	 * @throws EE_Error
547
+	 */
548
+	protected function get_primary_registration_details_link(EE_Transaction $transaction)
549
+	{
550
+		$registration = $transaction->primary_registration();
551
+		if ($registration instanceof EE_Registration) {
552
+			$url      = EE_Admin_Page::add_query_args_and_nonce(array(
553
+				'action'  => 'view_registration',
554
+				'_REG_ID' => $registration->ID(),
555
+			), REG_ADMIN_URL);
556
+			return EE_Registry::instance()->CAP->current_user_can(
557
+				'ee_read_registration',
558
+				'espresso_registrations_view_registration',
559
+				$registration->ID()
560
+			)
561
+				? '
562 562
 				<li>
563 563
 					<a href="' . $url . '"'
564
-                  . ' title="' . esc_attr__('View Registration Details', 'event_espresso') . '" class="tiny-text">
564
+				  . ' title="' . esc_attr__('View Registration Details', 'event_espresso') . '" class="tiny-text">
565 565
 						<span class="dashicons dashicons-clipboard"></span>
566 566
 					</a>
567 567
 				</li>'
568
-                : '';
569
-        }
570
-        return '';
571
-    }
572
-
573
-
574
-    /**
575
-     * Get send payment reminder trigger link
576
-     * @param EE_Transaction $transaction
577
-     * @return string
578
-     * @throws EE_Error
579
-     */
580
-    protected function get_send_payment_reminder_trigger_link(EE_Transaction $transaction)
581
-    {
582
-        $registration = $transaction->primary_registration();
583
-        if ($registration instanceof EE_Registration
584
-            && $registration->attendee() instanceof EE_Attendee
585
-            && EEH_MSG_Template::is_mt_active('payment_reminder')
586
-            && ! in_array(
587
-                $transaction->status_ID(),
588
-                array(EEM_Transaction::complete_status_code, EEM_Transaction::overpaid_status_code),
589
-                true
590
-            )
591
-            && EE_Registry::instance()->CAP->current_user_can(
592
-                'ee_send_message',
593
-                'espresso_transactions_send_payment_reminder'
594
-            )
595
-        ) {
596
-            $url = EE_Admin_Page::add_query_args_and_nonce(array(
597
-                'action' => 'send_payment_reminder',
598
-                'TXN_ID' => $transaction->ID(),
599
-            ), TXN_ADMIN_URL);
600
-            return  '
568
+				: '';
569
+		}
570
+		return '';
571
+	}
572
+
573
+
574
+	/**
575
+	 * Get send payment reminder trigger link
576
+	 * @param EE_Transaction $transaction
577
+	 * @return string
578
+	 * @throws EE_Error
579
+	 */
580
+	protected function get_send_payment_reminder_trigger_link(EE_Transaction $transaction)
581
+	{
582
+		$registration = $transaction->primary_registration();
583
+		if ($registration instanceof EE_Registration
584
+			&& $registration->attendee() instanceof EE_Attendee
585
+			&& EEH_MSG_Template::is_mt_active('payment_reminder')
586
+			&& ! in_array(
587
+				$transaction->status_ID(),
588
+				array(EEM_Transaction::complete_status_code, EEM_Transaction::overpaid_status_code),
589
+				true
590
+			)
591
+			&& EE_Registry::instance()->CAP->current_user_can(
592
+				'ee_send_message',
593
+				'espresso_transactions_send_payment_reminder'
594
+			)
595
+		) {
596
+			$url = EE_Admin_Page::add_query_args_and_nonce(array(
597
+				'action' => 'send_payment_reminder',
598
+				'TXN_ID' => $transaction->ID(),
599
+			), TXN_ADMIN_URL);
600
+			return  '
601 601
             <li>
602 602
                 <a href="' . $url . '"'
603
-                  . ' title="' . esc_attr__('Send Payment Reminder', 'event_espresso') . '" class="tiny-text">
603
+				  . ' title="' . esc_attr__('Send Payment Reminder', 'event_espresso') . '" class="tiny-text">
604 604
                     <span class="dashicons dashicons-email-alt"></span>
605 605
                 </a>
606 606
             </li>';
607
-        }
608
-        return '';
609
-    }
610
-
611
-
612
-
613
-    /**
614
-     * Get link to filtered view in the message activity list table of messages for this transaction.
615
-     * @param EE_Transaction $transaction
616
-     * @return string
617
-     * @throws EE_Error
618
-     */
619
-    protected function get_related_messages_link(EE_Transaction $transaction)
620
-    {
621
-        $url = EEH_MSG_Template::get_message_action_link(
622
-            'see_notifications_for',
623
-            null,
624
-            array('TXN_ID' => $transaction->ID())
625
-        );
626
-        return EE_Registry::instance()->CAP->current_user_can(
627
-            'ee_read_global_messages',
628
-            'view_filtered_messages'
629
-        )
630
-            ? '<li>' . $url . '</li>'
631
-            : '';
632
-    }
633
-
634
-
635
-    /**
636
-     * Return the link to make a payment on the frontend
637
-     * @param EE_Transaction $transaction
638
-     * @return string
639
-     * @throws EE_Error
640
-     */
641
-    protected function get_payment_overview_link(EE_Transaction $transaction)
642
-    {
643
-        $registration = $transaction->primary_registration();
644
-        if ($registration instanceof EE_Registration
645
-            && $transaction->status_ID() !== EEM_Transaction::complete_status_code
646
-            && $registration->owes_monies_and_can_pay()
647
-        ) {
648
-            return '
607
+		}
608
+		return '';
609
+	}
610
+
611
+
612
+
613
+	/**
614
+	 * Get link to filtered view in the message activity list table of messages for this transaction.
615
+	 * @param EE_Transaction $transaction
616
+	 * @return string
617
+	 * @throws EE_Error
618
+	 */
619
+	protected function get_related_messages_link(EE_Transaction $transaction)
620
+	{
621
+		$url = EEH_MSG_Template::get_message_action_link(
622
+			'see_notifications_for',
623
+			null,
624
+			array('TXN_ID' => $transaction->ID())
625
+		);
626
+		return EE_Registry::instance()->CAP->current_user_can(
627
+			'ee_read_global_messages',
628
+			'view_filtered_messages'
629
+		)
630
+			? '<li>' . $url . '</li>'
631
+			: '';
632
+	}
633
+
634
+
635
+	/**
636
+	 * Return the link to make a payment on the frontend
637
+	 * @param EE_Transaction $transaction
638
+	 * @return string
639
+	 * @throws EE_Error
640
+	 */
641
+	protected function get_payment_overview_link(EE_Transaction $transaction)
642
+	{
643
+		$registration = $transaction->primary_registration();
644
+		if ($registration instanceof EE_Registration
645
+			&& $transaction->status_ID() !== EEM_Transaction::complete_status_code
646
+			&& $registration->owes_monies_and_can_pay()
647
+		) {
648
+			return '
649 649
             <li>
650 650
                 <a title="' . esc_attr__('Make Payment from the Frontend.', 'event_espresso') . '"'
651
-                    . ' target="_blank" href="' . $registration->payment_overview_url(true) . '"'
652
-                    . ' class="tiny-text">
651
+					. ' target="_blank" href="' . $registration->payment_overview_url(true) . '"'
652
+					. ' class="tiny-text">
653 653
                     <span class="dashicons dashicons-money ee-icon-size-18"></span>
654 654
                 </a>
655 655
             </li>
656 656
             ';
657 657
 
658
-        }
659
-        return '';
660
-    }
658
+		}
659
+		return '';
660
+	}
661 661
 }
Please login to merge, or discard this patch.
Spacing   +36 added lines, -36 removed lines patch added patch discarded remove patch
@@ -48,11 +48,11 @@  discard block
 block discarded – undo
48 48
             'ajax'     => true,
49 49
             'screen'   => $this->_admin_page->get_current_screen()->id,
50 50
         );
51
-        $ID_column_name      = __('ID', 'event_espresso');
51
+        $ID_column_name = __('ID', 'event_espresso');
52 52
         $ID_column_name      .= ' : <span class="show-on-mobile-view-only" style="float:none">';
53 53
         $ID_column_name      .= __('Transaction Date', 'event_espresso');
54 54
         $ID_column_name      .= '</span> ';
55
-        $this->_columns      = array(
55
+        $this->_columns = array(
56 56
             'TXN_ID'        => $ID_column_name,
57 57
             'TXN_timestamp' => __('Transaction Date', 'event_espresso'),
58 58
             'TXN_total'     => __('Total', 'event_espresso'),
@@ -87,7 +87,7 @@  discard block
 block discarded – undo
87 87
     {
88 88
         $class = parent::_get_row_class($transaction);
89 89
         //add status class
90
-        $class .= ' ee-status-strip txn-status-' . $transaction->status_ID();
90
+        $class .= ' ee-status-strip txn-status-'.$transaction->status_ID();
91 91
         if ($this->_has_checkbox_column) {
92 92
             $class .= ' has-checkbox-column';
93 93
         }
@@ -113,7 +113,7 @@  discard block
 block discarded – undo
113 113
                 'm/d/Y',
114 114
                 strtotime('-10 year')
115 115
             );
116
-        $end_date   = isset($this->_req_data['txn-filter-end-date'])
116
+        $end_date = isset($this->_req_data['txn-filter-end-date'])
117 117
             ? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
118 118
             : date(
119 119
                 'm/d/Y',
@@ -158,13 +158,13 @@  discard block
 block discarded – undo
158 158
             'action' => 'view_transaction',
159 159
             'TXN_ID' => $transaction->ID(),
160 160
         ), TXN_ADMIN_URL);
161
-        $content      = '<a href="' . $view_lnk_url . '"'
162
-                        . ' title="' . esc_attr__('Go to Transaction Details', 'event_espresso') . '">'
161
+        $content = '<a href="'.$view_lnk_url.'"'
162
+                        . ' title="'.esc_attr__('Go to Transaction Details', 'event_espresso').'">'
163 163
                         . $transaction->ID()
164 164
                         . '</a>';
165 165
 
166 166
         //txn timestamp
167
-        $content .= '  <span class="show-on-mobile-view-only">' . $this->_get_txn_timestamp($transaction) . '</span>';
167
+        $content .= '  <span class="show-on-mobile-view-only">'.$this->_get_txn_timestamp($transaction).'</span>';
168 168
         return $content;
169 169
     }
170 170
 
@@ -221,9 +221,9 @@  discard block
 block discarded – undo
221 221
             'action' => 'view_transaction',
222 222
             'TXN_ID' => $transaction->ID(),
223 223
         ), TXN_ADMIN_URL);
224
-        $txn_date     = '<a href="' . $view_lnk_url . '"'
224
+        $txn_date = '<a href="'.$view_lnk_url.'"'
225 225
                         . ' title="'
226
-                        . esc_attr__('View Transaction Details for TXN #', 'event_espresso') . $transaction->ID() . '">'
226
+                        . esc_attr__('View Transaction Details for TXN #', 'event_espresso').$transaction->ID().'">'
227 227
                         . $this->_get_txn_timestamp($transaction)
228 228
                         . '</a>';
229 229
         //status
@@ -256,7 +256,7 @@  discard block
 block discarded – undo
256 256
                    )
257 257
                    . '</span>';
258 258
         } else {
259
-            return '<span class="txn-overview-free-event-spn">' . esc_html__('free', 'event_espresso') . '</span>';
259
+            return '<span class="txn-overview-free-event-spn">'.esc_html__('free', 'event_espresso').'</span>';
260 260
         }
261 261
     }
262 262
 
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
             : esc_html__('Unknown', 'event_espresso');
295 295
         $transaction_paid_content = $transaction_paid !== 0 ? $transaction->get_pretty('TXN_paid') : $transaction_paid;
296 296
 
297
-        $content = '<span class="' . $span_class . ' txn-pad-rght">'
297
+        $content = '<span class="'.$span_class.' txn-pad-rght">'
298 298
                    . $transaction_paid_content
299 299
                    . '</span>';
300 300
         if ($transaction_paid > 0) {
@@ -325,17 +325,17 @@  discard block
 block discarded – undo
325 325
                 'action'  => 'view_registration',
326 326
                 '_REG_ID' => $primary_reg->ID(),
327 327
             ), REG_ADMIN_URL);
328
-            $content      = EE_Registry::instance()->CAP->current_user_can(
328
+            $content = EE_Registry::instance()->CAP->current_user_can(
329 329
                 'ee_read_registration',
330 330
                 'espresso_registrations_view_registration',
331 331
                 $primary_reg->ID()
332 332
             )
333
-                ? '<a href="' . $edit_lnk_url . '"'
334
-                    . ' title="' . esc_attr__('View Registration Details', 'event_espresso') . '">'
333
+                ? '<a href="'.$edit_lnk_url.'"'
334
+                    . ' title="'.esc_attr__('View Registration Details', 'event_espresso').'">'
335 335
                     . $attendee->full_name()
336 336
                     . '</a>'
337 337
                 : $attendee->full_name();
338
-            $content      .= '<br>' . $attendee->email();
338
+            $content .= '<br>'.$attendee->email();
339 339
             return $content;
340 340
         }
341 341
         return $transaction->failed() || $transaction->is_abandoned()
@@ -357,8 +357,8 @@  discard block
 block discarded – undo
357 357
     public function column_ATT_email(EE_Transaction $transaction)
358 358
     {
359 359
         $attendee = $transaction->primary_registration()->get_first_related('Attendee');
360
-        if (! empty($attendee)) {
361
-            return '<a href="mailto:' . $attendee->get('ATT_email') . '">'
360
+        if ( ! empty($attendee)) {
361
+            return '<a href="mailto:'.$attendee->get('ATT_email').'">'
362 362
                    . $attendee->get('ATT_email')
363 363
                    . '</a>';
364 364
         } else {
@@ -383,12 +383,12 @@  discard block
 block discarded – undo
383 383
     {
384 384
         $actions = array();
385 385
         $event   = $transaction->primary_registration()->get_first_related('Event');
386
-        if (! empty($event)) {
386
+        if ( ! empty($event)) {
387 387
             $edit_event_url = EE_Admin_Page::add_query_args_and_nonce(
388 388
                 array('action' => 'edit', 'post' => $event->ID()),
389 389
                 EVENTS_ADMIN_URL
390 390
             );
391
-            $event_name     = $event->get('EVT_name');
391
+            $event_name = $event->get('EVT_name');
392 392
 
393 393
             //filter this view by transactions for this event
394 394
             $txn_by_event_lnk = EE_Admin_Page::add_query_args_and_nonce(array(
@@ -400,8 +400,8 @@  discard block
 block discarded – undo
400 400
                 'espresso_events_edit',
401 401
                 $event->ID()
402 402
             )) {
403
-                $actions['filter_by_event'] = '<a href="' . $txn_by_event_lnk . '"'
404
-                        . ' title="' . esc_attr__('Filter transactions by this event', 'event_espresso') . '">'
403
+                $actions['filter_by_event'] = '<a href="'.$txn_by_event_lnk.'"'
404
+                        . ' title="'.esc_attr__('Filter transactions by this event', 'event_espresso').'">'
405 405
                         . esc_html__('View Transactions for this event', 'event_espresso')
406 406
                         . '</a>';
407 407
             }
@@ -413,7 +413,7 @@  discard block
 block discarded – undo
413 413
                     'espresso_events_edit',
414 414
                     $event->ID()
415 415
                 )
416
-                    ? '<a href="' . $edit_event_url . '"'
416
+                    ? '<a href="'.$edit_event_url.'"'
417 417
                         . ' title="'
418 418
                         . sprintf(
419 419
                             esc_attr__('Edit Event: %s', 'event_espresso'),
@@ -470,14 +470,14 @@  discard block
 block discarded – undo
470 470
      */
471 471
     protected function get_transaction_details_link(EE_Transaction $transaction)
472 472
     {
473
-        $url          = EE_Admin_Page::add_query_args_and_nonce(array(
473
+        $url = EE_Admin_Page::add_query_args_and_nonce(array(
474 474
             'action' => 'view_transaction',
475 475
             'TXN_ID' => $transaction->ID(),
476 476
         ), TXN_ADMIN_URL);
477 477
         return '
478 478
 			<li>
479
-				<a href="' . $url . '"'
480
-                    . ' title="' . esc_attr__('View Transaction Details', 'event_espresso') . '" class="tiny-text">
479
+				<a href="' . $url.'"'
480
+                    . ' title="'.esc_attr__('View Transaction Details', 'event_espresso').'" class="tiny-text">
481 481
 					<span class="dashicons dashicons-cart"></span>
482 482
 				</a>
483 483
 			</li>';
@@ -501,8 +501,8 @@  discard block
 block discarded – undo
501 501
             ) {
502 502
                 return '
503 503
                 <li>
504
-                    <a title="' . esc_attr__('View Transaction Invoice', 'event_espresso') . '"'
505
-                       . ' target="_blank" href="' . $url . '" class="tiny-text">
504
+                    <a title="' . esc_attr__('View Transaction Invoice', 'event_espresso').'"'
505
+                       . ' target="_blank" href="'.$url.'" class="tiny-text">
506 506
                         <span class="dashicons dashicons-media-spreadsheet ee-icon-size-18"></span>
507 507
                     </a>
508 508
                 </li>';
@@ -528,8 +528,8 @@  discard block
 block discarded – undo
528 528
                 && EEH_MSG_Template::is_mt_active('receipt')) {
529 529
                 return '
530 530
 			<li>
531
-				<a title="' . esc_attr__('View Transaction Receipt', 'event_espresso') . '"'
532
-                                  . ' target="_blank" href="' . $url . '" class="tiny-text">
531
+				<a title="' . esc_attr__('View Transaction Receipt', 'event_espresso').'"'
532
+                                  . ' target="_blank" href="'.$url.'" class="tiny-text">
533 533
 					<span class="dashicons dashicons-media-default ee-icon-size-18"></span>
534 534
 				</a>
535 535
 			</li>';
@@ -560,8 +560,8 @@  discard block
 block discarded – undo
560 560
             )
561 561
                 ? '
562 562
 				<li>
563
-					<a href="' . $url . '"'
564
-                  . ' title="' . esc_attr__('View Registration Details', 'event_espresso') . '" class="tiny-text">
563
+					<a href="' . $url.'"'
564
+                  . ' title="'.esc_attr__('View Registration Details', 'event_espresso').'" class="tiny-text">
565 565
 						<span class="dashicons dashicons-clipboard"></span>
566 566
 					</a>
567 567
 				</li>'
@@ -599,8 +599,8 @@  discard block
 block discarded – undo
599 599
             ), TXN_ADMIN_URL);
600 600
             return  '
601 601
             <li>
602
-                <a href="' . $url . '"'
603
-                  . ' title="' . esc_attr__('Send Payment Reminder', 'event_espresso') . '" class="tiny-text">
602
+                <a href="' . $url.'"'
603
+                  . ' title="'.esc_attr__('Send Payment Reminder', 'event_espresso').'" class="tiny-text">
604 604
                     <span class="dashicons dashicons-email-alt"></span>
605 605
                 </a>
606 606
             </li>';
@@ -627,7 +627,7 @@  discard block
 block discarded – undo
627 627
             'ee_read_global_messages',
628 628
             'view_filtered_messages'
629 629
         )
630
-            ? '<li>' . $url . '</li>'
630
+            ? '<li>'.$url.'</li>'
631 631
             : '';
632 632
     }
633 633
 
@@ -647,8 +647,8 @@  discard block
 block discarded – undo
647 647
         ) {
648 648
             return '
649 649
             <li>
650
-                <a title="' . esc_attr__('Make Payment from the Frontend.', 'event_espresso') . '"'
651
-                    . ' target="_blank" href="' . $registration->payment_overview_url(true) . '"'
650
+                <a title="' . esc_attr__('Make Payment from the Frontend.', 'event_espresso').'"'
651
+                    . ' target="_blank" href="'.$registration->payment_overview_url(true).'"'
652 652
                     . ' class="tiny-text">
653 653
                     <span class="dashicons dashicons-money ee-icon-size-18"></span>
654 654
                 </a>
Please login to merge, or discard this patch.
modules/single_page_checkout/EED_Single_Page_Checkout.module.php 2 patches
Indentation   +1856 added lines, -1856 removed lines patch added patch discarded remove patch
@@ -5,7 +5,7 @@  discard block
 block discarded – undo
5 5
 use EventEspresso\core\exceptions\InvalidEntityException;
6 6
 
7 7
 if ( ! defined('EVENT_ESPRESSO_VERSION')) {
8
-    exit('No direct script access allowed');
8
+	exit('No direct script access allowed');
9 9
 }
10 10
 
11 11
 
@@ -20,1861 +20,1861 @@  discard block
 block discarded – undo
20 20
 class EED_Single_Page_Checkout extends EED_Module
21 21
 {
22 22
 
23
-    /**
24
-     * $_initialized - has the SPCO controller already been initialized ?
25
-     *
26
-     * @access private
27
-     * @var bool $_initialized
28
-     */
29
-    private static $_initialized = false;
30
-
31
-
32
-    /**
33
-     * $_checkout_verified - is the EE_Checkout verified as correct for this request ?
34
-     *
35
-     * @access private
36
-     * @var bool $_valid_checkout
37
-     */
38
-    private static $_checkout_verified = true;
39
-
40
-    /**
41
-     *    $_reg_steps_array - holds initial array of reg steps
42
-     *
43
-     * @access private
44
-     * @var array $_reg_steps_array
45
-     */
46
-    private static $_reg_steps_array = array();
47
-
48
-    /**
49
-     *    $checkout - EE_Checkout object for handling the properties of the current checkout process
50
-     *
51
-     * @access public
52
-     * @var EE_Checkout $checkout
53
-     */
54
-    public $checkout;
55
-
56
-
57
-
58
-    /**
59
-     * @return EED_Module|EED_Single_Page_Checkout
60
-     */
61
-    public static function instance()
62
-    {
63
-        add_filter('EED_Single_Page_Checkout__SPCO_active', '__return_true');
64
-        return parent::get_instance(__CLASS__);
65
-    }
66
-
67
-
68
-
69
-    /**
70
-     * @return EE_CART
71
-     */
72
-    public function cart()
73
-    {
74
-        return $this->checkout->cart;
75
-    }
76
-
77
-
78
-
79
-    /**
80
-     * @return EE_Transaction
81
-     */
82
-    public function transaction()
83
-    {
84
-        return $this->checkout->transaction;
85
-    }
86
-
87
-
88
-
89
-    /**
90
-     *    set_hooks - for hooking into EE Core, other modules, etc
91
-     *
92
-     * @access    public
93
-     * @return    void
94
-     * @throws EE_Error
95
-     */
96
-    public static function set_hooks()
97
-    {
98
-        EED_Single_Page_Checkout::set_definitions();
99
-    }
100
-
101
-
102
-
103
-    /**
104
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
105
-     *
106
-     * @access    public
107
-     * @return    void
108
-     * @throws EE_Error
109
-     */
110
-    public static function set_hooks_admin()
111
-    {
112
-        EED_Single_Page_Checkout::set_definitions();
113
-        if ( ! (defined('DOING_AJAX') && DOING_AJAX)) {
114
-            return;
115
-        }
116
-        // going to start an output buffer in case anything gets accidentally output
117
-        // that might disrupt our JSON response
118
-        ob_start();
119
-        EED_Single_Page_Checkout::load_request_handler();
120
-        EED_Single_Page_Checkout::load_reg_steps();
121
-        // set ajax hooks
122
-        add_action('wp_ajax_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step'));
123
-        add_action('wp_ajax_nopriv_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step'));
124
-        add_action('wp_ajax_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step'));
125
-        add_action('wp_ajax_nopriv_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step'));
126
-        add_action('wp_ajax_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step'));
127
-        add_action('wp_ajax_nopriv_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step'));
128
-    }
129
-
130
-
131
-
132
-    /**
133
-     *    process ajax request
134
-     *
135
-     * @param string $ajax_action
136
-     * @throws EE_Error
137
-     */
138
-    public static function process_ajax_request($ajax_action)
139
-    {
140
-        EE_Registry::instance()->REQ->set('action', $ajax_action);
141
-        EED_Single_Page_Checkout::instance()->_initialize();
142
-    }
143
-
144
-
145
-
146
-    /**
147
-     *    ajax display registration step
148
-     *
149
-     * @throws EE_Error
150
-     */
151
-    public static function display_reg_step()
152
-    {
153
-        EED_Single_Page_Checkout::process_ajax_request('display_spco_reg_step');
154
-    }
155
-
156
-
157
-
158
-    /**
159
-     *    ajax process registration step
160
-     *
161
-     * @throws EE_Error
162
-     */
163
-    public static function process_reg_step()
164
-    {
165
-        EED_Single_Page_Checkout::process_ajax_request('process_reg_step');
166
-    }
167
-
168
-
169
-
170
-    /**
171
-     *    ajax process registration step
172
-     *
173
-     * @throws EE_Error
174
-     */
175
-    public static function update_reg_step()
176
-    {
177
-        EED_Single_Page_Checkout::process_ajax_request('update_reg_step');
178
-    }
179
-
180
-
181
-
182
-    /**
183
-     *   update_checkout
184
-     *
185
-     * @access public
186
-     * @return void
187
-     * @throws EE_Error
188
-     */
189
-    public static function update_checkout()
190
-    {
191
-        EED_Single_Page_Checkout::process_ajax_request('update_checkout');
192
-    }
193
-
194
-
195
-
196
-    /**
197
-     *    load_request_handler
198
-     *
199
-     * @access    public
200
-     * @return    void
201
-     */
202
-    public static function load_request_handler()
203
-    {
204
-        // load core Request_Handler class
205
-        if (EE_Registry::instance()->REQ !== null) {
206
-            EE_Registry::instance()->load_core('Request_Handler');
207
-        }
208
-    }
209
-
210
-
211
-
212
-    /**
213
-     *    set_definitions
214
-     *
215
-     * @access    public
216
-     * @return    void
217
-     * @throws EE_Error
218
-     */
219
-    public static function set_definitions()
220
-    {
221
-        if(defined('SPCO_BASE_PATH')) {
222
-            return;
223
-        }
224
-        define(
225
-            'SPCO_BASE_PATH',
226
-            rtrim(str_replace(array('\\', '/'), DS, plugin_dir_path(__FILE__)), DS) . DS
227
-        );
228
-        define('SPCO_CSS_URL', plugin_dir_url(__FILE__) . 'css' . DS);
229
-        define('SPCO_IMG_URL', plugin_dir_url(__FILE__) . 'img' . DS);
230
-        define('SPCO_JS_URL', plugin_dir_url(__FILE__) . 'js' . DS);
231
-        define('SPCO_INC_PATH', SPCO_BASE_PATH . 'inc' . DS);
232
-        define('SPCO_REG_STEPS_PATH', SPCO_BASE_PATH . 'reg_steps' . DS);
233
-        define('SPCO_TEMPLATES_PATH', SPCO_BASE_PATH . 'templates' . DS);
234
-        EEH_Autoloader::register_autoloaders_for_each_file_in_folder(SPCO_BASE_PATH, true);
235
-        EE_Registry::$i18n_js_strings['registration_expiration_notice'] = sprintf(
236
-            __('%1$sWe\'re sorry, but you\'re registration time has expired.%2$s%4$sIf you still wish to complete your registration, please return to the %5$sEvent List%6$sEvent List%7$s and reselect your tickets if available. Please except our apologies for any inconvenience this may have caused.%8$s',
237
-                'event_espresso'),
238
-            '<h4 class="important-notice">',
239
-            '</h4>',
240
-            '<br />',
241
-            '<p>',
242
-            '<a href="' . get_post_type_archive_link('espresso_events') . '" title="',
243
-            '">',
244
-            '</a>',
245
-            '</p>'
246
-        );
247
-    }
248
-
249
-
250
-
251
-    /**
252
-     * load_reg_steps
253
-     * loads and instantiates each reg step based on the EE_Registry::instance()->CFG->registration->reg_steps array
254
-     *
255
-     * @access    private
256
-     * @throws EE_Error
257
-     */
258
-    public static function load_reg_steps()
259
-    {
260
-        static $reg_steps_loaded = false;
261
-        if ($reg_steps_loaded) {
262
-            return;
263
-        }
264
-        // filter list of reg_steps
265
-        $reg_steps_to_load = (array)apply_filters(
266
-            'AHEE__SPCO__load_reg_steps__reg_steps_to_load',
267
-            EED_Single_Page_Checkout::get_reg_steps()
268
-        );
269
-        // sort by key (order)
270
-        ksort($reg_steps_to_load);
271
-        // loop through folders
272
-        foreach ($reg_steps_to_load as $order => $reg_step) {
273
-            // we need a
274
-            if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) {
275
-                // copy over to the reg_steps_array
276
-                EED_Single_Page_Checkout::$_reg_steps_array[$order] = $reg_step;
277
-                // register custom key route for each reg step
278
-                // ie: step=>"slug" - this is the entire reason we load the reg steps array now
279
-                EE_Config::register_route(
280
-                    $reg_step['slug'],
281
-                    'EED_Single_Page_Checkout',
282
-                    'run',
283
-                    'step'
284
-                );
285
-                // add AJAX or other hooks
286
-                if (isset($reg_step['has_hooks']) && $reg_step['has_hooks']) {
287
-                    // setup autoloaders if necessary
288
-                    if ( ! class_exists($reg_step['class_name'])) {
289
-                        EEH_Autoloader::register_autoloaders_for_each_file_in_folder(
290
-                            $reg_step['file_path'],
291
-                            true
292
-                        );
293
-                    }
294
-                    if (is_callable($reg_step['class_name'], 'set_hooks')) {
295
-                        call_user_func(array($reg_step['class_name'], 'set_hooks'));
296
-                    }
297
-                }
298
-            }
299
-        }
300
-        $reg_steps_loaded = true;
301
-    }
302
-
303
-
304
-
305
-    /**
306
-     *    get_reg_steps
307
-     *
308
-     * @access    public
309
-     * @return    array
310
-     */
311
-    public static function get_reg_steps()
312
-    {
313
-        $reg_steps = EE_Registry::instance()->CFG->registration->reg_steps;
314
-        if (empty($reg_steps)) {
315
-            $reg_steps = array(
316
-                10  => array(
317
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'attendee_information',
318
-                    'class_name' => 'EE_SPCO_Reg_Step_Attendee_Information',
319
-                    'slug'       => 'attendee_information',
320
-                    'has_hooks'  => false,
321
-                ),
322
-                20  => array(
323
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'registration_confirmation',
324
-                    'class_name' => 'EE_SPCO_Reg_Step_Registration_Confirmation',
325
-                    'slug'       => 'registration_confirmation',
326
-                    'has_hooks'  => false,
327
-                ),
328
-                30  => array(
329
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'payment_options',
330
-                    'class_name' => 'EE_SPCO_Reg_Step_Payment_Options',
331
-                    'slug'       => 'payment_options',
332
-                    'has_hooks'  => true,
333
-                ),
334
-                999 => array(
335
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'finalize_registration',
336
-                    'class_name' => 'EE_SPCO_Reg_Step_Finalize_Registration',
337
-                    'slug'       => 'finalize_registration',
338
-                    'has_hooks'  => false,
339
-                ),
340
-            );
341
-        }
342
-        return $reg_steps;
343
-    }
344
-
345
-
346
-
347
-    /**
348
-     *    registration_checkout_for_admin
349
-     *
350
-     * @access    public
351
-     * @return    string
352
-     * @throws EE_Error
353
-     */
354
-    public static function registration_checkout_for_admin()
355
-    {
356
-        EED_Single_Page_Checkout::load_request_handler();
357
-        EE_Registry::instance()->REQ->set('step', 'attendee_information');
358
-        EE_Registry::instance()->REQ->set('action', 'display_spco_reg_step');
359
-        EE_Registry::instance()->REQ->set('process_form_submission', false);
360
-        EED_Single_Page_Checkout::instance()->_initialize();
361
-        EED_Single_Page_Checkout::instance()->_display_spco_reg_form();
362
-        return EE_Registry::instance()->REQ->get_output();
363
-    }
364
-
365
-
366
-
367
-    /**
368
-     * process_registration_from_admin
369
-     *
370
-     * @access public
371
-     * @return \EE_Transaction
372
-     * @throws EE_Error
373
-     */
374
-    public static function process_registration_from_admin()
375
-    {
376
-        EED_Single_Page_Checkout::load_request_handler();
377
-        EE_Registry::instance()->REQ->set('step', 'attendee_information');
378
-        EE_Registry::instance()->REQ->set('action', 'process_reg_step');
379
-        EE_Registry::instance()->REQ->set('process_form_submission', true);
380
-        EED_Single_Page_Checkout::instance()->_initialize();
381
-        if (EED_Single_Page_Checkout::instance()->checkout->current_step->completed()) {
382
-            $final_reg_step = end(EED_Single_Page_Checkout::instance()->checkout->reg_steps);
383
-            if ($final_reg_step instanceof EE_SPCO_Reg_Step_Finalize_Registration) {
384
-                EED_Single_Page_Checkout::instance()->checkout->set_reg_step_initiated($final_reg_step);
385
-                if ($final_reg_step->process_reg_step()) {
386
-                    $final_reg_step->set_completed();
387
-                    EED_Single_Page_Checkout::instance()->checkout->update_txn_reg_steps_array();
388
-                    return EED_Single_Page_Checkout::instance()->checkout->transaction;
389
-                }
390
-            }
391
-        }
392
-        return null;
393
-    }
394
-
395
-
396
-
397
-    /**
398
-     *    run
399
-     *
400
-     * @access    public
401
-     * @param WP_Query $WP_Query
402
-     * @return    void
403
-     * @throws EE_Error
404
-     */
405
-    public function run($WP_Query)
406
-    {
407
-        if (
408
-            $WP_Query instanceof WP_Query
409
-            && $WP_Query->is_main_query()
410
-            && apply_filters('FHEE__EED_Single_Page_Checkout__run', true)
411
-            && $this->_is_reg_checkout()
412
-        ) {
413
-            $this->_initialize();
414
-        }
415
-    }
416
-
417
-
418
-
419
-    /**
420
-     * determines whether current url matches reg page url
421
-     *
422
-     * @return bool
423
-     */
424
-    protected function _is_reg_checkout()
425
-    {
426
-        // get current permalink for reg page without any extra query args
427
-        $reg_page_url = \get_permalink(EE_Config::instance()->core->reg_page_id);
428
-        // get request URI for current request, but without the scheme or host
429
-        $current_request_uri = \EEH_URL::filter_input_server_url('REQUEST_URI');
430
-        $current_request_uri = html_entity_decode($current_request_uri);
431
-        // get array of query args from the current request URI
432
-        $query_args = \EEH_URL::get_query_string($current_request_uri);
433
-        // grab page id if it is set
434
-        $page_id = isset($query_args['page_id']) ? absint($query_args['page_id']) : 0;
435
-        // and remove the page id from the query args (we will re-add it later)
436
-        unset($query_args['page_id']);
437
-        // now strip all query args from current request URI
438
-        $current_request_uri = remove_query_arg(array_keys($query_args), $current_request_uri);
439
-        // and re-add the page id if it was set
440
-        if ($page_id) {
441
-            $current_request_uri = add_query_arg('page_id', $page_id, $current_request_uri);
442
-        }
443
-        // remove slashes and ?
444
-        $current_request_uri = trim($current_request_uri, '?/');
445
-        // is current request URI part of the known full reg page URL ?
446
-        return ! empty($current_request_uri) && strpos($reg_page_url, $current_request_uri) !== false;
447
-    }
448
-
449
-
450
-
451
-    /**
452
-     * @param WP_Query $wp_query
453
-     * @return    void
454
-     * @throws EE_Error
455
-     */
456
-    public static function init($wp_query)
457
-    {
458
-        EED_Single_Page_Checkout::instance()->run($wp_query);
459
-    }
460
-
461
-
462
-
463
-    /**
464
-     *    _initialize - initial module setup
465
-     *
466
-     * @access    private
467
-     * @throws EE_Error
468
-     * @return    void
469
-     */
470
-    private function _initialize()
471
-    {
472
-        // ensure SPCO doesn't run twice
473
-        if (EED_Single_Page_Checkout::$_initialized) {
474
-            return;
475
-        }
476
-        try {
477
-            EED_Single_Page_Checkout::load_reg_steps();
478
-            $this->_verify_session();
479
-            // setup the EE_Checkout object
480
-            $this->checkout = $this->_initialize_checkout();
481
-            // filter checkout
482
-            $this->checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize__checkout', $this->checkout);
483
-            // get the $_GET
484
-            $this->_get_request_vars();
485
-            if ($this->_block_bots()) {
486
-                return;
487
-            }
488
-            // filter continue_reg
489
-            $this->checkout->continue_reg = apply_filters(
490
-                'FHEE__EED_Single_Page_Checkout__init___continue_reg',
491
-                true,
492
-                $this->checkout
493
-            );
494
-            // load the reg steps array
495
-            if ( ! $this->_load_and_instantiate_reg_steps()) {
496
-                EED_Single_Page_Checkout::$_initialized = true;
497
-                return;
498
-            }
499
-            // set the current step
500
-            $this->checkout->set_current_step($this->checkout->step);
501
-            // and the next step
502
-            $this->checkout->set_next_step();
503
-            // verify that everything has been setup correctly
504
-            if ( ! ($this->_verify_transaction_and_get_registrations() && $this->_final_verifications())) {
505
-                EED_Single_Page_Checkout::$_initialized = true;
506
-                return;
507
-            }
508
-            // lock the transaction
509
-            $this->checkout->transaction->lock();
510
-            // make sure all of our cached objects are added to their respective model entity mappers
511
-            $this->checkout->refresh_all_entities();
512
-            // set amount owing
513
-            $this->checkout->amount_owing = $this->checkout->transaction->remaining();
514
-            // initialize each reg step, which gives them the chance to potentially alter the process
515
-            $this->_initialize_reg_steps();
516
-            // DEBUG LOG
517
-            //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
518
-            // get reg form
519
-            if( ! $this->_check_form_submission()) {
520
-                EED_Single_Page_Checkout::$_initialized = true;
521
-                return;
522
-            }
523
-            // checkout the action!!!
524
-            $this->_process_form_action();
525
-            // add some style and make it dance
526
-            $this->add_styles_and_scripts();
527
-            // kk... SPCO has successfully run
528
-            EED_Single_Page_Checkout::$_initialized = true;
529
-            // set no cache headers and constants
530
-            EE_System::do_not_cache();
531
-            // add anchor
532
-            add_action('loop_start', array($this, 'set_checkout_anchor'), 1);
533
-            // remove transaction lock
534
-            add_action('shutdown', array($this, 'unlock_transaction'), 1);
535
-        } catch (Exception $e) {
536
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
537
-        }
538
-    }
539
-
540
-
541
-
542
-    /**
543
-     *    _verify_session
544
-     * checks that the session is valid and not expired
545
-     *
546
-     * @access    private
547
-     * @throws EE_Error
548
-     */
549
-    private function _verify_session()
550
-    {
551
-        if ( ! EE_Registry::instance()->SSN instanceof EE_Session) {
552
-            throw new EE_Error(__('The EE_Session class could not be loaded.', 'event_espresso'));
553
-        }
554
-        $clear_session_requested = filter_var(
555
-            EE_Registry::instance()->REQ->get('clear_session', false),
556
-            FILTER_VALIDATE_BOOLEAN
557
-        );
558
-        // is session still valid ?
559
-        if ($clear_session_requested
560
-            || ( EE_Registry::instance()->SSN->expired()
561
-              && EE_Registry::instance()->REQ->get('e_reg_url_link', '') === ''
562
-            )
563
-        ) {
564
-            $this->checkout = new EE_Checkout();
565
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
566
-            // EE_Registry::instance()->SSN->reset_cart();
567
-            // EE_Registry::instance()->SSN->reset_checkout();
568
-            // EE_Registry::instance()->SSN->reset_transaction();
569
-            if (! $clear_session_requested) {
570
-                EE_Error::add_attention(
571
-                    EE_Registry::$i18n_js_strings['registration_expiration_notice'],
572
-                    __FILE__, __FUNCTION__, __LINE__
573
-                );
574
-            }
575
-            // EE_Registry::instance()->SSN->reset_expired();
576
-        }
577
-    }
578
-
579
-
580
-
581
-    /**
582
-     *    _initialize_checkout
583
-     * loads and instantiates EE_Checkout
584
-     *
585
-     * @access    private
586
-     * @throws EE_Error
587
-     * @return EE_Checkout
588
-     */
589
-    private function _initialize_checkout()
590
-    {
591
-        // look in session for existing checkout
592
-        /** @type EE_Checkout $checkout */
593
-        $checkout = EE_Registry::instance()->SSN->checkout();
594
-        // verify
595
-        if ( ! $checkout instanceof EE_Checkout) {
596
-            // instantiate EE_Checkout object for handling the properties of the current checkout process
597
-            $checkout = EE_Registry::instance()->load_file(
598
-                SPCO_INC_PATH,
599
-                'EE_Checkout',
600
-                'class', array(),
601
-                false
602
-            );
603
-        } else {
604
-            if ($checkout->current_step->is_final_step() && $checkout->exit_spco() === true) {
605
-                $this->unlock_transaction();
606
-                wp_safe_redirect($checkout->redirect_url);
607
-                exit();
608
-            }
609
-        }
610
-        $checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize_checkout__checkout', $checkout);
611
-        // verify again
612
-        if ( ! $checkout instanceof EE_Checkout) {
613
-            throw new EE_Error(__('The EE_Checkout class could not be loaded.', 'event_espresso'));
614
-        }
615
-        // reset anything that needs a clean slate for each request
616
-        $checkout->reset_for_current_request();
617
-        return $checkout;
618
-    }
619
-
620
-
621
-
622
-    /**
623
-     *    _get_request_vars
624
-     *
625
-     * @access    private
626
-     * @return    void
627
-     * @throws EE_Error
628
-     */
629
-    private function _get_request_vars()
630
-    {
631
-        // load classes
632
-        EED_Single_Page_Checkout::load_request_handler();
633
-        //make sure this request is marked as belonging to EE
634
-        EE_Registry::instance()->REQ->set_espresso_page(true);
635
-        // which step is being requested ?
636
-        $this->checkout->step = EE_Registry::instance()->REQ->get('step', $this->_get_first_step());
637
-        // which step is being edited ?
638
-        $this->checkout->edit_step = EE_Registry::instance()->REQ->get('edit_step', '');
639
-        // and what we're doing on the current step
640
-        $this->checkout->action = EE_Registry::instance()->REQ->get('action', 'display_spco_reg_step');
641
-        // timestamp
642
-        $this->checkout->uts = EE_Registry::instance()->REQ->get('uts', 0);
643
-        // returning to edit ?
644
-        $this->checkout->reg_url_link = EE_Registry::instance()->REQ->get('e_reg_url_link', '');
645
-        // or some other kind of revisit ?
646
-        $this->checkout->revisit = filter_var(
647
-            EE_Registry::instance()->REQ->get('revisit', false),
648
-            FILTER_VALIDATE_BOOLEAN
649
-        );
650
-        // and whether or not to generate a reg form for this request
651
-        $this->checkout->generate_reg_form = filter_var(
652
-            EE_Registry::instance()->REQ->get('generate_reg_form', true),
653
-            FILTER_VALIDATE_BOOLEAN
654
-        );
655
-        // and whether or not to process a reg form submission for this request
656
-        $this->checkout->process_form_submission = filter_var(
657
-            EE_Registry::instance()->REQ->get(
658
-                'process_form_submission',
659
-                $this->checkout->action === 'process_reg_step'
660
-            ),
661
-            FILTER_VALIDATE_BOOLEAN
662
-        );
663
-        $this->checkout->process_form_submission = filter_var(
664
-            $this->checkout->action !== 'display_spco_reg_step'
665
-                ? $this->checkout->process_form_submission
666
-                : false,
667
-            FILTER_VALIDATE_BOOLEAN
668
-        );
669
-        // $this->_display_request_vars();
670
-    }
671
-
672
-
673
-
674
-    /**
675
-     *  _display_request_vars
676
-     *
677
-     * @access    protected
678
-     * @return    void
679
-     */
680
-    protected function _display_request_vars()
681
-    {
682
-        if ( ! WP_DEBUG) {
683
-            return;
684
-        }
685
-        EEH_Debug_Tools::printr($_REQUEST, '$_REQUEST', __FILE__, __LINE__);
686
-        EEH_Debug_Tools::printr($this->checkout->step, '$this->checkout->step', __FILE__, __LINE__);
687
-        EEH_Debug_Tools::printr($this->checkout->edit_step, '$this->checkout->edit_step', __FILE__, __LINE__);
688
-        EEH_Debug_Tools::printr($this->checkout->action, '$this->checkout->action', __FILE__, __LINE__);
689
-        EEH_Debug_Tools::printr($this->checkout->reg_url_link, '$this->checkout->reg_url_link', __FILE__, __LINE__);
690
-        EEH_Debug_Tools::printr($this->checkout->revisit, '$this->checkout->revisit', __FILE__, __LINE__);
691
-        EEH_Debug_Tools::printr($this->checkout->generate_reg_form, '$this->checkout->generate_reg_form', __FILE__, __LINE__);
692
-        EEH_Debug_Tools::printr($this->checkout->process_form_submission, '$this->checkout->process_form_submission', __FILE__, __LINE__);
693
-    }
694
-
695
-
696
-
697
-    /**
698
-     * _block_bots
699
-     * checks that the incoming request has either of the following set:
700
-     *  a uts (unix timestamp) which indicates that the request was redirected from the Ticket Selector
701
-     *  a REG URL Link, which indicates that the request is a return visit to SPCO for a valid TXN
702
-     * so if you're not coming from the Ticket Selector nor returning for a valid IP...
703
-     * then where you coming from man?
704
-     *
705
-     * @return boolean
706
-     */
707
-    private function _block_bots()
708
-    {
709
-        $invalid_checkout_access = EED_Invalid_Checkout_Access::getInvalidCheckoutAccess();
710
-        if ($invalid_checkout_access->checkoutAccessIsInvalid($this->checkout)) {
711
-            return true;
712
-        }
713
-        return false;
714
-    }
715
-
716
-
717
-
718
-    /**
719
-     *    _get_first_step
720
-     *  gets slug for first step in $_reg_steps_array
721
-     *
722
-     * @access    private
723
-     * @throws EE_Error
724
-     * @return    string
725
-     */
726
-    private function _get_first_step()
727
-    {
728
-        $first_step = reset(EED_Single_Page_Checkout::$_reg_steps_array);
729
-        return isset($first_step['slug']) ? $first_step['slug'] : 'attendee_information';
730
-    }
731
-
732
-
733
-
734
-    /**
735
-     *    _load_and_instantiate_reg_steps
736
-     *  instantiates each reg step based on the loaded reg_steps array
737
-     *
738
-     * @access    private
739
-     * @throws EE_Error
740
-     * @return    bool
741
-     */
742
-    private function _load_and_instantiate_reg_steps()
743
-    {
744
-        do_action('AHEE__Single_Page_Checkout___load_and_instantiate_reg_steps__start', $this->checkout);
745
-        // have reg_steps already been instantiated ?
746
-        if (
747
-            empty($this->checkout->reg_steps)
748
-            || apply_filters('FHEE__Single_Page_Checkout__load_reg_steps__reload_reg_steps', false, $this->checkout)
749
-        ) {
750
-            // if not, then loop through raw reg steps array
751
-            foreach (EED_Single_Page_Checkout::$_reg_steps_array as $order => $reg_step) {
752
-                if ( ! $this->_load_and_instantiate_reg_step($reg_step, $order)) {
753
-                    return false;
754
-                }
755
-            }
756
-            EE_Registry::instance()->CFG->registration->skip_reg_confirmation = true;
757
-            EE_Registry::instance()->CFG->registration->reg_confirmation_last = true;
758
-            // skip the registration_confirmation page ?
759
-            if (EE_Registry::instance()->CFG->registration->skip_reg_confirmation) {
760
-                // just remove it from the reg steps array
761
-                $this->checkout->remove_reg_step('registration_confirmation', false);
762
-            } else if (
763
-                isset($this->checkout->reg_steps['registration_confirmation'])
764
-                && EE_Registry::instance()->CFG->registration->reg_confirmation_last
765
-            ) {
766
-                // set the order to something big like 100
767
-                $this->checkout->set_reg_step_order('registration_confirmation', 100);
768
-            }
769
-            // filter the array for good luck
770
-            $this->checkout->reg_steps = apply_filters(
771
-                'FHEE__Single_Page_Checkout__load_reg_steps__reg_steps',
772
-                $this->checkout->reg_steps
773
-            );
774
-            // finally re-sort based on the reg step class order properties
775
-            $this->checkout->sort_reg_steps();
776
-        } else {
777
-            foreach ($this->checkout->reg_steps as $reg_step) {
778
-                // set all current step stati to FALSE
779
-                $reg_step->set_is_current_step(false);
780
-            }
781
-        }
782
-        if (empty($this->checkout->reg_steps)) {
783
-            EE_Error::add_error(
784
-                __('No Reg Steps were loaded..', 'event_espresso'),
785
-                __FILE__, __FUNCTION__, __LINE__
786
-            );
787
-            return false;
788
-        }
789
-        // make reg step details available to JS
790
-        $this->checkout->set_reg_step_JSON_info();
791
-        return true;
792
-    }
793
-
794
-
795
-
796
-    /**
797
-     *     _load_and_instantiate_reg_step
798
-     *
799
-     * @access    private
800
-     * @param array $reg_step
801
-     * @param int   $order
802
-     * @return bool
803
-     */
804
-    private function _load_and_instantiate_reg_step($reg_step = array(), $order = 0)
805
-    {
806
-        // we need a file_path, class_name, and slug to add a reg step
807
-        if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) {
808
-            // if editing a specific step, but this is NOT that step... (and it's not the 'finalize_registration' step)
809
-            if (
810
-                $this->checkout->reg_url_link
811
-                && $this->checkout->step !== $reg_step['slug']
812
-                && $reg_step['slug'] !== 'finalize_registration'
813
-                // normally at this point we would NOT load the reg step, but this filter can change that
814
-                && apply_filters(
815
-                    'FHEE__Single_Page_Checkout___load_and_instantiate_reg_step__bypass_reg_step',
816
-                    true,
817
-                    $reg_step,
818
-                    $this->checkout
819
-                )
820
-            ) {
821
-                return true;
822
-            }
823
-            // instantiate step class using file path and class name
824
-            $reg_step_obj = EE_Registry::instance()->load_file(
825
-                $reg_step['file_path'],
826
-                $reg_step['class_name'],
827
-                'class',
828
-                $this->checkout,
829
-                false
830
-            );
831
-            // did we gets the goods ?
832
-            if ($reg_step_obj instanceof EE_SPCO_Reg_Step) {
833
-                // set reg step order based on config
834
-                $reg_step_obj->set_order($order);
835
-                // add instantiated reg step object to the master reg steps array
836
-                $this->checkout->add_reg_step($reg_step_obj);
837
-            } else {
838
-                EE_Error::add_error(
839
-                    __('The current step could not be set.', 'event_espresso'),
840
-                    __FILE__, __FUNCTION__, __LINE__
841
-                );
842
-                return false;
843
-            }
844
-        } else {
845
-            if (WP_DEBUG) {
846
-                EE_Error::add_error(
847
-                    sprintf(
848
-                        __(
849
-                            'A registration step could not be loaded. One or more of the following data points is invalid:%4$s%5$sFile Path: %1$s%6$s%5$sClass Name: %2$s%6$s%5$sSlug: %3$s%6$s%7$s',
850
-                            'event_espresso'
851
-                        ),
852
-                        isset($reg_step['file_path']) ? $reg_step['file_path'] : '',
853
-                        isset($reg_step['class_name']) ? $reg_step['class_name'] : '',
854
-                        isset($reg_step['slug']) ? $reg_step['slug'] : '',
855
-                        '<ul>',
856
-                        '<li>',
857
-                        '</li>',
858
-                        '</ul>'
859
-                    ),
860
-                    __FILE__, __FUNCTION__, __LINE__
861
-                );
862
-            }
863
-            return false;
864
-        }
865
-        return true;
866
-    }
867
-
868
-
869
-    /**
870
-     * _verify_transaction_and_get_registrations
871
-     *
872
-     * @access private
873
-     * @return bool
874
-     * @throws InvalidDataTypeException
875
-     * @throws InvalidEntityException
876
-     * @throws EE_Error
877
-     */
878
-    private function _verify_transaction_and_get_registrations()
879
-    {
880
-        // was there already a valid transaction in the checkout from the session ?
881
-        if ( ! $this->checkout->transaction instanceof EE_Transaction) {
882
-            // get transaction from db or session
883
-            $this->checkout->transaction = $this->checkout->reg_url_link && ! is_admin()
884
-                ? $this->_get_transaction_and_cart_for_previous_visit()
885
-                : $this->_get_cart_for_current_session_and_setup_new_transaction();
886
-            if ( ! $this->checkout->transaction instanceof EE_Transaction) {
887
-                EE_Error::add_error(
888
-                    __('Your Registration and Transaction information could not be retrieved from the db.',
889
-                        'event_espresso'),
890
-                    __FILE__, __FUNCTION__, __LINE__
891
-                );
892
-                $this->checkout->transaction = EE_Transaction::new_instance();
893
-                // add some style and make it dance
894
-                $this->add_styles_and_scripts();
895
-                EED_Single_Page_Checkout::$_initialized = true;
896
-                return false;
897
-            }
898
-            // and the registrations for the transaction
899
-            $this->_get_registrations($this->checkout->transaction);
900
-        }
901
-        return true;
902
-    }
903
-
904
-
905
-
906
-    /**
907
-     * _get_transaction_and_cart_for_previous_visit
908
-     *
909
-     * @access private
910
-     * @return mixed EE_Transaction|NULL
911
-     */
912
-    private function _get_transaction_and_cart_for_previous_visit()
913
-    {
914
-        /** @var $TXN_model EEM_Transaction */
915
-        $TXN_model = EE_Registry::instance()->load_model('Transaction');
916
-        // because the reg_url_link is present in the request,
917
-        // this is a return visit to SPCO, so we'll get the transaction data from the db
918
-        $transaction = $TXN_model->get_transaction_from_reg_url_link($this->checkout->reg_url_link);
919
-        // verify transaction
920
-        if ($transaction instanceof EE_Transaction) {
921
-            // and get the cart that was used for that transaction
922
-            $this->checkout->cart = $this->_get_cart_for_transaction($transaction);
923
-            return $transaction;
924
-        }
925
-        EE_Error::add_error(
926
-            __('Your Registration and Transaction information could not be retrieved from the db.', 'event_espresso'),
927
-            __FILE__, __FUNCTION__, __LINE__
928
-        );
929
-        return null;
930
-
931
-    }
932
-
933
-
934
-
935
-    /**
936
-     * _get_cart_for_transaction
937
-     *
938
-     * @access private
939
-     * @param EE_Transaction $transaction
940
-     * @return EE_Cart
941
-     */
942
-    private function _get_cart_for_transaction($transaction)
943
-    {
944
-        return $this->checkout->get_cart_for_transaction($transaction);
945
-    }
946
-
947
-
948
-
949
-    /**
950
-     * get_cart_for_transaction
951
-     *
952
-     * @access public
953
-     * @param EE_Transaction $transaction
954
-     * @return EE_Cart
955
-     */
956
-    public function get_cart_for_transaction(EE_Transaction $transaction)
957
-    {
958
-        return $this->checkout->get_cart_for_transaction($transaction);
959
-    }
960
-
961
-
962
-
963
-    /**
964
-     * _get_transaction_and_cart_for_current_session
965
-     *    generates a new EE_Transaction object and adds it to the $_transaction property.
966
-     *
967
-     * @access private
968
-     * @return EE_Transaction
969
-     * @throws EE_Error
970
-     */
971
-    private function _get_cart_for_current_session_and_setup_new_transaction()
972
-    {
973
-        //  if there's no transaction, then this is the FIRST visit to SPCO
974
-        // so load up the cart ( passing nothing for the TXN because it doesn't exist yet )
975
-        $this->checkout->cart = $this->_get_cart_for_transaction(null);
976
-        // and then create a new transaction
977
-        $transaction = $this->_initialize_transaction();
978
-        // verify transaction
979
-        if ($transaction instanceof EE_Transaction) {
980
-            // save it so that we have an ID for other objects to use
981
-            $transaction->save();
982
-            // and save TXN data to the cart
983
-            $this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn($transaction->ID());
984
-        } else {
985
-            EE_Error::add_error(
986
-                __('A Valid Transaction could not be initialized.', 'event_espresso'),
987
-                __FILE__, __FUNCTION__, __LINE__
988
-            );
989
-        }
990
-        return $transaction;
991
-    }
992
-
993
-
994
-
995
-    /**
996
-     *    generates a new EE_Transaction object and adds it to the $_transaction property.
997
-     *
998
-     * @access private
999
-     * @return mixed EE_Transaction|NULL
1000
-     */
1001
-    private function _initialize_transaction()
1002
-    {
1003
-        try {
1004
-            // ensure cart totals have been calculated
1005
-            $this->checkout->cart->get_grand_total()->recalculate_total_including_taxes();
1006
-            // grab the cart grand total
1007
-            $cart_total = $this->checkout->cart->get_cart_grand_total();
1008
-            // create new TXN
1009
-            $transaction = EE_Transaction::new_instance(
1010
-                array(
1011
-                    'TXN_reg_steps' => $this->checkout->initialize_txn_reg_steps_array(),
1012
-                    'TXN_total'     => $cart_total > 0 ? $cart_total : 0,
1013
-                    'TXN_paid'      => 0,
1014
-                    'STS_ID'        => EEM_Transaction::failed_status_code,
1015
-                )
1016
-            );
1017
-            // save it so that we have an ID for other objects to use
1018
-            $transaction->save();
1019
-            // set cron job for following up on TXNs after their session has expired
1020
-            EE_Cron_Tasks::schedule_expired_transaction_check(
1021
-                EE_Registry::instance()->SSN->expiration() + 1,
1022
-                $transaction->ID()
1023
-            );
1024
-            return $transaction;
1025
-        } catch (Exception $e) {
1026
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1027
-        }
1028
-        return null;
1029
-    }
1030
-
1031
-
1032
-    /**
1033
-     * _get_registrations
1034
-     *
1035
-     * @access private
1036
-     * @param EE_Transaction $transaction
1037
-     * @return void
1038
-     * @throws InvalidDataTypeException
1039
-     * @throws InvalidEntityException
1040
-     * @throws EE_Error
1041
-     */
1042
-    private function _get_registrations(EE_Transaction $transaction)
1043
-    {
1044
-        // first step: grab the registrants  { : o
1045
-        $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, true);
1046
-        // verify registrations have been set
1047
-        if (empty($registrations)) {
1048
-            // if no cached registrations, then check the db
1049
-            $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false);
1050
-            // still nothing ? well as long as this isn't a revisit
1051
-            if (empty($registrations) && ! $this->checkout->revisit) {
1052
-                // generate new registrations from scratch
1053
-                $registrations = $this->_initialize_registrations($transaction);
1054
-            }
1055
-        }
1056
-        // sort by their original registration order
1057
-        usort($registrations, array('EED_Single_Page_Checkout', 'sort_registrations_by_REG_count'));
1058
-        // then loop thru the array
1059
-        foreach ($registrations as $registration) {
1060
-            // verify each registration
1061
-            if ($registration instanceof EE_Registration) {
1062
-                // we display all attendee info for the primary registrant
1063
-                if ($this->checkout->reg_url_link === $registration->reg_url_link()
1064
-                    && $registration->is_primary_registrant()
1065
-                ) {
1066
-                    $this->checkout->primary_revisit = true;
1067
-                    break;
1068
-                }
1069
-                if ($this->checkout->revisit
1070
-                           && $this->checkout->reg_url_link !== $registration->reg_url_link()
1071
-                ) {
1072
-                    // but hide info if it doesn't belong to you
1073
-                    $transaction->clear_cache('Registration', $registration->ID());
1074
-                }
1075
-                $this->checkout->set_reg_status_updated($registration->ID(), false);
1076
-            }
1077
-        }
1078
-    }
1079
-
1080
-
1081
-    /**
1082
-     *    adds related EE_Registration objects for each ticket in the cart to the current EE_Transaction object
1083
-     *
1084
-     * @access private
1085
-     * @param EE_Transaction $transaction
1086
-     * @return    array
1087
-     * @throws InvalidDataTypeException
1088
-     * @throws InvalidEntityException
1089
-     * @throws EE_Error
1090
-     */
1091
-    private function _initialize_registrations(EE_Transaction $transaction)
1092
-    {
1093
-        $att_nmbr = 0;
1094
-        $registrations = array();
1095
-        if ($transaction instanceof EE_Transaction) {
1096
-            /** @type EE_Registration_Processor $registration_processor */
1097
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1098
-            $this->checkout->total_ticket_count = $this->checkout->cart->all_ticket_quantity_count();
1099
-            // now let's add the cart items to the $transaction
1100
-            foreach ($this->checkout->cart->get_tickets() as $line_item) {
1101
-                //do the following for each ticket of this type they selected
1102
-                for ($x = 1; $x <= $line_item->quantity(); $x++) {
1103
-                    $att_nmbr++;
1104
-                    /** @var EventEspresso\core\services\commands\registration\CreateRegistrationCommand $CreateRegistrationCommand */
1105
-                    $CreateRegistrationCommand = EE_Registry::instance()->create(
1106
-                        'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
1107
-                        array(
1108
-                            $transaction,
1109
-                            $line_item,
1110
-                            $att_nmbr,
1111
-                            $this->checkout->total_ticket_count,
1112
-                        )
1113
-                    );
1114
-                    // override capabilities for frontend registrations
1115
-                    if ( ! is_admin()) {
1116
-                        $CreateRegistrationCommand->setCapCheck(
1117
-                            new PublicCapabilities('', 'create_new_registration')
1118
-                        );
1119
-                    }
1120
-                    $registration = EE_Registry::instance()->BUS->execute($CreateRegistrationCommand);
1121
-                    if ( ! $registration instanceof EE_Registration) {
1122
-                        throw new InvalidEntityException($registration, 'EE_Registration');
1123
-                    }
1124
-                    $registrations[ $registration->ID() ] = $registration;
1125
-                }
1126
-            }
1127
-            $registration_processor->fix_reg_final_price_rounding_issue($transaction);
1128
-        }
1129
-        return $registrations;
1130
-    }
1131
-
1132
-
1133
-
1134
-    /**
1135
-     * sorts registrations by REG_count
1136
-     *
1137
-     * @access public
1138
-     * @param EE_Registration $reg_A
1139
-     * @param EE_Registration $reg_B
1140
-     * @return int
1141
-     */
1142
-    public static function sort_registrations_by_REG_count(EE_Registration $reg_A, EE_Registration $reg_B)
1143
-    {
1144
-        // this shouldn't ever happen within the same TXN, but oh well
1145
-        if ($reg_A->count() === $reg_B->count()) {
1146
-            return 0;
1147
-        }
1148
-        return ($reg_A->count() > $reg_B->count()) ? 1 : -1;
1149
-    }
1150
-
1151
-
1152
-
1153
-    /**
1154
-     *    _final_verifications
1155
-     * just makes sure that everything is set up correctly before proceeding
1156
-     *
1157
-     * @access    private
1158
-     * @return    bool
1159
-     * @throws EE_Error
1160
-     */
1161
-    private function _final_verifications()
1162
-    {
1163
-        // filter checkout
1164
-        $this->checkout = apply_filters(
1165
-            'FHEE__EED_Single_Page_Checkout___final_verifications__checkout',
1166
-            $this->checkout
1167
-        );
1168
-        //verify that current step is still set correctly
1169
-        if ( ! $this->checkout->current_step instanceof EE_SPCO_Reg_Step) {
1170
-            EE_Error::add_error(
1171
-                __('We\'re sorry but the registration process can not proceed because one or more registration steps were not setup correctly. Please refresh the page and try again or contact support.', 'event_espresso'),
1172
-                __FILE__,
1173
-                __FUNCTION__,
1174
-                __LINE__
1175
-            );
1176
-            return false;
1177
-        }
1178
-        // if returning to SPCO, then verify that primary registrant is set
1179
-        if ( ! empty($this->checkout->reg_url_link)) {
1180
-            $valid_registrant = $this->checkout->transaction->primary_registration();
1181
-            if ( ! $valid_registrant instanceof EE_Registration) {
1182
-                EE_Error::add_error(
1183
-                    __('We\'re sorry but there appears to be an error with the "reg_url_link" or the primary registrant for this transaction. Please refresh the page and try again or contact support.', 'event_espresso'),
1184
-                    __FILE__,
1185
-                    __FUNCTION__,
1186
-                    __LINE__
1187
-                );
1188
-                return false;
1189
-            }
1190
-            $valid_registrant = null;
1191
-            foreach (
1192
-                $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params) as $registration
1193
-            ) {
1194
-                if (
1195
-                    $registration instanceof EE_Registration
1196
-                    && $registration->reg_url_link() === $this->checkout->reg_url_link
1197
-                ) {
1198
-                    $valid_registrant = $registration;
1199
-                }
1200
-            }
1201
-            if ( ! $valid_registrant instanceof EE_Registration) {
1202
-                // hmmm... maybe we have the wrong session because the user is opening multiple tabs ?
1203
-                if (EED_Single_Page_Checkout::$_checkout_verified) {
1204
-                    // clear the session, mark the checkout as unverified, and try again
1205
-                    EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
1206
-                    EED_Single_Page_Checkout::$_initialized = false;
1207
-                    EED_Single_Page_Checkout::$_checkout_verified = false;
1208
-                    $this->_initialize();
1209
-                    EE_Error::reset_notices();
1210
-                    return false;
1211
-                }
1212
-                EE_Error::add_error(
1213
-                    __(
1214
-                        'We\'re sorry but there appears to be an error with the "reg_url_link" or the transaction itself. Please refresh the page and try again or contact support.',
1215
-                        'event_espresso'
1216
-                    ),
1217
-                    __FILE__,
1218
-                    __FUNCTION__,
1219
-                    __LINE__
1220
-                );
1221
-                return false;
1222
-            }
1223
-        }
1224
-        // now that things have been kinda sufficiently verified,
1225
-        // let's add the checkout to the session so that it's available to other systems
1226
-        EE_Registry::instance()->SSN->set_checkout($this->checkout);
1227
-        return true;
1228
-    }
1229
-
1230
-
1231
-
1232
-    /**
1233
-     *    _initialize_reg_steps
1234
-     * first makes sure that EE_Transaction_Processor::set_reg_step_initiated() is called as required
1235
-     * then loops thru all of the active reg steps and calls the initialize_reg_step() method
1236
-     *
1237
-     * @access    private
1238
-     * @param bool $reinitializing
1239
-     * @throws EE_Error
1240
-     */
1241
-    private function _initialize_reg_steps($reinitializing = false)
1242
-    {
1243
-        $this->checkout->set_reg_step_initiated($this->checkout->current_step);
1244
-        // loop thru all steps to call their individual "initialize" methods and set i18n strings for JS
1245
-        foreach ($this->checkout->reg_steps as $reg_step) {
1246
-            if ( ! $reg_step->initialize_reg_step()) {
1247
-                // if not initialized then maybe this step is being removed...
1248
-                if ( ! $reinitializing && $reg_step->is_current_step()) {
1249
-                    // if it was the current step, then we need to start over here
1250
-                    $this->_initialize_reg_steps(true);
1251
-                    return;
1252
-                }
1253
-                continue;
1254
-            }
1255
-            // add css and JS for current step
1256
-            $reg_step->enqueue_styles_and_scripts();
1257
-            // i18n
1258
-            $reg_step->translate_js_strings();
1259
-            if ($reg_step->is_current_step()) {
1260
-                // the text that appears on the reg step form submit button
1261
-                $reg_step->set_submit_button_text();
1262
-            }
1263
-        }
1264
-        // dynamically creates hook point like: AHEE__Single_Page_Checkout___initialize_reg_step__attendee_information
1265
-        do_action(
1266
-            "AHEE__Single_Page_Checkout___initialize_reg_step__{$this->checkout->current_step->slug()}",
1267
-            $this->checkout->current_step
1268
-        );
1269
-    }
1270
-
1271
-
1272
-
1273
-    /**
1274
-     * _check_form_submission
1275
-     *
1276
-     * @access private
1277
-     * @return boolean
1278
-     */
1279
-    private function _check_form_submission()
1280
-    {
1281
-        //does this request require the reg form to be generated ?
1282
-        if ($this->checkout->generate_reg_form) {
1283
-            // ever heard that song by Blue Rodeo ?
1284
-            try {
1285
-                $this->checkout->current_step->reg_form = $this->checkout->current_step->generate_reg_form();
1286
-                // if not displaying a form, then check for form submission
1287
-                if (
1288
-                    $this->checkout->process_form_submission
1289
-                    && $this->checkout->current_step->reg_form->was_submitted()
1290
-                ) {
1291
-                    // clear out any old data in case this step is being run again
1292
-                    $this->checkout->current_step->set_valid_data(array());
1293
-                    // capture submitted form data
1294
-                    $this->checkout->current_step->reg_form->receive_form_submission(
1295
-                        apply_filters(
1296
-                            'FHEE__Single_Page_Checkout___check_form_submission__request_params',
1297
-                            EE_Registry::instance()->REQ->params(),
1298
-                            $this->checkout
1299
-                        )
1300
-                    );
1301
-                    // validate submitted form data
1302
-                    if ( ! $this->checkout->continue_reg || ! $this->checkout->current_step->reg_form->is_valid()) {
1303
-                        // thou shall not pass !!!
1304
-                        $this->checkout->continue_reg = false;
1305
-                        // any form validation errors?
1306
-                        if ($this->checkout->current_step->reg_form->submission_error_message() !== '') {
1307
-                            $submission_error_messages = array();
1308
-                            // bad, bad, bad registrant
1309
-                            foreach (
1310
-                                $this->checkout->current_step->reg_form->get_validation_errors_accumulated()
1311
-                                as $validation_error
1312
-                            ) {
1313
-                                if ($validation_error instanceof EE_Validation_Error) {
1314
-                                    $submission_error_messages[] = sprintf(
1315
-                                        __('%s : %s', 'event_espresso'),
1316
-                                        $validation_error->get_form_section()->html_label_text(),
1317
-                                        $validation_error->getMessage()
1318
-                                    );
1319
-                                }
1320
-                            }
1321
-                            EE_Error::add_error(
1322
-                                implode('<br />', $submission_error_messages),
1323
-                                __FILE__, __FUNCTION__, __LINE__
1324
-                            );
1325
-                        }
1326
-                        // well not really... what will happen is
1327
-                        // we'll just get redirected back to redo the current step
1328
-                        $this->go_to_next_step();
1329
-                        return false;
1330
-                    }
1331
-                }
1332
-            } catch (EE_Error $e) {
1333
-                $e->get_error();
1334
-            }
1335
-        }
1336
-        return true;
1337
-    }
1338
-
1339
-
1340
-
1341
-    /**
1342
-     * _process_action
1343
-     *
1344
-     * @access private
1345
-     * @return void
1346
-     * @throws EE_Error
1347
-     */
1348
-    private function _process_form_action()
1349
-    {
1350
-        // what cha wanna do?
1351
-        switch ($this->checkout->action) {
1352
-            // AJAX next step reg form
1353
-            case 'display_spco_reg_step' :
1354
-                $this->checkout->redirect = false;
1355
-                if (EE_Registry::instance()->REQ->ajax) {
1356
-                    $this->checkout->json_response->set_reg_step_html(
1357
-                        $this->checkout->current_step->display_reg_form()
1358
-                    );
1359
-                }
1360
-                break;
1361
-            default :
1362
-                // meh... do one of those other steps first
1363
-                if (
1364
-                    ! empty($this->checkout->action)
1365
-                    && is_callable(array($this->checkout->current_step, $this->checkout->action))
1366
-                ) {
1367
-                    // dynamically creates hook point like:
1368
-                    //   AHEE__Single_Page_Checkout__before_attendee_information__process_reg_step
1369
-                    do_action(
1370
-                        "AHEE__Single_Page_Checkout__before_{$this->checkout->current_step->slug()}__{$this->checkout->action}",
1371
-                        $this->checkout->current_step
1372
-                    );
1373
-                    // call action on current step
1374
-                    if (call_user_func(array($this->checkout->current_step, $this->checkout->action))) {
1375
-                        // good registrant, you get to proceed
1376
-                        if (
1377
-                            $this->checkout->current_step->success_message() !== ''
1378
-                            && apply_filters(
1379
-                                'FHEE__Single_Page_Checkout___process_form_action__display_success',
1380
-                                false
1381
-                            )
1382
-                        ) {
1383
-                            EE_Error::add_success(
1384
-                                $this->checkout->current_step->success_message()
1385
-                                . '<br />' . $this->checkout->next_step->_instructions()
1386
-                            );
1387
-                        }
1388
-                        // pack it up, pack it in...
1389
-                        $this->_setup_redirect();
1390
-                    }
1391
-                    // dynamically creates hook point like:
1392
-                    //  AHEE__Single_Page_Checkout__after_payment_options__process_reg_step
1393
-                    do_action(
1394
-                        "AHEE__Single_Page_Checkout__after_{$this->checkout->current_step->slug()}__{$this->checkout->action}",
1395
-                        $this->checkout->current_step
1396
-                    );
1397
-                } else {
1398
-                    EE_Error::add_error(
1399
-                        sprintf(
1400
-                            __(
1401
-                                'The requested form action "%s" does not exist for the current "%s" registration step.',
1402
-                                'event_espresso'
1403
-                            ),
1404
-                            $this->checkout->action,
1405
-                            $this->checkout->current_step->name()
1406
-                        ),
1407
-                        __FILE__,
1408
-                        __FUNCTION__,
1409
-                        __LINE__
1410
-                    );
1411
-                }
1412
-            // end default
1413
-        }
1414
-        // store our progress so far
1415
-        $this->checkout->stash_transaction_and_checkout();
1416
-        // advance to the next step! If you pass GO, collect $200
1417
-        $this->go_to_next_step();
1418
-    }
1419
-
1420
-
1421
-
1422
-    /**
1423
-     *        add_styles_and_scripts
1424
-     *
1425
-     * @access        public
1426
-     * @return        void
1427
-     */
1428
-    public function add_styles_and_scripts()
1429
-    {
1430
-        // i18n
1431
-        $this->translate_js_strings();
1432
-        if ($this->checkout->admin_request) {
1433
-            add_action('admin_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10);
1434
-        } else {
1435
-            add_action('wp_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10);
1436
-        }
1437
-    }
1438
-
1439
-
1440
-
1441
-    /**
1442
-     *        translate_js_strings
1443
-     *
1444
-     * @access        public
1445
-     * @return        void
1446
-     */
1447
-    public function translate_js_strings()
1448
-    {
1449
-        EE_Registry::$i18n_js_strings['revisit'] = $this->checkout->revisit;
1450
-        EE_Registry::$i18n_js_strings['e_reg_url_link'] = $this->checkout->reg_url_link;
1451
-        EE_Registry::$i18n_js_strings['server_error'] = __(
1452
-            'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again or contact support.',
1453
-            'event_espresso'
1454
-        );
1455
-        EE_Registry::$i18n_js_strings['invalid_json_response'] = __(
1456
-            'An invalid response was returned from the server while attempting to process your request. Please refresh the page and try again or contact support.',
1457
-            'event_espresso'
1458
-        );
1459
-        EE_Registry::$i18n_js_strings['validation_error'] = __(
1460
-            'There appears to be a problem with the form validation configuration! Please check the admin settings or contact support.',
1461
-            'event_espresso'
1462
-        );
1463
-        EE_Registry::$i18n_js_strings['invalid_payment_method'] = __(
1464
-            'There appears to be a problem with the payment method configuration! Please refresh the page and try again or contact support.',
1465
-            'event_espresso'
1466
-        );
1467
-        EE_Registry::$i18n_js_strings['reg_step_error'] = __(
1468
-            'This registration step could not be completed. Please refresh the page and try again.',
1469
-            'event_espresso'
1470
-        );
1471
-        EE_Registry::$i18n_js_strings['invalid_coupon'] = __(
1472
-            'We\'re sorry but that coupon code does not appear to be valid. If this is incorrect, please contact the site administrator.',
1473
-            'event_espresso'
1474
-        );
1475
-        EE_Registry::$i18n_js_strings['process_registration'] = sprintf(
1476
-            __(
1477
-                'Please wait while we process your registration.%sDo not refresh the page or navigate away while this is happening.%sThank you for your patience.',
1478
-                'event_espresso'
1479
-            ),
1480
-            '<br/>',
1481
-            '<br/>'
1482
-        );
1483
-        EE_Registry::$i18n_js_strings['language'] = get_bloginfo('language');
1484
-        EE_Registry::$i18n_js_strings['EESID'] = EE_Registry::instance()->SSN->id();
1485
-        EE_Registry::$i18n_js_strings['currency'] = EE_Registry::instance()->CFG->currency;
1486
-        EE_Registry::$i18n_js_strings['datepicker_yearRange'] = '-150:+20';
1487
-        EE_Registry::$i18n_js_strings['timer_years'] = __('years', 'event_espresso');
1488
-        EE_Registry::$i18n_js_strings['timer_months'] = __('months', 'event_espresso');
1489
-        EE_Registry::$i18n_js_strings['timer_weeks'] = __('weeks', 'event_espresso');
1490
-        EE_Registry::$i18n_js_strings['timer_days'] = __('days', 'event_espresso');
1491
-        EE_Registry::$i18n_js_strings['timer_hours'] = __('hours', 'event_espresso');
1492
-        EE_Registry::$i18n_js_strings['timer_minutes'] = __('minutes', 'event_espresso');
1493
-        EE_Registry::$i18n_js_strings['timer_seconds'] = __('seconds', 'event_espresso');
1494
-        EE_Registry::$i18n_js_strings['timer_year'] = __('year', 'event_espresso');
1495
-        EE_Registry::$i18n_js_strings['timer_month'] = __('month', 'event_espresso');
1496
-        EE_Registry::$i18n_js_strings['timer_week'] = __('week', 'event_espresso');
1497
-        EE_Registry::$i18n_js_strings['timer_day'] = __('day', 'event_espresso');
1498
-        EE_Registry::$i18n_js_strings['timer_hour'] = __('hour', 'event_espresso');
1499
-        EE_Registry::$i18n_js_strings['timer_minute'] = __('minute', 'event_espresso');
1500
-        EE_Registry::$i18n_js_strings['timer_second'] = __('second', 'event_espresso');
1501
-        EE_Registry::$i18n_js_strings['registration_expiration_notice'] = sprintf(
1502
-            __(
1503
-                '%1$sWe\'re sorry, but your registration time has expired.%2$s%3$s%4$sIf you still wish to complete your registration, please return to the %5$sEvent List%6$sEvent List%7$s and reselect your tickets if available. Please except our apologies for any inconvenience this may have caused.%8$s',
1504
-                'event_espresso'
1505
-            ),
1506
-            '<h4 class="important-notice">',
1507
-            '</h4>',
1508
-            '<br />',
1509
-            '<p>',
1510
-            '<a href="' . get_post_type_archive_link('espresso_events') . '" title="',
1511
-            '">',
1512
-            '</a>',
1513
-            '</p>'
1514
-        );
1515
-        EE_Registry::$i18n_js_strings['ajax_submit'] = apply_filters(
1516
-            'FHEE__Single_Page_Checkout__translate_js_strings__ajax_submit',
1517
-            true
1518
-        );
1519
-        EE_Registry::$i18n_js_strings['session_extension'] = absint(
1520
-            apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS)
1521
-        );
1522
-        EE_Registry::$i18n_js_strings['session_expiration'] = gmdate(
1523
-            'M d, Y H:i:s',
1524
-            EE_Registry::instance()->SSN->expiration() + (get_option('gmt_offset') * HOUR_IN_SECONDS)
1525
-        );
1526
-    }
1527
-
1528
-
1529
-
1530
-    /**
1531
-     *    enqueue_styles_and_scripts
1532
-     *
1533
-     * @access        public
1534
-     * @return        void
1535
-     * @throws EE_Error
1536
-     */
1537
-    public function enqueue_styles_and_scripts()
1538
-    {
1539
-        // load css
1540
-        wp_register_style(
1541
-            'single_page_checkout',
1542
-            SPCO_CSS_URL . 'single_page_checkout.css',
1543
-            array('espresso_default'),
1544
-            EVENT_ESPRESSO_VERSION
1545
-        );
1546
-        wp_enqueue_style('single_page_checkout');
1547
-        // load JS
1548
-        wp_register_script(
1549
-            'jquery_plugin',
1550
-            EE_THIRD_PARTY_URL . 'jquery	.plugin.min.js',
1551
-            array('jquery'),
1552
-            '1.0.1',
1553
-            true
1554
-        );
1555
-        wp_register_script(
1556
-            'jquery_countdown',
1557
-            EE_THIRD_PARTY_URL . 'jquery	.countdown.min.js',
1558
-            array('jquery_plugin'),
1559
-            '2.0.2',
1560
-            true
1561
-        );
1562
-        wp_register_script(
1563
-            'single_page_checkout',
1564
-            SPCO_JS_URL . 'single_page_checkout.js',
1565
-            array('espresso_core', 'underscore', 'ee_form_section_validation', 'jquery_countdown'),
1566
-            EVENT_ESPRESSO_VERSION,
1567
-            true
1568
-        );
1569
-        if ($this->checkout->registration_form instanceof EE_Form_Section_Proper) {
1570
-            $this->checkout->registration_form->enqueue_js();
1571
-        }
1572
-        if ($this->checkout->current_step->reg_form instanceof EE_Form_Section_Proper) {
1573
-            $this->checkout->current_step->reg_form->enqueue_js();
1574
-        }
1575
-        wp_enqueue_script('single_page_checkout');
1576
-        /**
1577
-         * global action hook for enqueueing styles and scripts with
1578
-         * spco calls.
1579
-         */
1580
-        do_action('AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts', $this);
1581
-        /**
1582
-         * dynamic action hook for enqueueing styles and scripts with spco calls.
1583
-         * The hook will end up being something like:
1584
-         *      AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__attendee_information
1585
-         */
1586
-        do_action(
1587
-            'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__' . $this->checkout->current_step->slug(),
1588
-            $this
1589
-        );
1590
-    }
1591
-
1592
-
1593
-
1594
-    /**
1595
-     *    display the Registration Single Page Checkout Form
1596
-     *
1597
-     * @access    private
1598
-     * @return    void
1599
-     * @throws EE_Error
1600
-     */
1601
-    private function _display_spco_reg_form()
1602
-    {
1603
-        // if registering via the admin, just display the reg form for the current step
1604
-        if ($this->checkout->admin_request) {
1605
-            EE_Registry::instance()->REQ->add_output($this->checkout->current_step->display_reg_form());
1606
-        } else {
1607
-            // add powered by EE msg
1608
-            add_action('AHEE__SPCO__reg_form_footer', array('EED_Single_Page_Checkout', 'display_registration_footer'));
1609
-            $empty_cart = count(
1610
-                $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params)
1611
-            ) < 1;
1612
-            EE_Registry::$i18n_js_strings['empty_cart'] = $empty_cart;
1613
-            $cookies_not_set_msg = '';
1614
-            if ($empty_cart && ! isset($_COOKIE['ee_cookie_test'])) {
1615
-                $cookies_not_set_msg = apply_filters(
1616
-                    'FHEE__Single_Page_Checkout__display_spco_reg_form__cookies_not_set_msg',
1617
-                    sprintf(
1618
-                        __(
1619
-                            '%1$s%3$sIt appears your browser is not currently set to accept Cookies%4$s%5$sIn order to register for events, you need to enable cookies.%7$sIf you require assistance, then click the following link to learn how to %8$senable cookies%9$s%6$s%2$s',
1620
-                            'event_espresso'
1621
-                        ),
1622
-                        '<div class="ee-attention">',
1623
-                        '</div>',
1624
-                        '<h6 class="important-notice">',
1625
-                        '</h6>',
1626
-                        '<p>',
1627
-                        '</p>',
1628
-                        '<br />',
1629
-                        '<a href="http://www.whatarecookies.com/enable.asp" target="_blank">',
1630
-                        '</a>'
1631
-                    )
1632
-                );
1633
-            }
1634
-            $this->checkout->registration_form = new EE_Form_Section_Proper(
1635
-                array(
1636
-                    'name'            => 'single-page-checkout',
1637
-                    'html_id'         => 'ee-single-page-checkout-dv',
1638
-                    'layout_strategy' =>
1639
-                        new EE_Template_Layout(
1640
-                            array(
1641
-                                'layout_template_file' => SPCO_TEMPLATES_PATH . 'registration_page_wrapper.template.php',
1642
-                                'template_args'        => array(
1643
-                                    'empty_cart'              => $empty_cart,
1644
-                                    'revisit'                 => $this->checkout->revisit,
1645
-                                    'reg_steps'               => $this->checkout->reg_steps,
1646
-                                    'next_step'               => $this->checkout->next_step instanceof EE_SPCO_Reg_Step
1647
-                                        ? $this->checkout->next_step->slug()
1648
-                                        : '',
1649
-                                    'cancel_page_url'         => $this->checkout->cancel_page_url,
1650
-                                    'empty_msg'               => apply_filters(
1651
-                                        'FHEE__Single_Page_Checkout__display_spco_reg_form__empty_msg',
1652
-                                        sprintf(
1653
-                                            __(
1654
-                                                'You need to %1$sReturn to Events list%2$sselect at least one event%3$s before you can proceed with the registration process.',
1655
-                                                'event_espresso'
1656
-                                            ),
1657
-                                            '<a href="'
1658
-                                            . get_post_type_archive_link('espresso_events')
1659
-                                            . '" title="',
1660
-                                            '">',
1661
-                                            '</a>'
1662
-                                        )
1663
-                                    ),
1664
-                                    'cookies_not_set_msg'     => $cookies_not_set_msg,
1665
-                                    'registration_time_limit' => $this->checkout->get_registration_time_limit(),
1666
-                                    'session_expiration'      => gmdate(
1667
-                                        'M d, Y H:i:s',
1668
-                                        EE_Registry::instance()->SSN->expiration()
1669
-                                        + (get_option('gmt_offset') * HOUR_IN_SECONDS)
1670
-                                    ),
1671
-                                ),
1672
-                            )
1673
-                        ),
1674
-                )
1675
-            );
1676
-            // load template and add to output sent that gets filtered into the_content()
1677
-            EE_Registry::instance()->REQ->add_output($this->checkout->registration_form->get_html());
1678
-        }
1679
-    }
1680
-
1681
-
1682
-
1683
-    /**
1684
-     *    add_extra_finalize_registration_inputs
1685
-     *
1686
-     * @access    public
1687
-     * @param $next_step
1688
-     * @internal  param string $label
1689
-     * @return void
1690
-     */
1691
-    public function add_extra_finalize_registration_inputs($next_step)
1692
-    {
1693
-        if ($next_step === 'finalize_registration') {
1694
-            echo '<div id="spco-extra-finalize_registration-inputs-dv"></div>';
1695
-        }
1696
-    }
1697
-
1698
-
1699
-
1700
-    /**
1701
-     *    display_registration_footer
1702
-     *
1703
-     * @access    public
1704
-     * @return    string
1705
-     */
1706
-    public static function display_registration_footer()
1707
-    {
1708
-        if (
1709
-        apply_filters(
1710
-            'FHEE__EE_Front__Controller__show_reg_footer',
1711
-            EE_Registry::instance()->CFG->admin->show_reg_footer
1712
-        )
1713
-        ) {
1714
-            add_filter(
1715
-                'FHEE__EEH_Template__powered_by_event_espresso__url',
1716
-                function ($url) {
1717
-                    return apply_filters('FHEE__EE_Front_Controller__registration_footer__url', $url);
1718
-                }
1719
-            );
1720
-            echo apply_filters(
1721
-                'FHEE__EE_Front_Controller__display_registration_footer',
1722
-                \EEH_Template::powered_by_event_espresso(
1723
-                    '',
1724
-                    'espresso-registration-footer-dv',
1725
-                    array('utm_content' => 'registration_checkout')
1726
-                )
1727
-            );
1728
-        }
1729
-        return '';
1730
-    }
1731
-
1732
-
1733
-
1734
-    /**
1735
-     *    unlock_transaction
1736
-     *
1737
-     * @access    public
1738
-     * @return    void
1739
-     * @throws EE_Error
1740
-     */
1741
-    public function unlock_transaction()
1742
-    {
1743
-        if ($this->checkout->transaction instanceof EE_Transaction) {
1744
-            $this->checkout->transaction->unlock();
1745
-        }
1746
-    }
1747
-
1748
-
1749
-
1750
-    /**
1751
-     *        _setup_redirect
1752
-     *
1753
-     * @access    private
1754
-     * @return void
1755
-     */
1756
-    private function _setup_redirect()
1757
-    {
1758
-        if ($this->checkout->continue_reg && $this->checkout->next_step instanceof EE_SPCO_Reg_Step) {
1759
-            $this->checkout->redirect = true;
1760
-            if (empty($this->checkout->redirect_url)) {
1761
-                $this->checkout->redirect_url = $this->checkout->next_step->reg_step_url();
1762
-            }
1763
-            $this->checkout->redirect_url = apply_filters(
1764
-                'FHEE__EED_Single_Page_Checkout___setup_redirect__checkout_redirect_url',
1765
-                $this->checkout->redirect_url,
1766
-                $this->checkout
1767
-            );
1768
-        }
1769
-    }
1770
-
1771
-
1772
-
1773
-    /**
1774
-     *   handle ajax message responses and redirects
1775
-     *
1776
-     * @access public
1777
-     * @return void
1778
-     * @throws EE_Error
1779
-     */
1780
-    public function go_to_next_step()
1781
-    {
1782
-        if (EE_Registry::instance()->REQ->ajax) {
1783
-            // capture contents of output buffer we started earlier in the request, and insert into JSON response
1784
-            $this->checkout->json_response->set_unexpected_errors(ob_get_clean());
1785
-        }
1786
-        $this->unlock_transaction();
1787
-        // just return for these conditions
1788
-        if (
1789
-            $this->checkout->admin_request
1790
-            || $this->checkout->action === 'redirect_form'
1791
-            || $this->checkout->action === 'update_checkout'
1792
-        ) {
1793
-            return;
1794
-        }
1795
-        // AJAX response
1796
-        $this->_handle_json_response();
1797
-        // redirect to next step or the Thank You page
1798
-        $this->_handle_html_redirects();
1799
-        // hmmm... must be something wrong, so let's just display the form again !
1800
-        $this->_display_spco_reg_form();
1801
-    }
1802
-
1803
-
1804
-
1805
-    /**
1806
-     *   _handle_json_response
1807
-     *
1808
-     * @access protected
1809
-     * @return void
1810
-     */
1811
-    protected function _handle_json_response()
1812
-    {
1813
-        // if this is an ajax request
1814
-        if (EE_Registry::instance()->REQ->ajax) {
1815
-            // DEBUG LOG
1816
-            //$this->checkout->log(
1817
-            //	__CLASS__, __FUNCTION__, __LINE__,
1818
-            //	array(
1819
-            //		'json_response_redirect_url' => $this->checkout->json_response->redirect_url(),
1820
-            //		'redirect'                   => $this->checkout->redirect,
1821
-            //		'continue_reg'               => $this->checkout->continue_reg,
1822
-            //	)
1823
-            //);
1824
-            $this->checkout->json_response->set_registration_time_limit(
1825
-                $this->checkout->get_registration_time_limit()
1826
-            );
1827
-            $this->checkout->json_response->set_payment_amount($this->checkout->amount_owing);
1828
-            // just send the ajax (
1829
-            $json_response = apply_filters(
1830
-                'FHEE__EE_Single_Page_Checkout__JSON_response',
1831
-                $this->checkout->json_response
1832
-            );
1833
-            echo $json_response;
1834
-            exit();
1835
-        }
1836
-    }
1837
-
1838
-
1839
-
1840
-    /**
1841
-     *   _handle_redirects
1842
-     *
1843
-     * @access protected
1844
-     * @return void
1845
-     */
1846
-    protected function _handle_html_redirects()
1847
-    {
1848
-        // going somewhere ?
1849
-        if ($this->checkout->redirect && ! empty($this->checkout->redirect_url)) {
1850
-            // store notices in a transient
1851
-            EE_Error::get_notices(false, true, true);
1852
-            // DEBUG LOG
1853
-            //$this->checkout->log(
1854
-            //	__CLASS__, __FUNCTION__, __LINE__,
1855
-            //	array(
1856
-            //		'headers_sent' => headers_sent(),
1857
-            //		'redirect_url'     => $this->checkout->redirect_url,
1858
-            //		'headers_list'    => headers_list(),
1859
-            //	)
1860
-            //);
1861
-            wp_safe_redirect($this->checkout->redirect_url);
1862
-            exit();
1863
-        }
1864
-    }
1865
-
1866
-
1867
-
1868
-    /**
1869
-     *   set_checkout_anchor
1870
-     *
1871
-     * @access public
1872
-     * @return void
1873
-     */
1874
-    public function set_checkout_anchor()
1875
-    {
1876
-        echo '<a id="checkout" style="float: left; margin-left: -999em;"></a>';
1877
-    }
23
+	/**
24
+	 * $_initialized - has the SPCO controller already been initialized ?
25
+	 *
26
+	 * @access private
27
+	 * @var bool $_initialized
28
+	 */
29
+	private static $_initialized = false;
30
+
31
+
32
+	/**
33
+	 * $_checkout_verified - is the EE_Checkout verified as correct for this request ?
34
+	 *
35
+	 * @access private
36
+	 * @var bool $_valid_checkout
37
+	 */
38
+	private static $_checkout_verified = true;
39
+
40
+	/**
41
+	 *    $_reg_steps_array - holds initial array of reg steps
42
+	 *
43
+	 * @access private
44
+	 * @var array $_reg_steps_array
45
+	 */
46
+	private static $_reg_steps_array = array();
47
+
48
+	/**
49
+	 *    $checkout - EE_Checkout object for handling the properties of the current checkout process
50
+	 *
51
+	 * @access public
52
+	 * @var EE_Checkout $checkout
53
+	 */
54
+	public $checkout;
55
+
56
+
57
+
58
+	/**
59
+	 * @return EED_Module|EED_Single_Page_Checkout
60
+	 */
61
+	public static function instance()
62
+	{
63
+		add_filter('EED_Single_Page_Checkout__SPCO_active', '__return_true');
64
+		return parent::get_instance(__CLASS__);
65
+	}
66
+
67
+
68
+
69
+	/**
70
+	 * @return EE_CART
71
+	 */
72
+	public function cart()
73
+	{
74
+		return $this->checkout->cart;
75
+	}
76
+
77
+
78
+
79
+	/**
80
+	 * @return EE_Transaction
81
+	 */
82
+	public function transaction()
83
+	{
84
+		return $this->checkout->transaction;
85
+	}
86
+
87
+
88
+
89
+	/**
90
+	 *    set_hooks - for hooking into EE Core, other modules, etc
91
+	 *
92
+	 * @access    public
93
+	 * @return    void
94
+	 * @throws EE_Error
95
+	 */
96
+	public static function set_hooks()
97
+	{
98
+		EED_Single_Page_Checkout::set_definitions();
99
+	}
100
+
101
+
102
+
103
+	/**
104
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
105
+	 *
106
+	 * @access    public
107
+	 * @return    void
108
+	 * @throws EE_Error
109
+	 */
110
+	public static function set_hooks_admin()
111
+	{
112
+		EED_Single_Page_Checkout::set_definitions();
113
+		if ( ! (defined('DOING_AJAX') && DOING_AJAX)) {
114
+			return;
115
+		}
116
+		// going to start an output buffer in case anything gets accidentally output
117
+		// that might disrupt our JSON response
118
+		ob_start();
119
+		EED_Single_Page_Checkout::load_request_handler();
120
+		EED_Single_Page_Checkout::load_reg_steps();
121
+		// set ajax hooks
122
+		add_action('wp_ajax_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step'));
123
+		add_action('wp_ajax_nopriv_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step'));
124
+		add_action('wp_ajax_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step'));
125
+		add_action('wp_ajax_nopriv_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step'));
126
+		add_action('wp_ajax_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step'));
127
+		add_action('wp_ajax_nopriv_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step'));
128
+	}
129
+
130
+
131
+
132
+	/**
133
+	 *    process ajax request
134
+	 *
135
+	 * @param string $ajax_action
136
+	 * @throws EE_Error
137
+	 */
138
+	public static function process_ajax_request($ajax_action)
139
+	{
140
+		EE_Registry::instance()->REQ->set('action', $ajax_action);
141
+		EED_Single_Page_Checkout::instance()->_initialize();
142
+	}
143
+
144
+
145
+
146
+	/**
147
+	 *    ajax display registration step
148
+	 *
149
+	 * @throws EE_Error
150
+	 */
151
+	public static function display_reg_step()
152
+	{
153
+		EED_Single_Page_Checkout::process_ajax_request('display_spco_reg_step');
154
+	}
155
+
156
+
157
+
158
+	/**
159
+	 *    ajax process registration step
160
+	 *
161
+	 * @throws EE_Error
162
+	 */
163
+	public static function process_reg_step()
164
+	{
165
+		EED_Single_Page_Checkout::process_ajax_request('process_reg_step');
166
+	}
167
+
168
+
169
+
170
+	/**
171
+	 *    ajax process registration step
172
+	 *
173
+	 * @throws EE_Error
174
+	 */
175
+	public static function update_reg_step()
176
+	{
177
+		EED_Single_Page_Checkout::process_ajax_request('update_reg_step');
178
+	}
179
+
180
+
181
+
182
+	/**
183
+	 *   update_checkout
184
+	 *
185
+	 * @access public
186
+	 * @return void
187
+	 * @throws EE_Error
188
+	 */
189
+	public static function update_checkout()
190
+	{
191
+		EED_Single_Page_Checkout::process_ajax_request('update_checkout');
192
+	}
193
+
194
+
195
+
196
+	/**
197
+	 *    load_request_handler
198
+	 *
199
+	 * @access    public
200
+	 * @return    void
201
+	 */
202
+	public static function load_request_handler()
203
+	{
204
+		// load core Request_Handler class
205
+		if (EE_Registry::instance()->REQ !== null) {
206
+			EE_Registry::instance()->load_core('Request_Handler');
207
+		}
208
+	}
209
+
210
+
211
+
212
+	/**
213
+	 *    set_definitions
214
+	 *
215
+	 * @access    public
216
+	 * @return    void
217
+	 * @throws EE_Error
218
+	 */
219
+	public static function set_definitions()
220
+	{
221
+		if(defined('SPCO_BASE_PATH')) {
222
+			return;
223
+		}
224
+		define(
225
+			'SPCO_BASE_PATH',
226
+			rtrim(str_replace(array('\\', '/'), DS, plugin_dir_path(__FILE__)), DS) . DS
227
+		);
228
+		define('SPCO_CSS_URL', plugin_dir_url(__FILE__) . 'css' . DS);
229
+		define('SPCO_IMG_URL', plugin_dir_url(__FILE__) . 'img' . DS);
230
+		define('SPCO_JS_URL', plugin_dir_url(__FILE__) . 'js' . DS);
231
+		define('SPCO_INC_PATH', SPCO_BASE_PATH . 'inc' . DS);
232
+		define('SPCO_REG_STEPS_PATH', SPCO_BASE_PATH . 'reg_steps' . DS);
233
+		define('SPCO_TEMPLATES_PATH', SPCO_BASE_PATH . 'templates' . DS);
234
+		EEH_Autoloader::register_autoloaders_for_each_file_in_folder(SPCO_BASE_PATH, true);
235
+		EE_Registry::$i18n_js_strings['registration_expiration_notice'] = sprintf(
236
+			__('%1$sWe\'re sorry, but you\'re registration time has expired.%2$s%4$sIf you still wish to complete your registration, please return to the %5$sEvent List%6$sEvent List%7$s and reselect your tickets if available. Please except our apologies for any inconvenience this may have caused.%8$s',
237
+				'event_espresso'),
238
+			'<h4 class="important-notice">',
239
+			'</h4>',
240
+			'<br />',
241
+			'<p>',
242
+			'<a href="' . get_post_type_archive_link('espresso_events') . '" title="',
243
+			'">',
244
+			'</a>',
245
+			'</p>'
246
+		);
247
+	}
248
+
249
+
250
+
251
+	/**
252
+	 * load_reg_steps
253
+	 * loads and instantiates each reg step based on the EE_Registry::instance()->CFG->registration->reg_steps array
254
+	 *
255
+	 * @access    private
256
+	 * @throws EE_Error
257
+	 */
258
+	public static function load_reg_steps()
259
+	{
260
+		static $reg_steps_loaded = false;
261
+		if ($reg_steps_loaded) {
262
+			return;
263
+		}
264
+		// filter list of reg_steps
265
+		$reg_steps_to_load = (array)apply_filters(
266
+			'AHEE__SPCO__load_reg_steps__reg_steps_to_load',
267
+			EED_Single_Page_Checkout::get_reg_steps()
268
+		);
269
+		// sort by key (order)
270
+		ksort($reg_steps_to_load);
271
+		// loop through folders
272
+		foreach ($reg_steps_to_load as $order => $reg_step) {
273
+			// we need a
274
+			if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) {
275
+				// copy over to the reg_steps_array
276
+				EED_Single_Page_Checkout::$_reg_steps_array[$order] = $reg_step;
277
+				// register custom key route for each reg step
278
+				// ie: step=>"slug" - this is the entire reason we load the reg steps array now
279
+				EE_Config::register_route(
280
+					$reg_step['slug'],
281
+					'EED_Single_Page_Checkout',
282
+					'run',
283
+					'step'
284
+				);
285
+				// add AJAX or other hooks
286
+				if (isset($reg_step['has_hooks']) && $reg_step['has_hooks']) {
287
+					// setup autoloaders if necessary
288
+					if ( ! class_exists($reg_step['class_name'])) {
289
+						EEH_Autoloader::register_autoloaders_for_each_file_in_folder(
290
+							$reg_step['file_path'],
291
+							true
292
+						);
293
+					}
294
+					if (is_callable($reg_step['class_name'], 'set_hooks')) {
295
+						call_user_func(array($reg_step['class_name'], 'set_hooks'));
296
+					}
297
+				}
298
+			}
299
+		}
300
+		$reg_steps_loaded = true;
301
+	}
302
+
303
+
304
+
305
+	/**
306
+	 *    get_reg_steps
307
+	 *
308
+	 * @access    public
309
+	 * @return    array
310
+	 */
311
+	public static function get_reg_steps()
312
+	{
313
+		$reg_steps = EE_Registry::instance()->CFG->registration->reg_steps;
314
+		if (empty($reg_steps)) {
315
+			$reg_steps = array(
316
+				10  => array(
317
+					'file_path'  => SPCO_REG_STEPS_PATH . 'attendee_information',
318
+					'class_name' => 'EE_SPCO_Reg_Step_Attendee_Information',
319
+					'slug'       => 'attendee_information',
320
+					'has_hooks'  => false,
321
+				),
322
+				20  => array(
323
+					'file_path'  => SPCO_REG_STEPS_PATH . 'registration_confirmation',
324
+					'class_name' => 'EE_SPCO_Reg_Step_Registration_Confirmation',
325
+					'slug'       => 'registration_confirmation',
326
+					'has_hooks'  => false,
327
+				),
328
+				30  => array(
329
+					'file_path'  => SPCO_REG_STEPS_PATH . 'payment_options',
330
+					'class_name' => 'EE_SPCO_Reg_Step_Payment_Options',
331
+					'slug'       => 'payment_options',
332
+					'has_hooks'  => true,
333
+				),
334
+				999 => array(
335
+					'file_path'  => SPCO_REG_STEPS_PATH . 'finalize_registration',
336
+					'class_name' => 'EE_SPCO_Reg_Step_Finalize_Registration',
337
+					'slug'       => 'finalize_registration',
338
+					'has_hooks'  => false,
339
+				),
340
+			);
341
+		}
342
+		return $reg_steps;
343
+	}
344
+
345
+
346
+
347
+	/**
348
+	 *    registration_checkout_for_admin
349
+	 *
350
+	 * @access    public
351
+	 * @return    string
352
+	 * @throws EE_Error
353
+	 */
354
+	public static function registration_checkout_for_admin()
355
+	{
356
+		EED_Single_Page_Checkout::load_request_handler();
357
+		EE_Registry::instance()->REQ->set('step', 'attendee_information');
358
+		EE_Registry::instance()->REQ->set('action', 'display_spco_reg_step');
359
+		EE_Registry::instance()->REQ->set('process_form_submission', false);
360
+		EED_Single_Page_Checkout::instance()->_initialize();
361
+		EED_Single_Page_Checkout::instance()->_display_spco_reg_form();
362
+		return EE_Registry::instance()->REQ->get_output();
363
+	}
364
+
365
+
366
+
367
+	/**
368
+	 * process_registration_from_admin
369
+	 *
370
+	 * @access public
371
+	 * @return \EE_Transaction
372
+	 * @throws EE_Error
373
+	 */
374
+	public static function process_registration_from_admin()
375
+	{
376
+		EED_Single_Page_Checkout::load_request_handler();
377
+		EE_Registry::instance()->REQ->set('step', 'attendee_information');
378
+		EE_Registry::instance()->REQ->set('action', 'process_reg_step');
379
+		EE_Registry::instance()->REQ->set('process_form_submission', true);
380
+		EED_Single_Page_Checkout::instance()->_initialize();
381
+		if (EED_Single_Page_Checkout::instance()->checkout->current_step->completed()) {
382
+			$final_reg_step = end(EED_Single_Page_Checkout::instance()->checkout->reg_steps);
383
+			if ($final_reg_step instanceof EE_SPCO_Reg_Step_Finalize_Registration) {
384
+				EED_Single_Page_Checkout::instance()->checkout->set_reg_step_initiated($final_reg_step);
385
+				if ($final_reg_step->process_reg_step()) {
386
+					$final_reg_step->set_completed();
387
+					EED_Single_Page_Checkout::instance()->checkout->update_txn_reg_steps_array();
388
+					return EED_Single_Page_Checkout::instance()->checkout->transaction;
389
+				}
390
+			}
391
+		}
392
+		return null;
393
+	}
394
+
395
+
396
+
397
+	/**
398
+	 *    run
399
+	 *
400
+	 * @access    public
401
+	 * @param WP_Query $WP_Query
402
+	 * @return    void
403
+	 * @throws EE_Error
404
+	 */
405
+	public function run($WP_Query)
406
+	{
407
+		if (
408
+			$WP_Query instanceof WP_Query
409
+			&& $WP_Query->is_main_query()
410
+			&& apply_filters('FHEE__EED_Single_Page_Checkout__run', true)
411
+			&& $this->_is_reg_checkout()
412
+		) {
413
+			$this->_initialize();
414
+		}
415
+	}
416
+
417
+
418
+
419
+	/**
420
+	 * determines whether current url matches reg page url
421
+	 *
422
+	 * @return bool
423
+	 */
424
+	protected function _is_reg_checkout()
425
+	{
426
+		// get current permalink for reg page without any extra query args
427
+		$reg_page_url = \get_permalink(EE_Config::instance()->core->reg_page_id);
428
+		// get request URI for current request, but without the scheme or host
429
+		$current_request_uri = \EEH_URL::filter_input_server_url('REQUEST_URI');
430
+		$current_request_uri = html_entity_decode($current_request_uri);
431
+		// get array of query args from the current request URI
432
+		$query_args = \EEH_URL::get_query_string($current_request_uri);
433
+		// grab page id if it is set
434
+		$page_id = isset($query_args['page_id']) ? absint($query_args['page_id']) : 0;
435
+		// and remove the page id from the query args (we will re-add it later)
436
+		unset($query_args['page_id']);
437
+		// now strip all query args from current request URI
438
+		$current_request_uri = remove_query_arg(array_keys($query_args), $current_request_uri);
439
+		// and re-add the page id if it was set
440
+		if ($page_id) {
441
+			$current_request_uri = add_query_arg('page_id', $page_id, $current_request_uri);
442
+		}
443
+		// remove slashes and ?
444
+		$current_request_uri = trim($current_request_uri, '?/');
445
+		// is current request URI part of the known full reg page URL ?
446
+		return ! empty($current_request_uri) && strpos($reg_page_url, $current_request_uri) !== false;
447
+	}
448
+
449
+
450
+
451
+	/**
452
+	 * @param WP_Query $wp_query
453
+	 * @return    void
454
+	 * @throws EE_Error
455
+	 */
456
+	public static function init($wp_query)
457
+	{
458
+		EED_Single_Page_Checkout::instance()->run($wp_query);
459
+	}
460
+
461
+
462
+
463
+	/**
464
+	 *    _initialize - initial module setup
465
+	 *
466
+	 * @access    private
467
+	 * @throws EE_Error
468
+	 * @return    void
469
+	 */
470
+	private function _initialize()
471
+	{
472
+		// ensure SPCO doesn't run twice
473
+		if (EED_Single_Page_Checkout::$_initialized) {
474
+			return;
475
+		}
476
+		try {
477
+			EED_Single_Page_Checkout::load_reg_steps();
478
+			$this->_verify_session();
479
+			// setup the EE_Checkout object
480
+			$this->checkout = $this->_initialize_checkout();
481
+			// filter checkout
482
+			$this->checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize__checkout', $this->checkout);
483
+			// get the $_GET
484
+			$this->_get_request_vars();
485
+			if ($this->_block_bots()) {
486
+				return;
487
+			}
488
+			// filter continue_reg
489
+			$this->checkout->continue_reg = apply_filters(
490
+				'FHEE__EED_Single_Page_Checkout__init___continue_reg',
491
+				true,
492
+				$this->checkout
493
+			);
494
+			// load the reg steps array
495
+			if ( ! $this->_load_and_instantiate_reg_steps()) {
496
+				EED_Single_Page_Checkout::$_initialized = true;
497
+				return;
498
+			}
499
+			// set the current step
500
+			$this->checkout->set_current_step($this->checkout->step);
501
+			// and the next step
502
+			$this->checkout->set_next_step();
503
+			// verify that everything has been setup correctly
504
+			if ( ! ($this->_verify_transaction_and_get_registrations() && $this->_final_verifications())) {
505
+				EED_Single_Page_Checkout::$_initialized = true;
506
+				return;
507
+			}
508
+			// lock the transaction
509
+			$this->checkout->transaction->lock();
510
+			// make sure all of our cached objects are added to their respective model entity mappers
511
+			$this->checkout->refresh_all_entities();
512
+			// set amount owing
513
+			$this->checkout->amount_owing = $this->checkout->transaction->remaining();
514
+			// initialize each reg step, which gives them the chance to potentially alter the process
515
+			$this->_initialize_reg_steps();
516
+			// DEBUG LOG
517
+			//$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
518
+			// get reg form
519
+			if( ! $this->_check_form_submission()) {
520
+				EED_Single_Page_Checkout::$_initialized = true;
521
+				return;
522
+			}
523
+			// checkout the action!!!
524
+			$this->_process_form_action();
525
+			// add some style and make it dance
526
+			$this->add_styles_and_scripts();
527
+			// kk... SPCO has successfully run
528
+			EED_Single_Page_Checkout::$_initialized = true;
529
+			// set no cache headers and constants
530
+			EE_System::do_not_cache();
531
+			// add anchor
532
+			add_action('loop_start', array($this, 'set_checkout_anchor'), 1);
533
+			// remove transaction lock
534
+			add_action('shutdown', array($this, 'unlock_transaction'), 1);
535
+		} catch (Exception $e) {
536
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
537
+		}
538
+	}
539
+
540
+
541
+
542
+	/**
543
+	 *    _verify_session
544
+	 * checks that the session is valid and not expired
545
+	 *
546
+	 * @access    private
547
+	 * @throws EE_Error
548
+	 */
549
+	private function _verify_session()
550
+	{
551
+		if ( ! EE_Registry::instance()->SSN instanceof EE_Session) {
552
+			throw new EE_Error(__('The EE_Session class could not be loaded.', 'event_espresso'));
553
+		}
554
+		$clear_session_requested = filter_var(
555
+			EE_Registry::instance()->REQ->get('clear_session', false),
556
+			FILTER_VALIDATE_BOOLEAN
557
+		);
558
+		// is session still valid ?
559
+		if ($clear_session_requested
560
+			|| ( EE_Registry::instance()->SSN->expired()
561
+			  && EE_Registry::instance()->REQ->get('e_reg_url_link', '') === ''
562
+			)
563
+		) {
564
+			$this->checkout = new EE_Checkout();
565
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
566
+			// EE_Registry::instance()->SSN->reset_cart();
567
+			// EE_Registry::instance()->SSN->reset_checkout();
568
+			// EE_Registry::instance()->SSN->reset_transaction();
569
+			if (! $clear_session_requested) {
570
+				EE_Error::add_attention(
571
+					EE_Registry::$i18n_js_strings['registration_expiration_notice'],
572
+					__FILE__, __FUNCTION__, __LINE__
573
+				);
574
+			}
575
+			// EE_Registry::instance()->SSN->reset_expired();
576
+		}
577
+	}
578
+
579
+
580
+
581
+	/**
582
+	 *    _initialize_checkout
583
+	 * loads and instantiates EE_Checkout
584
+	 *
585
+	 * @access    private
586
+	 * @throws EE_Error
587
+	 * @return EE_Checkout
588
+	 */
589
+	private function _initialize_checkout()
590
+	{
591
+		// look in session for existing checkout
592
+		/** @type EE_Checkout $checkout */
593
+		$checkout = EE_Registry::instance()->SSN->checkout();
594
+		// verify
595
+		if ( ! $checkout instanceof EE_Checkout) {
596
+			// instantiate EE_Checkout object for handling the properties of the current checkout process
597
+			$checkout = EE_Registry::instance()->load_file(
598
+				SPCO_INC_PATH,
599
+				'EE_Checkout',
600
+				'class', array(),
601
+				false
602
+			);
603
+		} else {
604
+			if ($checkout->current_step->is_final_step() && $checkout->exit_spco() === true) {
605
+				$this->unlock_transaction();
606
+				wp_safe_redirect($checkout->redirect_url);
607
+				exit();
608
+			}
609
+		}
610
+		$checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize_checkout__checkout', $checkout);
611
+		// verify again
612
+		if ( ! $checkout instanceof EE_Checkout) {
613
+			throw new EE_Error(__('The EE_Checkout class could not be loaded.', 'event_espresso'));
614
+		}
615
+		// reset anything that needs a clean slate for each request
616
+		$checkout->reset_for_current_request();
617
+		return $checkout;
618
+	}
619
+
620
+
621
+
622
+	/**
623
+	 *    _get_request_vars
624
+	 *
625
+	 * @access    private
626
+	 * @return    void
627
+	 * @throws EE_Error
628
+	 */
629
+	private function _get_request_vars()
630
+	{
631
+		// load classes
632
+		EED_Single_Page_Checkout::load_request_handler();
633
+		//make sure this request is marked as belonging to EE
634
+		EE_Registry::instance()->REQ->set_espresso_page(true);
635
+		// which step is being requested ?
636
+		$this->checkout->step = EE_Registry::instance()->REQ->get('step', $this->_get_first_step());
637
+		// which step is being edited ?
638
+		$this->checkout->edit_step = EE_Registry::instance()->REQ->get('edit_step', '');
639
+		// and what we're doing on the current step
640
+		$this->checkout->action = EE_Registry::instance()->REQ->get('action', 'display_spco_reg_step');
641
+		// timestamp
642
+		$this->checkout->uts = EE_Registry::instance()->REQ->get('uts', 0);
643
+		// returning to edit ?
644
+		$this->checkout->reg_url_link = EE_Registry::instance()->REQ->get('e_reg_url_link', '');
645
+		// or some other kind of revisit ?
646
+		$this->checkout->revisit = filter_var(
647
+			EE_Registry::instance()->REQ->get('revisit', false),
648
+			FILTER_VALIDATE_BOOLEAN
649
+		);
650
+		// and whether or not to generate a reg form for this request
651
+		$this->checkout->generate_reg_form = filter_var(
652
+			EE_Registry::instance()->REQ->get('generate_reg_form', true),
653
+			FILTER_VALIDATE_BOOLEAN
654
+		);
655
+		// and whether or not to process a reg form submission for this request
656
+		$this->checkout->process_form_submission = filter_var(
657
+			EE_Registry::instance()->REQ->get(
658
+				'process_form_submission',
659
+				$this->checkout->action === 'process_reg_step'
660
+			),
661
+			FILTER_VALIDATE_BOOLEAN
662
+		);
663
+		$this->checkout->process_form_submission = filter_var(
664
+			$this->checkout->action !== 'display_spco_reg_step'
665
+				? $this->checkout->process_form_submission
666
+				: false,
667
+			FILTER_VALIDATE_BOOLEAN
668
+		);
669
+		// $this->_display_request_vars();
670
+	}
671
+
672
+
673
+
674
+	/**
675
+	 *  _display_request_vars
676
+	 *
677
+	 * @access    protected
678
+	 * @return    void
679
+	 */
680
+	protected function _display_request_vars()
681
+	{
682
+		if ( ! WP_DEBUG) {
683
+			return;
684
+		}
685
+		EEH_Debug_Tools::printr($_REQUEST, '$_REQUEST', __FILE__, __LINE__);
686
+		EEH_Debug_Tools::printr($this->checkout->step, '$this->checkout->step', __FILE__, __LINE__);
687
+		EEH_Debug_Tools::printr($this->checkout->edit_step, '$this->checkout->edit_step', __FILE__, __LINE__);
688
+		EEH_Debug_Tools::printr($this->checkout->action, '$this->checkout->action', __FILE__, __LINE__);
689
+		EEH_Debug_Tools::printr($this->checkout->reg_url_link, '$this->checkout->reg_url_link', __FILE__, __LINE__);
690
+		EEH_Debug_Tools::printr($this->checkout->revisit, '$this->checkout->revisit', __FILE__, __LINE__);
691
+		EEH_Debug_Tools::printr($this->checkout->generate_reg_form, '$this->checkout->generate_reg_form', __FILE__, __LINE__);
692
+		EEH_Debug_Tools::printr($this->checkout->process_form_submission, '$this->checkout->process_form_submission', __FILE__, __LINE__);
693
+	}
694
+
695
+
696
+
697
+	/**
698
+	 * _block_bots
699
+	 * checks that the incoming request has either of the following set:
700
+	 *  a uts (unix timestamp) which indicates that the request was redirected from the Ticket Selector
701
+	 *  a REG URL Link, which indicates that the request is a return visit to SPCO for a valid TXN
702
+	 * so if you're not coming from the Ticket Selector nor returning for a valid IP...
703
+	 * then where you coming from man?
704
+	 *
705
+	 * @return boolean
706
+	 */
707
+	private function _block_bots()
708
+	{
709
+		$invalid_checkout_access = EED_Invalid_Checkout_Access::getInvalidCheckoutAccess();
710
+		if ($invalid_checkout_access->checkoutAccessIsInvalid($this->checkout)) {
711
+			return true;
712
+		}
713
+		return false;
714
+	}
715
+
716
+
717
+
718
+	/**
719
+	 *    _get_first_step
720
+	 *  gets slug for first step in $_reg_steps_array
721
+	 *
722
+	 * @access    private
723
+	 * @throws EE_Error
724
+	 * @return    string
725
+	 */
726
+	private function _get_first_step()
727
+	{
728
+		$first_step = reset(EED_Single_Page_Checkout::$_reg_steps_array);
729
+		return isset($first_step['slug']) ? $first_step['slug'] : 'attendee_information';
730
+	}
731
+
732
+
733
+
734
+	/**
735
+	 *    _load_and_instantiate_reg_steps
736
+	 *  instantiates each reg step based on the loaded reg_steps array
737
+	 *
738
+	 * @access    private
739
+	 * @throws EE_Error
740
+	 * @return    bool
741
+	 */
742
+	private function _load_and_instantiate_reg_steps()
743
+	{
744
+		do_action('AHEE__Single_Page_Checkout___load_and_instantiate_reg_steps__start', $this->checkout);
745
+		// have reg_steps already been instantiated ?
746
+		if (
747
+			empty($this->checkout->reg_steps)
748
+			|| apply_filters('FHEE__Single_Page_Checkout__load_reg_steps__reload_reg_steps', false, $this->checkout)
749
+		) {
750
+			// if not, then loop through raw reg steps array
751
+			foreach (EED_Single_Page_Checkout::$_reg_steps_array as $order => $reg_step) {
752
+				if ( ! $this->_load_and_instantiate_reg_step($reg_step, $order)) {
753
+					return false;
754
+				}
755
+			}
756
+			EE_Registry::instance()->CFG->registration->skip_reg_confirmation = true;
757
+			EE_Registry::instance()->CFG->registration->reg_confirmation_last = true;
758
+			// skip the registration_confirmation page ?
759
+			if (EE_Registry::instance()->CFG->registration->skip_reg_confirmation) {
760
+				// just remove it from the reg steps array
761
+				$this->checkout->remove_reg_step('registration_confirmation', false);
762
+			} else if (
763
+				isset($this->checkout->reg_steps['registration_confirmation'])
764
+				&& EE_Registry::instance()->CFG->registration->reg_confirmation_last
765
+			) {
766
+				// set the order to something big like 100
767
+				$this->checkout->set_reg_step_order('registration_confirmation', 100);
768
+			}
769
+			// filter the array for good luck
770
+			$this->checkout->reg_steps = apply_filters(
771
+				'FHEE__Single_Page_Checkout__load_reg_steps__reg_steps',
772
+				$this->checkout->reg_steps
773
+			);
774
+			// finally re-sort based on the reg step class order properties
775
+			$this->checkout->sort_reg_steps();
776
+		} else {
777
+			foreach ($this->checkout->reg_steps as $reg_step) {
778
+				// set all current step stati to FALSE
779
+				$reg_step->set_is_current_step(false);
780
+			}
781
+		}
782
+		if (empty($this->checkout->reg_steps)) {
783
+			EE_Error::add_error(
784
+				__('No Reg Steps were loaded..', 'event_espresso'),
785
+				__FILE__, __FUNCTION__, __LINE__
786
+			);
787
+			return false;
788
+		}
789
+		// make reg step details available to JS
790
+		$this->checkout->set_reg_step_JSON_info();
791
+		return true;
792
+	}
793
+
794
+
795
+
796
+	/**
797
+	 *     _load_and_instantiate_reg_step
798
+	 *
799
+	 * @access    private
800
+	 * @param array $reg_step
801
+	 * @param int   $order
802
+	 * @return bool
803
+	 */
804
+	private function _load_and_instantiate_reg_step($reg_step = array(), $order = 0)
805
+	{
806
+		// we need a file_path, class_name, and slug to add a reg step
807
+		if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) {
808
+			// if editing a specific step, but this is NOT that step... (and it's not the 'finalize_registration' step)
809
+			if (
810
+				$this->checkout->reg_url_link
811
+				&& $this->checkout->step !== $reg_step['slug']
812
+				&& $reg_step['slug'] !== 'finalize_registration'
813
+				// normally at this point we would NOT load the reg step, but this filter can change that
814
+				&& apply_filters(
815
+					'FHEE__Single_Page_Checkout___load_and_instantiate_reg_step__bypass_reg_step',
816
+					true,
817
+					$reg_step,
818
+					$this->checkout
819
+				)
820
+			) {
821
+				return true;
822
+			}
823
+			// instantiate step class using file path and class name
824
+			$reg_step_obj = EE_Registry::instance()->load_file(
825
+				$reg_step['file_path'],
826
+				$reg_step['class_name'],
827
+				'class',
828
+				$this->checkout,
829
+				false
830
+			);
831
+			// did we gets the goods ?
832
+			if ($reg_step_obj instanceof EE_SPCO_Reg_Step) {
833
+				// set reg step order based on config
834
+				$reg_step_obj->set_order($order);
835
+				// add instantiated reg step object to the master reg steps array
836
+				$this->checkout->add_reg_step($reg_step_obj);
837
+			} else {
838
+				EE_Error::add_error(
839
+					__('The current step could not be set.', 'event_espresso'),
840
+					__FILE__, __FUNCTION__, __LINE__
841
+				);
842
+				return false;
843
+			}
844
+		} else {
845
+			if (WP_DEBUG) {
846
+				EE_Error::add_error(
847
+					sprintf(
848
+						__(
849
+							'A registration step could not be loaded. One or more of the following data points is invalid:%4$s%5$sFile Path: %1$s%6$s%5$sClass Name: %2$s%6$s%5$sSlug: %3$s%6$s%7$s',
850
+							'event_espresso'
851
+						),
852
+						isset($reg_step['file_path']) ? $reg_step['file_path'] : '',
853
+						isset($reg_step['class_name']) ? $reg_step['class_name'] : '',
854
+						isset($reg_step['slug']) ? $reg_step['slug'] : '',
855
+						'<ul>',
856
+						'<li>',
857
+						'</li>',
858
+						'</ul>'
859
+					),
860
+					__FILE__, __FUNCTION__, __LINE__
861
+				);
862
+			}
863
+			return false;
864
+		}
865
+		return true;
866
+	}
867
+
868
+
869
+	/**
870
+	 * _verify_transaction_and_get_registrations
871
+	 *
872
+	 * @access private
873
+	 * @return bool
874
+	 * @throws InvalidDataTypeException
875
+	 * @throws InvalidEntityException
876
+	 * @throws EE_Error
877
+	 */
878
+	private function _verify_transaction_and_get_registrations()
879
+	{
880
+		// was there already a valid transaction in the checkout from the session ?
881
+		if ( ! $this->checkout->transaction instanceof EE_Transaction) {
882
+			// get transaction from db or session
883
+			$this->checkout->transaction = $this->checkout->reg_url_link && ! is_admin()
884
+				? $this->_get_transaction_and_cart_for_previous_visit()
885
+				: $this->_get_cart_for_current_session_and_setup_new_transaction();
886
+			if ( ! $this->checkout->transaction instanceof EE_Transaction) {
887
+				EE_Error::add_error(
888
+					__('Your Registration and Transaction information could not be retrieved from the db.',
889
+						'event_espresso'),
890
+					__FILE__, __FUNCTION__, __LINE__
891
+				);
892
+				$this->checkout->transaction = EE_Transaction::new_instance();
893
+				// add some style and make it dance
894
+				$this->add_styles_and_scripts();
895
+				EED_Single_Page_Checkout::$_initialized = true;
896
+				return false;
897
+			}
898
+			// and the registrations for the transaction
899
+			$this->_get_registrations($this->checkout->transaction);
900
+		}
901
+		return true;
902
+	}
903
+
904
+
905
+
906
+	/**
907
+	 * _get_transaction_and_cart_for_previous_visit
908
+	 *
909
+	 * @access private
910
+	 * @return mixed EE_Transaction|NULL
911
+	 */
912
+	private function _get_transaction_and_cart_for_previous_visit()
913
+	{
914
+		/** @var $TXN_model EEM_Transaction */
915
+		$TXN_model = EE_Registry::instance()->load_model('Transaction');
916
+		// because the reg_url_link is present in the request,
917
+		// this is a return visit to SPCO, so we'll get the transaction data from the db
918
+		$transaction = $TXN_model->get_transaction_from_reg_url_link($this->checkout->reg_url_link);
919
+		// verify transaction
920
+		if ($transaction instanceof EE_Transaction) {
921
+			// and get the cart that was used for that transaction
922
+			$this->checkout->cart = $this->_get_cart_for_transaction($transaction);
923
+			return $transaction;
924
+		}
925
+		EE_Error::add_error(
926
+			__('Your Registration and Transaction information could not be retrieved from the db.', 'event_espresso'),
927
+			__FILE__, __FUNCTION__, __LINE__
928
+		);
929
+		return null;
930
+
931
+	}
932
+
933
+
934
+
935
+	/**
936
+	 * _get_cart_for_transaction
937
+	 *
938
+	 * @access private
939
+	 * @param EE_Transaction $transaction
940
+	 * @return EE_Cart
941
+	 */
942
+	private function _get_cart_for_transaction($transaction)
943
+	{
944
+		return $this->checkout->get_cart_for_transaction($transaction);
945
+	}
946
+
947
+
948
+
949
+	/**
950
+	 * get_cart_for_transaction
951
+	 *
952
+	 * @access public
953
+	 * @param EE_Transaction $transaction
954
+	 * @return EE_Cart
955
+	 */
956
+	public function get_cart_for_transaction(EE_Transaction $transaction)
957
+	{
958
+		return $this->checkout->get_cart_for_transaction($transaction);
959
+	}
960
+
961
+
962
+
963
+	/**
964
+	 * _get_transaction_and_cart_for_current_session
965
+	 *    generates a new EE_Transaction object and adds it to the $_transaction property.
966
+	 *
967
+	 * @access private
968
+	 * @return EE_Transaction
969
+	 * @throws EE_Error
970
+	 */
971
+	private function _get_cart_for_current_session_and_setup_new_transaction()
972
+	{
973
+		//  if there's no transaction, then this is the FIRST visit to SPCO
974
+		// so load up the cart ( passing nothing for the TXN because it doesn't exist yet )
975
+		$this->checkout->cart = $this->_get_cart_for_transaction(null);
976
+		// and then create a new transaction
977
+		$transaction = $this->_initialize_transaction();
978
+		// verify transaction
979
+		if ($transaction instanceof EE_Transaction) {
980
+			// save it so that we have an ID for other objects to use
981
+			$transaction->save();
982
+			// and save TXN data to the cart
983
+			$this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn($transaction->ID());
984
+		} else {
985
+			EE_Error::add_error(
986
+				__('A Valid Transaction could not be initialized.', 'event_espresso'),
987
+				__FILE__, __FUNCTION__, __LINE__
988
+			);
989
+		}
990
+		return $transaction;
991
+	}
992
+
993
+
994
+
995
+	/**
996
+	 *    generates a new EE_Transaction object and adds it to the $_transaction property.
997
+	 *
998
+	 * @access private
999
+	 * @return mixed EE_Transaction|NULL
1000
+	 */
1001
+	private function _initialize_transaction()
1002
+	{
1003
+		try {
1004
+			// ensure cart totals have been calculated
1005
+			$this->checkout->cart->get_grand_total()->recalculate_total_including_taxes();
1006
+			// grab the cart grand total
1007
+			$cart_total = $this->checkout->cart->get_cart_grand_total();
1008
+			// create new TXN
1009
+			$transaction = EE_Transaction::new_instance(
1010
+				array(
1011
+					'TXN_reg_steps' => $this->checkout->initialize_txn_reg_steps_array(),
1012
+					'TXN_total'     => $cart_total > 0 ? $cart_total : 0,
1013
+					'TXN_paid'      => 0,
1014
+					'STS_ID'        => EEM_Transaction::failed_status_code,
1015
+				)
1016
+			);
1017
+			// save it so that we have an ID for other objects to use
1018
+			$transaction->save();
1019
+			// set cron job for following up on TXNs after their session has expired
1020
+			EE_Cron_Tasks::schedule_expired_transaction_check(
1021
+				EE_Registry::instance()->SSN->expiration() + 1,
1022
+				$transaction->ID()
1023
+			);
1024
+			return $transaction;
1025
+		} catch (Exception $e) {
1026
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1027
+		}
1028
+		return null;
1029
+	}
1030
+
1031
+
1032
+	/**
1033
+	 * _get_registrations
1034
+	 *
1035
+	 * @access private
1036
+	 * @param EE_Transaction $transaction
1037
+	 * @return void
1038
+	 * @throws InvalidDataTypeException
1039
+	 * @throws InvalidEntityException
1040
+	 * @throws EE_Error
1041
+	 */
1042
+	private function _get_registrations(EE_Transaction $transaction)
1043
+	{
1044
+		// first step: grab the registrants  { : o
1045
+		$registrations = $transaction->registrations($this->checkout->reg_cache_where_params, true);
1046
+		// verify registrations have been set
1047
+		if (empty($registrations)) {
1048
+			// if no cached registrations, then check the db
1049
+			$registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false);
1050
+			// still nothing ? well as long as this isn't a revisit
1051
+			if (empty($registrations) && ! $this->checkout->revisit) {
1052
+				// generate new registrations from scratch
1053
+				$registrations = $this->_initialize_registrations($transaction);
1054
+			}
1055
+		}
1056
+		// sort by their original registration order
1057
+		usort($registrations, array('EED_Single_Page_Checkout', 'sort_registrations_by_REG_count'));
1058
+		// then loop thru the array
1059
+		foreach ($registrations as $registration) {
1060
+			// verify each registration
1061
+			if ($registration instanceof EE_Registration) {
1062
+				// we display all attendee info for the primary registrant
1063
+				if ($this->checkout->reg_url_link === $registration->reg_url_link()
1064
+					&& $registration->is_primary_registrant()
1065
+				) {
1066
+					$this->checkout->primary_revisit = true;
1067
+					break;
1068
+				}
1069
+				if ($this->checkout->revisit
1070
+						   && $this->checkout->reg_url_link !== $registration->reg_url_link()
1071
+				) {
1072
+					// but hide info if it doesn't belong to you
1073
+					$transaction->clear_cache('Registration', $registration->ID());
1074
+				}
1075
+				$this->checkout->set_reg_status_updated($registration->ID(), false);
1076
+			}
1077
+		}
1078
+	}
1079
+
1080
+
1081
+	/**
1082
+	 *    adds related EE_Registration objects for each ticket in the cart to the current EE_Transaction object
1083
+	 *
1084
+	 * @access private
1085
+	 * @param EE_Transaction $transaction
1086
+	 * @return    array
1087
+	 * @throws InvalidDataTypeException
1088
+	 * @throws InvalidEntityException
1089
+	 * @throws EE_Error
1090
+	 */
1091
+	private function _initialize_registrations(EE_Transaction $transaction)
1092
+	{
1093
+		$att_nmbr = 0;
1094
+		$registrations = array();
1095
+		if ($transaction instanceof EE_Transaction) {
1096
+			/** @type EE_Registration_Processor $registration_processor */
1097
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1098
+			$this->checkout->total_ticket_count = $this->checkout->cart->all_ticket_quantity_count();
1099
+			// now let's add the cart items to the $transaction
1100
+			foreach ($this->checkout->cart->get_tickets() as $line_item) {
1101
+				//do the following for each ticket of this type they selected
1102
+				for ($x = 1; $x <= $line_item->quantity(); $x++) {
1103
+					$att_nmbr++;
1104
+					/** @var EventEspresso\core\services\commands\registration\CreateRegistrationCommand $CreateRegistrationCommand */
1105
+					$CreateRegistrationCommand = EE_Registry::instance()->create(
1106
+						'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
1107
+						array(
1108
+							$transaction,
1109
+							$line_item,
1110
+							$att_nmbr,
1111
+							$this->checkout->total_ticket_count,
1112
+						)
1113
+					);
1114
+					// override capabilities for frontend registrations
1115
+					if ( ! is_admin()) {
1116
+						$CreateRegistrationCommand->setCapCheck(
1117
+							new PublicCapabilities('', 'create_new_registration')
1118
+						);
1119
+					}
1120
+					$registration = EE_Registry::instance()->BUS->execute($CreateRegistrationCommand);
1121
+					if ( ! $registration instanceof EE_Registration) {
1122
+						throw new InvalidEntityException($registration, 'EE_Registration');
1123
+					}
1124
+					$registrations[ $registration->ID() ] = $registration;
1125
+				}
1126
+			}
1127
+			$registration_processor->fix_reg_final_price_rounding_issue($transaction);
1128
+		}
1129
+		return $registrations;
1130
+	}
1131
+
1132
+
1133
+
1134
+	/**
1135
+	 * sorts registrations by REG_count
1136
+	 *
1137
+	 * @access public
1138
+	 * @param EE_Registration $reg_A
1139
+	 * @param EE_Registration $reg_B
1140
+	 * @return int
1141
+	 */
1142
+	public static function sort_registrations_by_REG_count(EE_Registration $reg_A, EE_Registration $reg_B)
1143
+	{
1144
+		// this shouldn't ever happen within the same TXN, but oh well
1145
+		if ($reg_A->count() === $reg_B->count()) {
1146
+			return 0;
1147
+		}
1148
+		return ($reg_A->count() > $reg_B->count()) ? 1 : -1;
1149
+	}
1150
+
1151
+
1152
+
1153
+	/**
1154
+	 *    _final_verifications
1155
+	 * just makes sure that everything is set up correctly before proceeding
1156
+	 *
1157
+	 * @access    private
1158
+	 * @return    bool
1159
+	 * @throws EE_Error
1160
+	 */
1161
+	private function _final_verifications()
1162
+	{
1163
+		// filter checkout
1164
+		$this->checkout = apply_filters(
1165
+			'FHEE__EED_Single_Page_Checkout___final_verifications__checkout',
1166
+			$this->checkout
1167
+		);
1168
+		//verify that current step is still set correctly
1169
+		if ( ! $this->checkout->current_step instanceof EE_SPCO_Reg_Step) {
1170
+			EE_Error::add_error(
1171
+				__('We\'re sorry but the registration process can not proceed because one or more registration steps were not setup correctly. Please refresh the page and try again or contact support.', 'event_espresso'),
1172
+				__FILE__,
1173
+				__FUNCTION__,
1174
+				__LINE__
1175
+			);
1176
+			return false;
1177
+		}
1178
+		// if returning to SPCO, then verify that primary registrant is set
1179
+		if ( ! empty($this->checkout->reg_url_link)) {
1180
+			$valid_registrant = $this->checkout->transaction->primary_registration();
1181
+			if ( ! $valid_registrant instanceof EE_Registration) {
1182
+				EE_Error::add_error(
1183
+					__('We\'re sorry but there appears to be an error with the "reg_url_link" or the primary registrant for this transaction. Please refresh the page and try again or contact support.', 'event_espresso'),
1184
+					__FILE__,
1185
+					__FUNCTION__,
1186
+					__LINE__
1187
+				);
1188
+				return false;
1189
+			}
1190
+			$valid_registrant = null;
1191
+			foreach (
1192
+				$this->checkout->transaction->registrations($this->checkout->reg_cache_where_params) as $registration
1193
+			) {
1194
+				if (
1195
+					$registration instanceof EE_Registration
1196
+					&& $registration->reg_url_link() === $this->checkout->reg_url_link
1197
+				) {
1198
+					$valid_registrant = $registration;
1199
+				}
1200
+			}
1201
+			if ( ! $valid_registrant instanceof EE_Registration) {
1202
+				// hmmm... maybe we have the wrong session because the user is opening multiple tabs ?
1203
+				if (EED_Single_Page_Checkout::$_checkout_verified) {
1204
+					// clear the session, mark the checkout as unverified, and try again
1205
+					EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
1206
+					EED_Single_Page_Checkout::$_initialized = false;
1207
+					EED_Single_Page_Checkout::$_checkout_verified = false;
1208
+					$this->_initialize();
1209
+					EE_Error::reset_notices();
1210
+					return false;
1211
+				}
1212
+				EE_Error::add_error(
1213
+					__(
1214
+						'We\'re sorry but there appears to be an error with the "reg_url_link" or the transaction itself. Please refresh the page and try again or contact support.',
1215
+						'event_espresso'
1216
+					),
1217
+					__FILE__,
1218
+					__FUNCTION__,
1219
+					__LINE__
1220
+				);
1221
+				return false;
1222
+			}
1223
+		}
1224
+		// now that things have been kinda sufficiently verified,
1225
+		// let's add the checkout to the session so that it's available to other systems
1226
+		EE_Registry::instance()->SSN->set_checkout($this->checkout);
1227
+		return true;
1228
+	}
1229
+
1230
+
1231
+
1232
+	/**
1233
+	 *    _initialize_reg_steps
1234
+	 * first makes sure that EE_Transaction_Processor::set_reg_step_initiated() is called as required
1235
+	 * then loops thru all of the active reg steps and calls the initialize_reg_step() method
1236
+	 *
1237
+	 * @access    private
1238
+	 * @param bool $reinitializing
1239
+	 * @throws EE_Error
1240
+	 */
1241
+	private function _initialize_reg_steps($reinitializing = false)
1242
+	{
1243
+		$this->checkout->set_reg_step_initiated($this->checkout->current_step);
1244
+		// loop thru all steps to call their individual "initialize" methods and set i18n strings for JS
1245
+		foreach ($this->checkout->reg_steps as $reg_step) {
1246
+			if ( ! $reg_step->initialize_reg_step()) {
1247
+				// if not initialized then maybe this step is being removed...
1248
+				if ( ! $reinitializing && $reg_step->is_current_step()) {
1249
+					// if it was the current step, then we need to start over here
1250
+					$this->_initialize_reg_steps(true);
1251
+					return;
1252
+				}
1253
+				continue;
1254
+			}
1255
+			// add css and JS for current step
1256
+			$reg_step->enqueue_styles_and_scripts();
1257
+			// i18n
1258
+			$reg_step->translate_js_strings();
1259
+			if ($reg_step->is_current_step()) {
1260
+				// the text that appears on the reg step form submit button
1261
+				$reg_step->set_submit_button_text();
1262
+			}
1263
+		}
1264
+		// dynamically creates hook point like: AHEE__Single_Page_Checkout___initialize_reg_step__attendee_information
1265
+		do_action(
1266
+			"AHEE__Single_Page_Checkout___initialize_reg_step__{$this->checkout->current_step->slug()}",
1267
+			$this->checkout->current_step
1268
+		);
1269
+	}
1270
+
1271
+
1272
+
1273
+	/**
1274
+	 * _check_form_submission
1275
+	 *
1276
+	 * @access private
1277
+	 * @return boolean
1278
+	 */
1279
+	private function _check_form_submission()
1280
+	{
1281
+		//does this request require the reg form to be generated ?
1282
+		if ($this->checkout->generate_reg_form) {
1283
+			// ever heard that song by Blue Rodeo ?
1284
+			try {
1285
+				$this->checkout->current_step->reg_form = $this->checkout->current_step->generate_reg_form();
1286
+				// if not displaying a form, then check for form submission
1287
+				if (
1288
+					$this->checkout->process_form_submission
1289
+					&& $this->checkout->current_step->reg_form->was_submitted()
1290
+				) {
1291
+					// clear out any old data in case this step is being run again
1292
+					$this->checkout->current_step->set_valid_data(array());
1293
+					// capture submitted form data
1294
+					$this->checkout->current_step->reg_form->receive_form_submission(
1295
+						apply_filters(
1296
+							'FHEE__Single_Page_Checkout___check_form_submission__request_params',
1297
+							EE_Registry::instance()->REQ->params(),
1298
+							$this->checkout
1299
+						)
1300
+					);
1301
+					// validate submitted form data
1302
+					if ( ! $this->checkout->continue_reg || ! $this->checkout->current_step->reg_form->is_valid()) {
1303
+						// thou shall not pass !!!
1304
+						$this->checkout->continue_reg = false;
1305
+						// any form validation errors?
1306
+						if ($this->checkout->current_step->reg_form->submission_error_message() !== '') {
1307
+							$submission_error_messages = array();
1308
+							// bad, bad, bad registrant
1309
+							foreach (
1310
+								$this->checkout->current_step->reg_form->get_validation_errors_accumulated()
1311
+								as $validation_error
1312
+							) {
1313
+								if ($validation_error instanceof EE_Validation_Error) {
1314
+									$submission_error_messages[] = sprintf(
1315
+										__('%s : %s', 'event_espresso'),
1316
+										$validation_error->get_form_section()->html_label_text(),
1317
+										$validation_error->getMessage()
1318
+									);
1319
+								}
1320
+							}
1321
+							EE_Error::add_error(
1322
+								implode('<br />', $submission_error_messages),
1323
+								__FILE__, __FUNCTION__, __LINE__
1324
+							);
1325
+						}
1326
+						// well not really... what will happen is
1327
+						// we'll just get redirected back to redo the current step
1328
+						$this->go_to_next_step();
1329
+						return false;
1330
+					}
1331
+				}
1332
+			} catch (EE_Error $e) {
1333
+				$e->get_error();
1334
+			}
1335
+		}
1336
+		return true;
1337
+	}
1338
+
1339
+
1340
+
1341
+	/**
1342
+	 * _process_action
1343
+	 *
1344
+	 * @access private
1345
+	 * @return void
1346
+	 * @throws EE_Error
1347
+	 */
1348
+	private function _process_form_action()
1349
+	{
1350
+		// what cha wanna do?
1351
+		switch ($this->checkout->action) {
1352
+			// AJAX next step reg form
1353
+			case 'display_spco_reg_step' :
1354
+				$this->checkout->redirect = false;
1355
+				if (EE_Registry::instance()->REQ->ajax) {
1356
+					$this->checkout->json_response->set_reg_step_html(
1357
+						$this->checkout->current_step->display_reg_form()
1358
+					);
1359
+				}
1360
+				break;
1361
+			default :
1362
+				// meh... do one of those other steps first
1363
+				if (
1364
+					! empty($this->checkout->action)
1365
+					&& is_callable(array($this->checkout->current_step, $this->checkout->action))
1366
+				) {
1367
+					// dynamically creates hook point like:
1368
+					//   AHEE__Single_Page_Checkout__before_attendee_information__process_reg_step
1369
+					do_action(
1370
+						"AHEE__Single_Page_Checkout__before_{$this->checkout->current_step->slug()}__{$this->checkout->action}",
1371
+						$this->checkout->current_step
1372
+					);
1373
+					// call action on current step
1374
+					if (call_user_func(array($this->checkout->current_step, $this->checkout->action))) {
1375
+						// good registrant, you get to proceed
1376
+						if (
1377
+							$this->checkout->current_step->success_message() !== ''
1378
+							&& apply_filters(
1379
+								'FHEE__Single_Page_Checkout___process_form_action__display_success',
1380
+								false
1381
+							)
1382
+						) {
1383
+							EE_Error::add_success(
1384
+								$this->checkout->current_step->success_message()
1385
+								. '<br />' . $this->checkout->next_step->_instructions()
1386
+							);
1387
+						}
1388
+						// pack it up, pack it in...
1389
+						$this->_setup_redirect();
1390
+					}
1391
+					// dynamically creates hook point like:
1392
+					//  AHEE__Single_Page_Checkout__after_payment_options__process_reg_step
1393
+					do_action(
1394
+						"AHEE__Single_Page_Checkout__after_{$this->checkout->current_step->slug()}__{$this->checkout->action}",
1395
+						$this->checkout->current_step
1396
+					);
1397
+				} else {
1398
+					EE_Error::add_error(
1399
+						sprintf(
1400
+							__(
1401
+								'The requested form action "%s" does not exist for the current "%s" registration step.',
1402
+								'event_espresso'
1403
+							),
1404
+							$this->checkout->action,
1405
+							$this->checkout->current_step->name()
1406
+						),
1407
+						__FILE__,
1408
+						__FUNCTION__,
1409
+						__LINE__
1410
+					);
1411
+				}
1412
+			// end default
1413
+		}
1414
+		// store our progress so far
1415
+		$this->checkout->stash_transaction_and_checkout();
1416
+		// advance to the next step! If you pass GO, collect $200
1417
+		$this->go_to_next_step();
1418
+	}
1419
+
1420
+
1421
+
1422
+	/**
1423
+	 *        add_styles_and_scripts
1424
+	 *
1425
+	 * @access        public
1426
+	 * @return        void
1427
+	 */
1428
+	public function add_styles_and_scripts()
1429
+	{
1430
+		// i18n
1431
+		$this->translate_js_strings();
1432
+		if ($this->checkout->admin_request) {
1433
+			add_action('admin_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10);
1434
+		} else {
1435
+			add_action('wp_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10);
1436
+		}
1437
+	}
1438
+
1439
+
1440
+
1441
+	/**
1442
+	 *        translate_js_strings
1443
+	 *
1444
+	 * @access        public
1445
+	 * @return        void
1446
+	 */
1447
+	public function translate_js_strings()
1448
+	{
1449
+		EE_Registry::$i18n_js_strings['revisit'] = $this->checkout->revisit;
1450
+		EE_Registry::$i18n_js_strings['e_reg_url_link'] = $this->checkout->reg_url_link;
1451
+		EE_Registry::$i18n_js_strings['server_error'] = __(
1452
+			'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again or contact support.',
1453
+			'event_espresso'
1454
+		);
1455
+		EE_Registry::$i18n_js_strings['invalid_json_response'] = __(
1456
+			'An invalid response was returned from the server while attempting to process your request. Please refresh the page and try again or contact support.',
1457
+			'event_espresso'
1458
+		);
1459
+		EE_Registry::$i18n_js_strings['validation_error'] = __(
1460
+			'There appears to be a problem with the form validation configuration! Please check the admin settings or contact support.',
1461
+			'event_espresso'
1462
+		);
1463
+		EE_Registry::$i18n_js_strings['invalid_payment_method'] = __(
1464
+			'There appears to be a problem with the payment method configuration! Please refresh the page and try again or contact support.',
1465
+			'event_espresso'
1466
+		);
1467
+		EE_Registry::$i18n_js_strings['reg_step_error'] = __(
1468
+			'This registration step could not be completed. Please refresh the page and try again.',
1469
+			'event_espresso'
1470
+		);
1471
+		EE_Registry::$i18n_js_strings['invalid_coupon'] = __(
1472
+			'We\'re sorry but that coupon code does not appear to be valid. If this is incorrect, please contact the site administrator.',
1473
+			'event_espresso'
1474
+		);
1475
+		EE_Registry::$i18n_js_strings['process_registration'] = sprintf(
1476
+			__(
1477
+				'Please wait while we process your registration.%sDo not refresh the page or navigate away while this is happening.%sThank you for your patience.',
1478
+				'event_espresso'
1479
+			),
1480
+			'<br/>',
1481
+			'<br/>'
1482
+		);
1483
+		EE_Registry::$i18n_js_strings['language'] = get_bloginfo('language');
1484
+		EE_Registry::$i18n_js_strings['EESID'] = EE_Registry::instance()->SSN->id();
1485
+		EE_Registry::$i18n_js_strings['currency'] = EE_Registry::instance()->CFG->currency;
1486
+		EE_Registry::$i18n_js_strings['datepicker_yearRange'] = '-150:+20';
1487
+		EE_Registry::$i18n_js_strings['timer_years'] = __('years', 'event_espresso');
1488
+		EE_Registry::$i18n_js_strings['timer_months'] = __('months', 'event_espresso');
1489
+		EE_Registry::$i18n_js_strings['timer_weeks'] = __('weeks', 'event_espresso');
1490
+		EE_Registry::$i18n_js_strings['timer_days'] = __('days', 'event_espresso');
1491
+		EE_Registry::$i18n_js_strings['timer_hours'] = __('hours', 'event_espresso');
1492
+		EE_Registry::$i18n_js_strings['timer_minutes'] = __('minutes', 'event_espresso');
1493
+		EE_Registry::$i18n_js_strings['timer_seconds'] = __('seconds', 'event_espresso');
1494
+		EE_Registry::$i18n_js_strings['timer_year'] = __('year', 'event_espresso');
1495
+		EE_Registry::$i18n_js_strings['timer_month'] = __('month', 'event_espresso');
1496
+		EE_Registry::$i18n_js_strings['timer_week'] = __('week', 'event_espresso');
1497
+		EE_Registry::$i18n_js_strings['timer_day'] = __('day', 'event_espresso');
1498
+		EE_Registry::$i18n_js_strings['timer_hour'] = __('hour', 'event_espresso');
1499
+		EE_Registry::$i18n_js_strings['timer_minute'] = __('minute', 'event_espresso');
1500
+		EE_Registry::$i18n_js_strings['timer_second'] = __('second', 'event_espresso');
1501
+		EE_Registry::$i18n_js_strings['registration_expiration_notice'] = sprintf(
1502
+			__(
1503
+				'%1$sWe\'re sorry, but your registration time has expired.%2$s%3$s%4$sIf you still wish to complete your registration, please return to the %5$sEvent List%6$sEvent List%7$s and reselect your tickets if available. Please except our apologies for any inconvenience this may have caused.%8$s',
1504
+				'event_espresso'
1505
+			),
1506
+			'<h4 class="important-notice">',
1507
+			'</h4>',
1508
+			'<br />',
1509
+			'<p>',
1510
+			'<a href="' . get_post_type_archive_link('espresso_events') . '" title="',
1511
+			'">',
1512
+			'</a>',
1513
+			'</p>'
1514
+		);
1515
+		EE_Registry::$i18n_js_strings['ajax_submit'] = apply_filters(
1516
+			'FHEE__Single_Page_Checkout__translate_js_strings__ajax_submit',
1517
+			true
1518
+		);
1519
+		EE_Registry::$i18n_js_strings['session_extension'] = absint(
1520
+			apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS)
1521
+		);
1522
+		EE_Registry::$i18n_js_strings['session_expiration'] = gmdate(
1523
+			'M d, Y H:i:s',
1524
+			EE_Registry::instance()->SSN->expiration() + (get_option('gmt_offset') * HOUR_IN_SECONDS)
1525
+		);
1526
+	}
1527
+
1528
+
1529
+
1530
+	/**
1531
+	 *    enqueue_styles_and_scripts
1532
+	 *
1533
+	 * @access        public
1534
+	 * @return        void
1535
+	 * @throws EE_Error
1536
+	 */
1537
+	public function enqueue_styles_and_scripts()
1538
+	{
1539
+		// load css
1540
+		wp_register_style(
1541
+			'single_page_checkout',
1542
+			SPCO_CSS_URL . 'single_page_checkout.css',
1543
+			array('espresso_default'),
1544
+			EVENT_ESPRESSO_VERSION
1545
+		);
1546
+		wp_enqueue_style('single_page_checkout');
1547
+		// load JS
1548
+		wp_register_script(
1549
+			'jquery_plugin',
1550
+			EE_THIRD_PARTY_URL . 'jquery	.plugin.min.js',
1551
+			array('jquery'),
1552
+			'1.0.1',
1553
+			true
1554
+		);
1555
+		wp_register_script(
1556
+			'jquery_countdown',
1557
+			EE_THIRD_PARTY_URL . 'jquery	.countdown.min.js',
1558
+			array('jquery_plugin'),
1559
+			'2.0.2',
1560
+			true
1561
+		);
1562
+		wp_register_script(
1563
+			'single_page_checkout',
1564
+			SPCO_JS_URL . 'single_page_checkout.js',
1565
+			array('espresso_core', 'underscore', 'ee_form_section_validation', 'jquery_countdown'),
1566
+			EVENT_ESPRESSO_VERSION,
1567
+			true
1568
+		);
1569
+		if ($this->checkout->registration_form instanceof EE_Form_Section_Proper) {
1570
+			$this->checkout->registration_form->enqueue_js();
1571
+		}
1572
+		if ($this->checkout->current_step->reg_form instanceof EE_Form_Section_Proper) {
1573
+			$this->checkout->current_step->reg_form->enqueue_js();
1574
+		}
1575
+		wp_enqueue_script('single_page_checkout');
1576
+		/**
1577
+		 * global action hook for enqueueing styles and scripts with
1578
+		 * spco calls.
1579
+		 */
1580
+		do_action('AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts', $this);
1581
+		/**
1582
+		 * dynamic action hook for enqueueing styles and scripts with spco calls.
1583
+		 * The hook will end up being something like:
1584
+		 *      AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__attendee_information
1585
+		 */
1586
+		do_action(
1587
+			'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__' . $this->checkout->current_step->slug(),
1588
+			$this
1589
+		);
1590
+	}
1591
+
1592
+
1593
+
1594
+	/**
1595
+	 *    display the Registration Single Page Checkout Form
1596
+	 *
1597
+	 * @access    private
1598
+	 * @return    void
1599
+	 * @throws EE_Error
1600
+	 */
1601
+	private function _display_spco_reg_form()
1602
+	{
1603
+		// if registering via the admin, just display the reg form for the current step
1604
+		if ($this->checkout->admin_request) {
1605
+			EE_Registry::instance()->REQ->add_output($this->checkout->current_step->display_reg_form());
1606
+		} else {
1607
+			// add powered by EE msg
1608
+			add_action('AHEE__SPCO__reg_form_footer', array('EED_Single_Page_Checkout', 'display_registration_footer'));
1609
+			$empty_cart = count(
1610
+				$this->checkout->transaction->registrations($this->checkout->reg_cache_where_params)
1611
+			) < 1;
1612
+			EE_Registry::$i18n_js_strings['empty_cart'] = $empty_cart;
1613
+			$cookies_not_set_msg = '';
1614
+			if ($empty_cart && ! isset($_COOKIE['ee_cookie_test'])) {
1615
+				$cookies_not_set_msg = apply_filters(
1616
+					'FHEE__Single_Page_Checkout__display_spco_reg_form__cookies_not_set_msg',
1617
+					sprintf(
1618
+						__(
1619
+							'%1$s%3$sIt appears your browser is not currently set to accept Cookies%4$s%5$sIn order to register for events, you need to enable cookies.%7$sIf you require assistance, then click the following link to learn how to %8$senable cookies%9$s%6$s%2$s',
1620
+							'event_espresso'
1621
+						),
1622
+						'<div class="ee-attention">',
1623
+						'</div>',
1624
+						'<h6 class="important-notice">',
1625
+						'</h6>',
1626
+						'<p>',
1627
+						'</p>',
1628
+						'<br />',
1629
+						'<a href="http://www.whatarecookies.com/enable.asp" target="_blank">',
1630
+						'</a>'
1631
+					)
1632
+				);
1633
+			}
1634
+			$this->checkout->registration_form = new EE_Form_Section_Proper(
1635
+				array(
1636
+					'name'            => 'single-page-checkout',
1637
+					'html_id'         => 'ee-single-page-checkout-dv',
1638
+					'layout_strategy' =>
1639
+						new EE_Template_Layout(
1640
+							array(
1641
+								'layout_template_file' => SPCO_TEMPLATES_PATH . 'registration_page_wrapper.template.php',
1642
+								'template_args'        => array(
1643
+									'empty_cart'              => $empty_cart,
1644
+									'revisit'                 => $this->checkout->revisit,
1645
+									'reg_steps'               => $this->checkout->reg_steps,
1646
+									'next_step'               => $this->checkout->next_step instanceof EE_SPCO_Reg_Step
1647
+										? $this->checkout->next_step->slug()
1648
+										: '',
1649
+									'cancel_page_url'         => $this->checkout->cancel_page_url,
1650
+									'empty_msg'               => apply_filters(
1651
+										'FHEE__Single_Page_Checkout__display_spco_reg_form__empty_msg',
1652
+										sprintf(
1653
+											__(
1654
+												'You need to %1$sReturn to Events list%2$sselect at least one event%3$s before you can proceed with the registration process.',
1655
+												'event_espresso'
1656
+											),
1657
+											'<a href="'
1658
+											. get_post_type_archive_link('espresso_events')
1659
+											. '" title="',
1660
+											'">',
1661
+											'</a>'
1662
+										)
1663
+									),
1664
+									'cookies_not_set_msg'     => $cookies_not_set_msg,
1665
+									'registration_time_limit' => $this->checkout->get_registration_time_limit(),
1666
+									'session_expiration'      => gmdate(
1667
+										'M d, Y H:i:s',
1668
+										EE_Registry::instance()->SSN->expiration()
1669
+										+ (get_option('gmt_offset') * HOUR_IN_SECONDS)
1670
+									),
1671
+								),
1672
+							)
1673
+						),
1674
+				)
1675
+			);
1676
+			// load template and add to output sent that gets filtered into the_content()
1677
+			EE_Registry::instance()->REQ->add_output($this->checkout->registration_form->get_html());
1678
+		}
1679
+	}
1680
+
1681
+
1682
+
1683
+	/**
1684
+	 *    add_extra_finalize_registration_inputs
1685
+	 *
1686
+	 * @access    public
1687
+	 * @param $next_step
1688
+	 * @internal  param string $label
1689
+	 * @return void
1690
+	 */
1691
+	public function add_extra_finalize_registration_inputs($next_step)
1692
+	{
1693
+		if ($next_step === 'finalize_registration') {
1694
+			echo '<div id="spco-extra-finalize_registration-inputs-dv"></div>';
1695
+		}
1696
+	}
1697
+
1698
+
1699
+
1700
+	/**
1701
+	 *    display_registration_footer
1702
+	 *
1703
+	 * @access    public
1704
+	 * @return    string
1705
+	 */
1706
+	public static function display_registration_footer()
1707
+	{
1708
+		if (
1709
+		apply_filters(
1710
+			'FHEE__EE_Front__Controller__show_reg_footer',
1711
+			EE_Registry::instance()->CFG->admin->show_reg_footer
1712
+		)
1713
+		) {
1714
+			add_filter(
1715
+				'FHEE__EEH_Template__powered_by_event_espresso__url',
1716
+				function ($url) {
1717
+					return apply_filters('FHEE__EE_Front_Controller__registration_footer__url', $url);
1718
+				}
1719
+			);
1720
+			echo apply_filters(
1721
+				'FHEE__EE_Front_Controller__display_registration_footer',
1722
+				\EEH_Template::powered_by_event_espresso(
1723
+					'',
1724
+					'espresso-registration-footer-dv',
1725
+					array('utm_content' => 'registration_checkout')
1726
+				)
1727
+			);
1728
+		}
1729
+		return '';
1730
+	}
1731
+
1732
+
1733
+
1734
+	/**
1735
+	 *    unlock_transaction
1736
+	 *
1737
+	 * @access    public
1738
+	 * @return    void
1739
+	 * @throws EE_Error
1740
+	 */
1741
+	public function unlock_transaction()
1742
+	{
1743
+		if ($this->checkout->transaction instanceof EE_Transaction) {
1744
+			$this->checkout->transaction->unlock();
1745
+		}
1746
+	}
1747
+
1748
+
1749
+
1750
+	/**
1751
+	 *        _setup_redirect
1752
+	 *
1753
+	 * @access    private
1754
+	 * @return void
1755
+	 */
1756
+	private function _setup_redirect()
1757
+	{
1758
+		if ($this->checkout->continue_reg && $this->checkout->next_step instanceof EE_SPCO_Reg_Step) {
1759
+			$this->checkout->redirect = true;
1760
+			if (empty($this->checkout->redirect_url)) {
1761
+				$this->checkout->redirect_url = $this->checkout->next_step->reg_step_url();
1762
+			}
1763
+			$this->checkout->redirect_url = apply_filters(
1764
+				'FHEE__EED_Single_Page_Checkout___setup_redirect__checkout_redirect_url',
1765
+				$this->checkout->redirect_url,
1766
+				$this->checkout
1767
+			);
1768
+		}
1769
+	}
1770
+
1771
+
1772
+
1773
+	/**
1774
+	 *   handle ajax message responses and redirects
1775
+	 *
1776
+	 * @access public
1777
+	 * @return void
1778
+	 * @throws EE_Error
1779
+	 */
1780
+	public function go_to_next_step()
1781
+	{
1782
+		if (EE_Registry::instance()->REQ->ajax) {
1783
+			// capture contents of output buffer we started earlier in the request, and insert into JSON response
1784
+			$this->checkout->json_response->set_unexpected_errors(ob_get_clean());
1785
+		}
1786
+		$this->unlock_transaction();
1787
+		// just return for these conditions
1788
+		if (
1789
+			$this->checkout->admin_request
1790
+			|| $this->checkout->action === 'redirect_form'
1791
+			|| $this->checkout->action === 'update_checkout'
1792
+		) {
1793
+			return;
1794
+		}
1795
+		// AJAX response
1796
+		$this->_handle_json_response();
1797
+		// redirect to next step or the Thank You page
1798
+		$this->_handle_html_redirects();
1799
+		// hmmm... must be something wrong, so let's just display the form again !
1800
+		$this->_display_spco_reg_form();
1801
+	}
1802
+
1803
+
1804
+
1805
+	/**
1806
+	 *   _handle_json_response
1807
+	 *
1808
+	 * @access protected
1809
+	 * @return void
1810
+	 */
1811
+	protected function _handle_json_response()
1812
+	{
1813
+		// if this is an ajax request
1814
+		if (EE_Registry::instance()->REQ->ajax) {
1815
+			// DEBUG LOG
1816
+			//$this->checkout->log(
1817
+			//	__CLASS__, __FUNCTION__, __LINE__,
1818
+			//	array(
1819
+			//		'json_response_redirect_url' => $this->checkout->json_response->redirect_url(),
1820
+			//		'redirect'                   => $this->checkout->redirect,
1821
+			//		'continue_reg'               => $this->checkout->continue_reg,
1822
+			//	)
1823
+			//);
1824
+			$this->checkout->json_response->set_registration_time_limit(
1825
+				$this->checkout->get_registration_time_limit()
1826
+			);
1827
+			$this->checkout->json_response->set_payment_amount($this->checkout->amount_owing);
1828
+			// just send the ajax (
1829
+			$json_response = apply_filters(
1830
+				'FHEE__EE_Single_Page_Checkout__JSON_response',
1831
+				$this->checkout->json_response
1832
+			);
1833
+			echo $json_response;
1834
+			exit();
1835
+		}
1836
+	}
1837
+
1838
+
1839
+
1840
+	/**
1841
+	 *   _handle_redirects
1842
+	 *
1843
+	 * @access protected
1844
+	 * @return void
1845
+	 */
1846
+	protected function _handle_html_redirects()
1847
+	{
1848
+		// going somewhere ?
1849
+		if ($this->checkout->redirect && ! empty($this->checkout->redirect_url)) {
1850
+			// store notices in a transient
1851
+			EE_Error::get_notices(false, true, true);
1852
+			// DEBUG LOG
1853
+			//$this->checkout->log(
1854
+			//	__CLASS__, __FUNCTION__, __LINE__,
1855
+			//	array(
1856
+			//		'headers_sent' => headers_sent(),
1857
+			//		'redirect_url'     => $this->checkout->redirect_url,
1858
+			//		'headers_list'    => headers_list(),
1859
+			//	)
1860
+			//);
1861
+			wp_safe_redirect($this->checkout->redirect_url);
1862
+			exit();
1863
+		}
1864
+	}
1865
+
1866
+
1867
+
1868
+	/**
1869
+	 *   set_checkout_anchor
1870
+	 *
1871
+	 * @access public
1872
+	 * @return void
1873
+	 */
1874
+	public function set_checkout_anchor()
1875
+	{
1876
+		echo '<a id="checkout" style="float: left; margin-left: -999em;"></a>';
1877
+	}
1878 1878
 
1879 1879
 
1880 1880
 
Please login to merge, or discard this patch.
Spacing   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -218,19 +218,19 @@  discard block
 block discarded – undo
218 218
      */
219 219
     public static function set_definitions()
220 220
     {
221
-        if(defined('SPCO_BASE_PATH')) {
221
+        if (defined('SPCO_BASE_PATH')) {
222 222
             return;
223 223
         }
224 224
         define(
225 225
             'SPCO_BASE_PATH',
226
-            rtrim(str_replace(array('\\', '/'), DS, plugin_dir_path(__FILE__)), DS) . DS
226
+            rtrim(str_replace(array('\\', '/'), DS, plugin_dir_path(__FILE__)), DS).DS
227 227
         );
228
-        define('SPCO_CSS_URL', plugin_dir_url(__FILE__) . 'css' . DS);
229
-        define('SPCO_IMG_URL', plugin_dir_url(__FILE__) . 'img' . DS);
230
-        define('SPCO_JS_URL', plugin_dir_url(__FILE__) . 'js' . DS);
231
-        define('SPCO_INC_PATH', SPCO_BASE_PATH . 'inc' . DS);
232
-        define('SPCO_REG_STEPS_PATH', SPCO_BASE_PATH . 'reg_steps' . DS);
233
-        define('SPCO_TEMPLATES_PATH', SPCO_BASE_PATH . 'templates' . DS);
228
+        define('SPCO_CSS_URL', plugin_dir_url(__FILE__).'css'.DS);
229
+        define('SPCO_IMG_URL', plugin_dir_url(__FILE__).'img'.DS);
230
+        define('SPCO_JS_URL', plugin_dir_url(__FILE__).'js'.DS);
231
+        define('SPCO_INC_PATH', SPCO_BASE_PATH.'inc'.DS);
232
+        define('SPCO_REG_STEPS_PATH', SPCO_BASE_PATH.'reg_steps'.DS);
233
+        define('SPCO_TEMPLATES_PATH', SPCO_BASE_PATH.'templates'.DS);
234 234
         EEH_Autoloader::register_autoloaders_for_each_file_in_folder(SPCO_BASE_PATH, true);
235 235
         EE_Registry::$i18n_js_strings['registration_expiration_notice'] = sprintf(
236 236
             __('%1$sWe\'re sorry, but you\'re registration time has expired.%2$s%4$sIf you still wish to complete your registration, please return to the %5$sEvent List%6$sEvent List%7$s and reselect your tickets if available. Please except our apologies for any inconvenience this may have caused.%8$s',
@@ -239,7 +239,7 @@  discard block
 block discarded – undo
239 239
             '</h4>',
240 240
             '<br />',
241 241
             '<p>',
242
-            '<a href="' . get_post_type_archive_link('espresso_events') . '" title="',
242
+            '<a href="'.get_post_type_archive_link('espresso_events').'" title="',
243 243
             '">',
244 244
             '</a>',
245 245
             '</p>'
@@ -262,7 +262,7 @@  discard block
 block discarded – undo
262 262
             return;
263 263
         }
264 264
         // filter list of reg_steps
265
-        $reg_steps_to_load = (array)apply_filters(
265
+        $reg_steps_to_load = (array) apply_filters(
266 266
             'AHEE__SPCO__load_reg_steps__reg_steps_to_load',
267 267
             EED_Single_Page_Checkout::get_reg_steps()
268 268
         );
@@ -314,25 +314,25 @@  discard block
 block discarded – undo
314 314
         if (empty($reg_steps)) {
315 315
             $reg_steps = array(
316 316
                 10  => array(
317
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'attendee_information',
317
+                    'file_path'  => SPCO_REG_STEPS_PATH.'attendee_information',
318 318
                     'class_name' => 'EE_SPCO_Reg_Step_Attendee_Information',
319 319
                     'slug'       => 'attendee_information',
320 320
                     'has_hooks'  => false,
321 321
                 ),
322 322
                 20  => array(
323
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'registration_confirmation',
323
+                    'file_path'  => SPCO_REG_STEPS_PATH.'registration_confirmation',
324 324
                     'class_name' => 'EE_SPCO_Reg_Step_Registration_Confirmation',
325 325
                     'slug'       => 'registration_confirmation',
326 326
                     'has_hooks'  => false,
327 327
                 ),
328 328
                 30  => array(
329
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'payment_options',
329
+                    'file_path'  => SPCO_REG_STEPS_PATH.'payment_options',
330 330
                     'class_name' => 'EE_SPCO_Reg_Step_Payment_Options',
331 331
                     'slug'       => 'payment_options',
332 332
                     'has_hooks'  => true,
333 333
                 ),
334 334
                 999 => array(
335
-                    'file_path'  => SPCO_REG_STEPS_PATH . 'finalize_registration',
335
+                    'file_path'  => SPCO_REG_STEPS_PATH.'finalize_registration',
336 336
                     'class_name' => 'EE_SPCO_Reg_Step_Finalize_Registration',
337 337
                     'slug'       => 'finalize_registration',
338 338
                     'has_hooks'  => false,
@@ -516,7 +516,7 @@  discard block
 block discarded – undo
516 516
             // DEBUG LOG
517 517
             //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
518 518
             // get reg form
519
-            if( ! $this->_check_form_submission()) {
519
+            if ( ! $this->_check_form_submission()) {
520 520
                 EED_Single_Page_Checkout::$_initialized = true;
521 521
                 return;
522 522
             }
@@ -557,7 +557,7 @@  discard block
 block discarded – undo
557 557
         );
558 558
         // is session still valid ?
559 559
         if ($clear_session_requested
560
-            || ( EE_Registry::instance()->SSN->expired()
560
+            || (EE_Registry::instance()->SSN->expired()
561 561
               && EE_Registry::instance()->REQ->get('e_reg_url_link', '') === ''
562 562
             )
563 563
         ) {
@@ -566,7 +566,7 @@  discard block
 block discarded – undo
566 566
             // EE_Registry::instance()->SSN->reset_cart();
567 567
             // EE_Registry::instance()->SSN->reset_checkout();
568 568
             // EE_Registry::instance()->SSN->reset_transaction();
569
-            if (! $clear_session_requested) {
569
+            if ( ! $clear_session_requested) {
570 570
                 EE_Error::add_attention(
571 571
                     EE_Registry::$i18n_js_strings['registration_expiration_notice'],
572 572
                     __FILE__, __FUNCTION__, __LINE__
@@ -1121,7 +1121,7 @@  discard block
 block discarded – undo
1121 1121
                     if ( ! $registration instanceof EE_Registration) {
1122 1122
                         throw new InvalidEntityException($registration, 'EE_Registration');
1123 1123
                     }
1124
-                    $registrations[ $registration->ID() ] = $registration;
1124
+                    $registrations[$registration->ID()] = $registration;
1125 1125
                 }
1126 1126
             }
1127 1127
             $registration_processor->fix_reg_final_price_rounding_issue($transaction);
@@ -1382,7 +1382,7 @@  discard block
 block discarded – undo
1382 1382
                         ) {
1383 1383
                             EE_Error::add_success(
1384 1384
                                 $this->checkout->current_step->success_message()
1385
-                                . '<br />' . $this->checkout->next_step->_instructions()
1385
+                                . '<br />'.$this->checkout->next_step->_instructions()
1386 1386
                             );
1387 1387
                         }
1388 1388
                         // pack it up, pack it in...
@@ -1507,7 +1507,7 @@  discard block
 block discarded – undo
1507 1507
             '</h4>',
1508 1508
             '<br />',
1509 1509
             '<p>',
1510
-            '<a href="' . get_post_type_archive_link('espresso_events') . '" title="',
1510
+            '<a href="'.get_post_type_archive_link('espresso_events').'" title="',
1511 1511
             '">',
1512 1512
             '</a>',
1513 1513
             '</p>'
@@ -1539,7 +1539,7 @@  discard block
 block discarded – undo
1539 1539
         // load css
1540 1540
         wp_register_style(
1541 1541
             'single_page_checkout',
1542
-            SPCO_CSS_URL . 'single_page_checkout.css',
1542
+            SPCO_CSS_URL.'single_page_checkout.css',
1543 1543
             array('espresso_default'),
1544 1544
             EVENT_ESPRESSO_VERSION
1545 1545
         );
@@ -1547,21 +1547,21 @@  discard block
 block discarded – undo
1547 1547
         // load JS
1548 1548
         wp_register_script(
1549 1549
             'jquery_plugin',
1550
-            EE_THIRD_PARTY_URL . 'jquery	.plugin.min.js',
1550
+            EE_THIRD_PARTY_URL.'jquery	.plugin.min.js',
1551 1551
             array('jquery'),
1552 1552
             '1.0.1',
1553 1553
             true
1554 1554
         );
1555 1555
         wp_register_script(
1556 1556
             'jquery_countdown',
1557
-            EE_THIRD_PARTY_URL . 'jquery	.countdown.min.js',
1557
+            EE_THIRD_PARTY_URL.'jquery	.countdown.min.js',
1558 1558
             array('jquery_plugin'),
1559 1559
             '2.0.2',
1560 1560
             true
1561 1561
         );
1562 1562
         wp_register_script(
1563 1563
             'single_page_checkout',
1564
-            SPCO_JS_URL . 'single_page_checkout.js',
1564
+            SPCO_JS_URL.'single_page_checkout.js',
1565 1565
             array('espresso_core', 'underscore', 'ee_form_section_validation', 'jquery_countdown'),
1566 1566
             EVENT_ESPRESSO_VERSION,
1567 1567
             true
@@ -1584,7 +1584,7 @@  discard block
 block discarded – undo
1584 1584
          *      AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__attendee_information
1585 1585
          */
1586 1586
         do_action(
1587
-            'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__' . $this->checkout->current_step->slug(),
1587
+            'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__'.$this->checkout->current_step->slug(),
1588 1588
             $this
1589 1589
         );
1590 1590
     }
@@ -1638,7 +1638,7 @@  discard block
 block discarded – undo
1638 1638
                     'layout_strategy' =>
1639 1639
                         new EE_Template_Layout(
1640 1640
                             array(
1641
-                                'layout_template_file' => SPCO_TEMPLATES_PATH . 'registration_page_wrapper.template.php',
1641
+                                'layout_template_file' => SPCO_TEMPLATES_PATH.'registration_page_wrapper.template.php',
1642 1642
                                 'template_args'        => array(
1643 1643
                                     'empty_cart'              => $empty_cart,
1644 1644
                                     'revisit'                 => $this->checkout->revisit,
@@ -1713,7 +1713,7 @@  discard block
 block discarded – undo
1713 1713
         ) {
1714 1714
             add_filter(
1715 1715
                 'FHEE__EEH_Template__powered_by_event_espresso__url',
1716
-                function ($url) {
1716
+                function($url) {
1717 1717
                     return apply_filters('FHEE__EE_Front_Controller__registration_footer__url', $url);
1718 1718
                 }
1719 1719
             );
Please login to merge, or discard this patch.
admin_pages/transactions/Transactions_Admin_Page.core.php 1 patch
Indentation   +1967 added lines, -1967 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
 /**
@@ -27,1975 +27,1975 @@  discard block
 block discarded – undo
27 27
 class Transactions_Admin_Page extends EE_Admin_Page
28 28
 {
29 29
 
30
-    /**
31
-     * @var EE_Transaction
32
-     */
33
-    private $_transaction;
34
-
35
-    /**
36
-     * @var EE_Session
37
-     */
38
-    private $_session;
39
-
40
-    /**
41
-     * @var array $_txn_status
42
-     */
43
-    private static $_txn_status;
44
-
45
-    /**
46
-     * @var array $_pay_status
47
-     */
48
-    private static $_pay_status;
49
-
50
-    /**
51
-     * @var array $_existing_reg_payment_REG_IDs
52
-     */
53
-    protected $_existing_reg_payment_REG_IDs = null;
54
-
55
-
56
-    /**
57
-     * @Constructor
58
-     * @access public
59
-     *
60
-     * @param bool $routing
61
-     *
62
-     * @return Transactions_Admin_Page
63
-     */
64
-    public function __construct($routing = true)
65
-    {
66
-        parent::__construct($routing);
67
-    }
68
-
69
-
70
-    /**
71
-     *    _init_page_props
72
-     * @return void
73
-     */
74
-    protected function _init_page_props()
75
-    {
76
-        $this->page_slug        = TXN_PG_SLUG;
77
-        $this->page_label       = esc_html__('Transactions', 'event_espresso');
78
-        $this->_admin_base_url  = TXN_ADMIN_URL;
79
-        $this->_admin_base_path = TXN_ADMIN;
80
-    }
81
-
82
-
83
-    /**
84
-     *    _ajax_hooks
85
-     * @return void
86
-     */
87
-    protected function _ajax_hooks()
88
-    {
89
-        add_action('wp_ajax_espresso_apply_payment', array($this, 'apply_payments_or_refunds'));
90
-        add_action('wp_ajax_espresso_apply_refund', array($this, 'apply_payments_or_refunds'));
91
-        add_action('wp_ajax_espresso_delete_payment', array($this, 'delete_payment'));
92
-    }
93
-
94
-
95
-    /**
96
-     *    _define_page_props
97
-     * @return void
98
-     */
99
-    protected function _define_page_props()
100
-    {
101
-        $this->_admin_page_title = $this->page_label;
102
-        $this->_labels           = array(
103
-            'buttons' => array(
104
-                'add'    => esc_html__('Add New Transaction', 'event_espresso'),
105
-                'edit'   => esc_html__('Edit Transaction', 'event_espresso'),
106
-                'delete' => esc_html__('Delete Transaction', 'event_espresso'),
107
-            )
108
-        );
109
-    }
110
-
111
-
112
-    /**
113
-     *        grab url requests and route them
114
-     * @access private
115
-     * @return void
116
-     */
117
-    public function _set_page_routes()
118
-    {
119
-
120
-        $this->_set_transaction_status_array();
121
-
122
-        $txn_id = ! empty($this->_req_data['TXN_ID']) && ! is_array($this->_req_data['TXN_ID']) ? $this->_req_data['TXN_ID'] : 0;
123
-
124
-        $this->_page_routes = array(
125
-
126
-            'default' => array(
127
-                'func'       => '_transactions_overview_list_table',
128
-                'capability' => 'ee_read_transactions'
129
-            ),
130
-
131
-            'view_transaction' => array(
132
-                'func'       => '_transaction_details',
133
-                'capability' => 'ee_read_transaction',
134
-                'obj_id'     => $txn_id
135
-            ),
136
-
137
-            'send_payment_reminder' => array(
138
-                'func'       => '_send_payment_reminder',
139
-                'noheader'   => true,
140
-                'capability' => 'ee_send_message'
141
-            ),
142
-
143
-            'espresso_apply_payment' => array(
144
-                'func'       => 'apply_payments_or_refunds',
145
-                'noheader'   => true,
146
-                'capability' => 'ee_edit_payments'
147
-            ),
148
-
149
-            'espresso_apply_refund' => array(
150
-                'func'       => 'apply_payments_or_refunds',
151
-                'noheader'   => true,
152
-                'capability' => 'ee_edit_payments'
153
-            ),
154
-
155
-            'espresso_delete_payment' => array(
156
-                'func'       => 'delete_payment',
157
-                'noheader'   => true,
158
-                'capability' => 'ee_delete_payments'
159
-            ),
160
-
161
-        );
162
-
163
-    }
164
-
165
-
166
-    protected function _set_page_config()
167
-    {
168
-        $this->_page_config = array(
169
-            'default'          => array(
170
-                'nav'           => array(
171
-                    'label' => esc_html__('Overview', 'event_espresso'),
172
-                    'order' => 10
173
-                ),
174
-                'list_table'    => 'EE_Admin_Transactions_List_Table',
175
-                'help_tabs'     => array(
176
-                    'transactions_overview_help_tab'                       => array(
177
-                        'title'    => esc_html__('Transactions Overview', 'event_espresso'),
178
-                        'filename' => 'transactions_overview'
179
-                    ),
180
-                    'transactions_overview_table_column_headings_help_tab' => array(
181
-                        'title'    => esc_html__('Transactions Table Column Headings', 'event_espresso'),
182
-                        'filename' => 'transactions_overview_table_column_headings'
183
-                    ),
184
-                    'transactions_overview_views_filters_help_tab'         => array(
185
-                        'title'    => esc_html__('Transaction Views & Filters & Search', 'event_espresso'),
186
-                        'filename' => 'transactions_overview_views_filters_search'
187
-                    ),
188
-                ),
189
-                'help_tour'     => array('Transactions_Overview_Help_Tour'),
190
-                /**
191
-                 * commented out because currently we are not displaying tips for transaction list table status but this
192
-                 * may change in a later iteration so want to keep the code for then.
193
-                 */
194
-                //'qtips' => array( 'Transactions_List_Table_Tips' ),
195
-                'require_nonce' => false
196
-            ),
197
-            'view_transaction' => array(
198
-                'nav'       => array(
199
-                    'label'      => esc_html__('View Transaction', 'event_espresso'),
200
-                    'order'      => 5,
201
-                    'url'        => isset($this->_req_data['TXN_ID']) ? add_query_arg(array('TXN_ID' => $this->_req_data['TXN_ID']),
202
-                        $this->_current_page_view_url) : $this->_admin_base_url,
203
-                    'persistent' => false
204
-                ),
205
-                'help_tabs' => array(
206
-                    'transactions_view_transaction_help_tab'                                              => array(
207
-                        'title'    => esc_html__('View Transaction', 'event_espresso'),
208
-                        'filename' => 'transactions_view_transaction'
209
-                    ),
210
-                    'transactions_view_transaction_transaction_details_table_help_tab'                    => array(
211
-                        'title'    => esc_html__('Transaction Details Table', 'event_espresso'),
212
-                        'filename' => 'transactions_view_transaction_transaction_details_table'
213
-                    ),
214
-                    'transactions_view_transaction_attendees_registered_help_tab'                         => array(
215
-                        'title'    => esc_html__('Attendees Registered', 'event_espresso'),
216
-                        'filename' => 'transactions_view_transaction_attendees_registered'
217
-                    ),
218
-                    'transactions_view_transaction_views_primary_registrant_billing_information_help_tab' => array(
219
-                        'title'    => esc_html__('Primary Registrant & Billing Information', 'event_espresso'),
220
-                        'filename' => 'transactions_view_transaction_primary_registrant_billing_information'
221
-                    ),
222
-                ),
223
-                'qtips'     => array('Transaction_Details_Tips'),
224
-                'help_tour' => array('Transaction_Details_Help_Tour'),
225
-                'metaboxes' => array('_transaction_details_metaboxes'),
226
-
227
-                'require_nonce' => false
228
-            )
229
-        );
230
-    }
231
-
232
-
233
-    /**
234
-     * The below methods aren't used by this class currently
235
-     */
236
-    protected function _add_screen_options()
237
-    {
238
-    }
239
-
240
-    protected function _add_feature_pointers()
241
-    {
242
-    }
243
-
244
-    public function admin_init()
245
-    {
246
-        // IF a registration was JUST added via the admin...
247
-        if (
248
-        isset(
249
-            $this->_req_data['redirect_from'],
250
-            $this->_req_data['EVT_ID'],
251
-            $this->_req_data['event_name']
252
-        )
253
-        ) {
254
-            // then set a cookie so that we can block any attempts to use
255
-            // the back button as a way to enter another registration.
256
-            setcookie('ee_registration_added', $this->_req_data['EVT_ID'], time() + WEEK_IN_SECONDS, '/');
257
-            // and update the global
258
-            $_COOKIE['ee_registration_added'] = $this->_req_data['EVT_ID'];
259
-        }
260
-        EE_Registry::$i18n_js_strings['invalid_server_response'] = esc_html__('An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
261
-            'event_espresso');
262
-        EE_Registry::$i18n_js_strings['error_occurred']          = esc_html__('An error occurred! Please refresh the page and try again.',
263
-            'event_espresso');
264
-        EE_Registry::$i18n_js_strings['txn_status_array']        = self::$_txn_status;
265
-        EE_Registry::$i18n_js_strings['pay_status_array']        = self::$_pay_status;
266
-        EE_Registry::$i18n_js_strings['payments_total']          = esc_html__('Payments Total', 'event_espresso');
267
-        EE_Registry::$i18n_js_strings['transaction_overpaid']    = esc_html__('This transaction has been overpaid ! Payments Total',
268
-            'event_espresso');
269
-    }
270
-
271
-    public function admin_notices()
272
-    {
273
-    }
274
-
275
-    public function admin_footer_scripts()
276
-    {
277
-    }
278
-
279
-
280
-    /**
281
-     * _set_transaction_status_array
282
-     * sets list of transaction statuses
283
-     *
284
-     * @access private
285
-     * @return void
286
-     */
287
-    private function _set_transaction_status_array()
288
-    {
289
-        self::$_txn_status = EEM_Transaction::instance()->status_array(true);
290
-    }
291
-
292
-
293
-    /**
294
-     * get_transaction_status_array
295
-     * return the transaction status array for wp_list_table
296
-     *
297
-     * @access public
298
-     * @return array
299
-     */
300
-    public function get_transaction_status_array()
301
-    {
302
-        return self::$_txn_status;
303
-    }
304
-
305
-
306
-    /**
307
-     *    get list of payment statuses
308
-     *
309
-     * @access private
310
-     * @return void
311
-     */
312
-    private function _get_payment_status_array()
313
-    {
314
-        self::$_pay_status                      = EEM_Payment::instance()->status_array(true);
315
-        $this->_template_args['payment_status'] = self::$_pay_status;
316
-
317
-    }
318
-
319
-
320
-    /**
321
-     *    _add_screen_options_default
322
-     *
323
-     * @access protected
324
-     * @return void
325
-     */
326
-    protected function _add_screen_options_default()
327
-    {
328
-        $this->_per_page_screen_option();
329
-    }
330
-
331
-
332
-    /**
333
-     * load_scripts_styles
334
-     *
335
-     * @access public
336
-     * @return void
337
-     */
338
-    public function load_scripts_styles()
339
-    {
340
-        //enqueue style
341
-        wp_register_style('espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.css', array(),
342
-            EVENT_ESPRESSO_VERSION);
343
-        wp_enqueue_style('espresso_txn');
344
-        //scripts
345
-        wp_register_script('espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.js', array(
346
-            'ee_admin_js',
347
-            'ee-datepicker',
348
-            'jquery-ui-datepicker',
349
-            'jquery-ui-draggable',
350
-            'ee-dialog',
351
-            'ee-accounting',
352
-            'ee-serialize-full-array'
353
-        ), EVENT_ESPRESSO_VERSION, true);
354
-        wp_enqueue_script('espresso_txn');
355
-
356
-    }
357
-
358
-
359
-    /**
360
-     *    load_scripts_styles_view_transaction
361
-     *
362
-     * @access public
363
-     * @return void
364
-     */
365
-    public function load_scripts_styles_view_transaction()
366
-    {
367
-        //styles
368
-        wp_enqueue_style('espresso-ui-theme');
369
-    }
370
-
371
-
372
-    /**
373
-     *    load_scripts_styles_default
374
-     *
375
-     * @access public
376
-     * @return void
377
-     */
378
-    public function load_scripts_styles_default()
379
-    {
380
-        //styles
381
-        wp_enqueue_style('espresso-ui-theme');
382
-    }
383
-
384
-
385
-    /**
386
-     *    _set_list_table_views_default
387
-     *
388
-     * @access protected
389
-     * @return void
390
-     */
391
-    protected function _set_list_table_views_default()
392
-    {
393
-        $this->_views = array(
394
-            'all'       => array(
395
-                'slug'  => 'all',
396
-                'label' => esc_html__('View All Transactions', 'event_espresso'),
397
-                'count' => 0
398
-            ),
399
-            'abandoned' => array(
400
-                'slug'  => 'abandoned',
401
-                'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
402
-                'count' => 0
403
-            ),
404
-            'failed'    => array(
405
-                'slug'  => 'failed',
406
-                'label' => esc_html__('Failed Transactions', 'event_espresso'),
407
-                'count' => 0
408
-            )
409
-        );
410
-    }
411
-
412
-
413
-    /**
414
-     * _set_transaction_object
415
-     * This sets the _transaction property for the transaction details screen
416
-     *
417
-     * @access private
418
-     * @return void
419
-     */
420
-    private function _set_transaction_object()
421
-    {
422
-        if (is_object($this->_transaction)) {
423
-            return;
424
-        } //get out we've already set the object
425
-
426
-        $TXN = EEM_Transaction::instance();
427
-
428
-        $TXN_ID = ( ! empty($this->_req_data['TXN_ID'])) ? absint($this->_req_data['TXN_ID']) : false;
429
-
430
-        //get transaction object
431
-        $this->_transaction = $TXN->get_one_by_ID($TXN_ID);
432
-        $this->_session     = ! empty($this->_transaction) ? $this->_transaction->get('TXN_session_data') : null;
433
-        $this->_transaction->verify_abandoned_transaction_status();
434
-
435
-        if (empty($this->_transaction)) {
436
-            $error_msg = esc_html__('An error occurred and the details for Transaction ID #',
437
-                    'event_espresso') . $TXN_ID . esc_html__(' could not be retrieved.', 'event_espresso');
438
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
439
-        }
440
-    }
441
-
442
-
443
-    /**
444
-     *    _transaction_legend_items
445
-     *
446
-     * @access protected
447
-     * @return array
448
-     */
449
-    protected function _transaction_legend_items()
450
-    {
451
-        EE_Registry::instance()->load_helper('MSG_Template');
452
-        $items = array();
453
-
454
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
455
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
456
-            if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
457
-                $items['view_related_messages'] = array(
458
-                    'class' => $related_for_icon['css_class'],
459
-                    'desc'  => $related_for_icon['label'],
460
-                );
461
-            }
462
-        }
463
-
464
-        $items = apply_filters(
465
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
466
-            array_merge($items,
467
-                array(
468
-                    'view_details'      => array(
469
-                        'class' => 'dashicons dashicons-cart',
470
-                        'desc'  => esc_html__('View Transaction Details', 'event_espresso')
471
-                    ),
472
-                    'view_invoice'      => array(
473
-                        'class' => 'dashicons dashicons-media-spreadsheet',
474
-                        'desc'  => esc_html__('View Transaction Invoice', 'event_espresso')
475
-                    ),
476
-                    'view_receipt'      => array(
477
-                        'class' => 'dashicons dashicons-media-default',
478
-                        'desc'  => esc_html__('View Transaction Receipt', 'event_espresso')
479
-                    ),
480
-                    'view_registration' => array(
481
-                        'class' => 'dashicons dashicons-clipboard',
482
-                        'desc'  => esc_html__('View Registration Details', 'event_espresso')
483
-                    ),
484
-                    'payment_overview_link' => array(
485
-                        'class' => 'dashicons dashicons-money',
486
-                        'desc' => esc_html__('Make Payment on Frontend', 'event_espresso')
487
-                    )
488
-                )
489
-            )
490
-        );
491
-
492
-        if (EE_Registry::instance()->CAP->current_user_can('ee_send_message',
493
-            'espresso_transactions_send_payment_reminder')
494
-        ) {
495
-            if (EEH_MSG_Template::is_mt_active('payment_reminder')) {
496
-                $items['send_payment_reminder'] = array(
497
-                    'class' => 'dashicons dashicons-email-alt',
498
-                    'desc'  => esc_html__('Send Payment Reminder', 'event_espresso')
499
-                );
500
-            } else {
501
-                $items['blank*'] = array(
502
-                    'class' => '',
503
-                    'desc'  => ''
504
-                );
505
-            }
506
-        } else {
507
-            $items['blank*'] = array(
508
-                'class' => '',
509
-                'desc'  => ''
510
-            );
511
-        }
512
-        $more_items = apply_filters(
513
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
514
-            array(
515
-                'overpaid'   => array(
516
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
517
-                    'desc'  => EEH_Template::pretty_status(EEM_Transaction::overpaid_status_code, false, 'sentence')
518
-                ),
519
-                'complete'   => array(
520
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
521
-                    'desc'  => EEH_Template::pretty_status(EEM_Transaction::complete_status_code, false, 'sentence')
522
-                ),
523
-                'incomplete' => array(
524
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
525
-                    'desc'  => EEH_Template::pretty_status(EEM_Transaction::incomplete_status_code, false, 'sentence')
526
-                ),
527
-                'abandoned'  => array(
528
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
529
-                    'desc'  => EEH_Template::pretty_status(EEM_Transaction::abandoned_status_code, false, 'sentence')
530
-                ),
531
-                'failed'     => array(
532
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
533
-                    'desc'  => EEH_Template::pretty_status(EEM_Transaction::failed_status_code, false, 'sentence')
534
-                )
535
-            )
536
-        );
537
-
538
-        return array_merge($items, $more_items);
539
-    }
540
-
541
-
542
-    /**
543
-     *    _transactions_overview_list_table
544
-     *
545
-     * @access protected
546
-     * @return void
547
-     */
548
-    protected function _transactions_overview_list_table()
549
-    {
550
-        $this->_admin_page_title                   = esc_html__('Transactions', 'event_espresso');
551
-        $event                                     = isset($this->_req_data['EVT_ID']) ? EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID']) : null;
552
-        $this->_template_args['admin_page_header'] = $event instanceof EE_Event ? sprintf(esc_html__('%sViewing Transactions for the Event: %s%s',
553
-            'event_espresso'), '<h3>',
554
-            '<a href="' . EE_Admin_Page::add_query_args_and_nonce(array('action' => 'edit', 'post' => $event->ID()),
555
-                EVENTS_ADMIN_URL) . '" title="' . esc_attr__('Click to Edit event',
556
-                'event_espresso') . '">' . $event->get('EVT_name') . '</a>', '</h3>') : '';
557
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
558
-        $this->display_admin_list_table_page_with_no_sidebar();
559
-    }
560
-
561
-
562
-    /**
563
-     *    _transaction_details
564
-     * generates HTML for the View Transaction Details Admin page
565
-     *
566
-     * @access protected
567
-     * @return void
568
-     */
569
-    protected function _transaction_details()
570
-    {
571
-        do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
572
-
573
-        $this->_set_transaction_status_array();
574
-
575
-        $this->_template_args                      = array();
576
-        $this->_template_args['transactions_page'] = $this->_wp_page_slug;
577
-
578
-        $this->_set_transaction_object();
579
-
580
-        $primary_registration = $this->_transaction->primary_registration();
581
-        $attendee             = $primary_registration instanceof EE_Registration ? $primary_registration->attendee() : null;
582
-
583
-        $this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
584
-        $this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
585
-
586
-        $this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
587
-        $this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
588
-
589
-        $this->_template_args['txn_status']['value'] = self::$_txn_status[$this->_transaction->get('STS_ID')];
590
-        $this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
591
-        $this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
592
-
593
-        $this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
594
-        $this->_template_args['total_paid']  = $this->_transaction->get('TXN_paid');
595
-
596
-        if (
597
-            $attendee instanceof EE_Attendee
598
-            && EE_Registry::instance()->CAP->current_user_can(
599
-                'ee_send_message',
600
-                'espresso_transactions_send_payment_reminder'
601
-            )
602
-        ) {
603
-            $this->_template_args['send_payment_reminder_button'] =
604
-                EEH_MSG_Template::is_mt_active('payment_reminder')
605
-                && $this->_transaction->get('STS_ID') != EEM_Transaction::complete_status_code
606
-                && $this->_transaction->get('STS_ID') != EEM_Transaction::overpaid_status_code
607
-                    ? EEH_Template::get_button_or_link(
608
-                    EE_Admin_Page::add_query_args_and_nonce(
609
-                        array(
610
-                            'action'      => 'send_payment_reminder',
611
-                            'TXN_ID'      => $this->_transaction->ID(),
612
-                            'redirect_to' => 'view_transaction'
613
-                        ),
614
-                        TXN_ADMIN_URL
615
-                    ),
616
-                    __(' Send Payment Reminder', 'event_espresso'),
617
-                    'button secondary-button right',
618
-                    'dashicons dashicons-email-alt'
619
-                )
620
-                    : '';
621
-        } else {
622
-            $this->_template_args['send_payment_reminder_button'] = '';
623
-        }
624
-
625
-        $amount_due                         = $this->_transaction->get('TXN_total') - $this->_transaction->get('TXN_paid');
626
-        $this->_template_args['amount_due'] = EEH_Template::format_currency($amount_due, true);
627
-        if (EE_Registry::instance()->CFG->currency->sign_b4) {
628
-            $this->_template_args['amount_due'] = EE_Registry::instance()->CFG->currency->sign . $this->_template_args['amount_due'];
629
-        } else {
630
-            $this->_template_args['amount_due'] = $this->_template_args['amount_due'] . EE_Registry::instance()->CFG->currency->sign;
631
-        }
632
-        $this->_template_args['amount_due_class'] = '';
633
-
634
-        if ($this->_transaction->get('TXN_paid') == $this->_transaction->get('TXN_total')) {
635
-            // paid in full
636
-            $this->_template_args['amount_due'] = false;
637
-        } elseif ($this->_transaction->get('TXN_paid') > $this->_transaction->get('TXN_total')) {
638
-            // overpaid
639
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
640
-        } elseif (($this->_transaction->get('TXN_total') > 0) && ($this->_transaction->get('TXN_paid') > 0)) {
641
-            // monies owing
642
-            $this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn';
643
-        } elseif (($this->_transaction->get('TXN_total') > 0) && ($this->_transaction->get('TXN_paid') == 0)) {
644
-            // no payments made yet
645
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
646
-        } elseif ($this->_transaction->get('TXN_total') == 0) {
647
-            // free event
648
-            $this->_template_args['amount_due'] = false;
649
-        }
650
-
651
-        $payment_method = $this->_transaction->payment_method();
652
-
653
-        $this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
654
-            ? $payment_method->admin_name()
655
-            : esc_html__('Unknown', 'event_espresso');
656
-
657
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
658
-        // link back to overview
659
-        $this->_template_args['txn_overview_url'] = ! empty ($_SERVER['HTTP_REFERER'])
660
-            ? $_SERVER['HTTP_REFERER']
661
-            : TXN_ADMIN_URL;
662
-
663
-
664
-        // next link
665
-        $next_txn                                 = $this->_transaction->next(
666
-            null,
667
-            array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
668
-            'TXN_ID'
669
-        );
670
-        $this->_template_args['next_transaction'] = $next_txn
671
-            ? $this->_next_link(
672
-                EE_Admin_Page::add_query_args_and_nonce(
673
-                    array('action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']),
674
-                    TXN_ADMIN_URL
675
-                ),
676
-                'dashicons dashicons-arrow-right ee-icon-size-22'
677
-            )
678
-            : '';
679
-        // previous link
680
-        $previous_txn                                 = $this->_transaction->previous(
681
-            null,
682
-            array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
683
-            'TXN_ID'
684
-        );
685
-        $this->_template_args['previous_transaction'] = $previous_txn
686
-            ? $this->_previous_link(
687
-                EE_Admin_Page::add_query_args_and_nonce(
688
-                    array('action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']),
689
-                    TXN_ADMIN_URL
690
-                ),
691
-                'dashicons dashicons-arrow-left ee-icon-size-22'
692
-            )
693
-            : '';
694
-
695
-        // were we just redirected here after adding a new registration ???
696
-        if (
697
-        isset(
698
-            $this->_req_data['redirect_from'],
699
-            $this->_req_data['EVT_ID'],
700
-            $this->_req_data['event_name']
701
-        )
702
-        ) {
703
-            if (
704
-            EE_Registry::instance()->CAP->current_user_can(
705
-                'ee_edit_registrations',
706
-                'espresso_registrations_new_registration',
707
-                $this->_req_data['EVT_ID']
708
-            )
709
-            ) {
710
-                $this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button-primary" href="';
711
-                $this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
712
-                    array(
713
-                        'page'     => 'espresso_registrations',
714
-                        'action'   => 'new_registration',
715
-                        'return'   => 'default',
716
-                        'TXN_ID'   => $this->_transaction->ID(),
717
-                        'event_id' => $this->_req_data['EVT_ID'],
718
-                    ),
719
-                    REG_ADMIN_URL
720
-                );
721
-                $this->_admin_page_title .= '">';
722
-
723
-                $this->_admin_page_title .= sprintf(
724
-                    esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
725
-                    htmlentities(urldecode($this->_req_data['event_name']), ENT_QUOTES, 'UTF-8')
726
-                );
727
-                $this->_admin_page_title .= '</a>';
728
-            }
729
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
730
-        }
731
-        // grab messages at the last second
732
-        $this->_template_args['notices'] = EE_Error::get_notices();
733
-        // path to template
734
-        $template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
735
-        $this->_template_args['admin_page_header'] = EEH_Template::display_template($template_path,
736
-            $this->_template_args, true);
737
-
738
-        // the details template wrapper
739
-        $this->display_admin_page_with_sidebar();
740
-
741
-    }
742
-
743
-
744
-    /**
745
-     *        _transaction_details_metaboxes
746
-     *
747
-     * @access protected
748
-     * @return void
749
-     */
750
-    protected function _transaction_details_metaboxes()
751
-    {
752
-
753
-        $this->_set_transaction_object();
754
-
755
-        add_meta_box('edit-txn-details-mbox', esc_html__('Transaction Details', 'event_espresso'),
756
-            array($this, 'txn_details_meta_box'), $this->_wp_page_slug, 'normal', 'high');
757
-        add_meta_box(
758
-            'edit-txn-attendees-mbox',
759
-            esc_html__('Attendees Registered in this Transaction', 'event_espresso'),
760
-            array($this, 'txn_attendees_meta_box'),
761
-            $this->_wp_page_slug,
762
-            'normal',
763
-            'high',
764
-            array('TXN_ID' => $this->_transaction->ID())
765
-        );
766
-        add_meta_box('edit-txn-registrant-mbox', esc_html__('Primary Contact', 'event_espresso'),
767
-            array($this, 'txn_registrant_side_meta_box'), $this->_wp_page_slug, 'side', 'high');
768
-        add_meta_box('edit-txn-billing-info-mbox', esc_html__('Billing Information', 'event_espresso'),
769
-            array($this, 'txn_billing_info_side_meta_box'), $this->_wp_page_slug, 'side', 'high');
770
-
771
-    }
772
-
773
-
774
-    /**
775
-     * txn_details_meta_box
776
-     * generates HTML for the Transaction main meta box
777
-     *
778
-     * @access public
779
-     * @return void
780
-     */
781
-    public function txn_details_meta_box()
782
-    {
783
-
784
-        $this->_set_transaction_object();
785
-        $this->_template_args['TXN_ID']   = $this->_transaction->ID();
786
-        $this->_template_args['attendee'] = $this->_transaction->primary_registration() instanceof EE_Registration ? $this->_transaction->primary_registration()->attendee() : null;
787
-
788
-        //get line table
789
-        EEH_Autoloader::register_line_item_display_autoloaders();
790
-        $Line_Item_Display                       = new EE_Line_Item_Display('admin_table',
791
-            'EE_Admin_Table_Line_Item_Display_Strategy');
792
-        $this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item($this->_transaction->total_line_item());
793
-        $this->_template_args['REG_code']        = $this->_transaction->get_first_related('Registration')->get('REG_code');
794
-
795
-        // process taxes
796
-        $taxes                         = $this->_transaction->get_many_related('Line_Item',
797
-            array(array('LIN_type' => EEM_Line_Item::type_tax)));
798
-        $this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
799
-
800
-        $this->_template_args['grand_total']     = EEH_Template::format_currency($this->_transaction->get('TXN_total'),
801
-            false, false);
802
-        $this->_template_args['grand_raw_total'] = $this->_transaction->get('TXN_total');
803
-        $this->_template_args['TXN_status']      = $this->_transaction->get('STS_ID');
30
+	/**
31
+	 * @var EE_Transaction
32
+	 */
33
+	private $_transaction;
34
+
35
+	/**
36
+	 * @var EE_Session
37
+	 */
38
+	private $_session;
39
+
40
+	/**
41
+	 * @var array $_txn_status
42
+	 */
43
+	private static $_txn_status;
44
+
45
+	/**
46
+	 * @var array $_pay_status
47
+	 */
48
+	private static $_pay_status;
49
+
50
+	/**
51
+	 * @var array $_existing_reg_payment_REG_IDs
52
+	 */
53
+	protected $_existing_reg_payment_REG_IDs = null;
54
+
55
+
56
+	/**
57
+	 * @Constructor
58
+	 * @access public
59
+	 *
60
+	 * @param bool $routing
61
+	 *
62
+	 * @return Transactions_Admin_Page
63
+	 */
64
+	public function __construct($routing = true)
65
+	{
66
+		parent::__construct($routing);
67
+	}
68
+
69
+
70
+	/**
71
+	 *    _init_page_props
72
+	 * @return void
73
+	 */
74
+	protected function _init_page_props()
75
+	{
76
+		$this->page_slug        = TXN_PG_SLUG;
77
+		$this->page_label       = esc_html__('Transactions', 'event_espresso');
78
+		$this->_admin_base_url  = TXN_ADMIN_URL;
79
+		$this->_admin_base_path = TXN_ADMIN;
80
+	}
81
+
82
+
83
+	/**
84
+	 *    _ajax_hooks
85
+	 * @return void
86
+	 */
87
+	protected function _ajax_hooks()
88
+	{
89
+		add_action('wp_ajax_espresso_apply_payment', array($this, 'apply_payments_or_refunds'));
90
+		add_action('wp_ajax_espresso_apply_refund', array($this, 'apply_payments_or_refunds'));
91
+		add_action('wp_ajax_espresso_delete_payment', array($this, 'delete_payment'));
92
+	}
93
+
94
+
95
+	/**
96
+	 *    _define_page_props
97
+	 * @return void
98
+	 */
99
+	protected function _define_page_props()
100
+	{
101
+		$this->_admin_page_title = $this->page_label;
102
+		$this->_labels           = array(
103
+			'buttons' => array(
104
+				'add'    => esc_html__('Add New Transaction', 'event_espresso'),
105
+				'edit'   => esc_html__('Edit Transaction', 'event_espresso'),
106
+				'delete' => esc_html__('Delete Transaction', 'event_espresso'),
107
+			)
108
+		);
109
+	}
110
+
111
+
112
+	/**
113
+	 *        grab url requests and route them
114
+	 * @access private
115
+	 * @return void
116
+	 */
117
+	public function _set_page_routes()
118
+	{
119
+
120
+		$this->_set_transaction_status_array();
121
+
122
+		$txn_id = ! empty($this->_req_data['TXN_ID']) && ! is_array($this->_req_data['TXN_ID']) ? $this->_req_data['TXN_ID'] : 0;
123
+
124
+		$this->_page_routes = array(
125
+
126
+			'default' => array(
127
+				'func'       => '_transactions_overview_list_table',
128
+				'capability' => 'ee_read_transactions'
129
+			),
130
+
131
+			'view_transaction' => array(
132
+				'func'       => '_transaction_details',
133
+				'capability' => 'ee_read_transaction',
134
+				'obj_id'     => $txn_id
135
+			),
136
+
137
+			'send_payment_reminder' => array(
138
+				'func'       => '_send_payment_reminder',
139
+				'noheader'   => true,
140
+				'capability' => 'ee_send_message'
141
+			),
142
+
143
+			'espresso_apply_payment' => array(
144
+				'func'       => 'apply_payments_or_refunds',
145
+				'noheader'   => true,
146
+				'capability' => 'ee_edit_payments'
147
+			),
148
+
149
+			'espresso_apply_refund' => array(
150
+				'func'       => 'apply_payments_or_refunds',
151
+				'noheader'   => true,
152
+				'capability' => 'ee_edit_payments'
153
+			),
154
+
155
+			'espresso_delete_payment' => array(
156
+				'func'       => 'delete_payment',
157
+				'noheader'   => true,
158
+				'capability' => 'ee_delete_payments'
159
+			),
160
+
161
+		);
162
+
163
+	}
164
+
165
+
166
+	protected function _set_page_config()
167
+	{
168
+		$this->_page_config = array(
169
+			'default'          => array(
170
+				'nav'           => array(
171
+					'label' => esc_html__('Overview', 'event_espresso'),
172
+					'order' => 10
173
+				),
174
+				'list_table'    => 'EE_Admin_Transactions_List_Table',
175
+				'help_tabs'     => array(
176
+					'transactions_overview_help_tab'                       => array(
177
+						'title'    => esc_html__('Transactions Overview', 'event_espresso'),
178
+						'filename' => 'transactions_overview'
179
+					),
180
+					'transactions_overview_table_column_headings_help_tab' => array(
181
+						'title'    => esc_html__('Transactions Table Column Headings', 'event_espresso'),
182
+						'filename' => 'transactions_overview_table_column_headings'
183
+					),
184
+					'transactions_overview_views_filters_help_tab'         => array(
185
+						'title'    => esc_html__('Transaction Views & Filters & Search', 'event_espresso'),
186
+						'filename' => 'transactions_overview_views_filters_search'
187
+					),
188
+				),
189
+				'help_tour'     => array('Transactions_Overview_Help_Tour'),
190
+				/**
191
+				 * commented out because currently we are not displaying tips for transaction list table status but this
192
+				 * may change in a later iteration so want to keep the code for then.
193
+				 */
194
+				//'qtips' => array( 'Transactions_List_Table_Tips' ),
195
+				'require_nonce' => false
196
+			),
197
+			'view_transaction' => array(
198
+				'nav'       => array(
199
+					'label'      => esc_html__('View Transaction', 'event_espresso'),
200
+					'order'      => 5,
201
+					'url'        => isset($this->_req_data['TXN_ID']) ? add_query_arg(array('TXN_ID' => $this->_req_data['TXN_ID']),
202
+						$this->_current_page_view_url) : $this->_admin_base_url,
203
+					'persistent' => false
204
+				),
205
+				'help_tabs' => array(
206
+					'transactions_view_transaction_help_tab'                                              => array(
207
+						'title'    => esc_html__('View Transaction', 'event_espresso'),
208
+						'filename' => 'transactions_view_transaction'
209
+					),
210
+					'transactions_view_transaction_transaction_details_table_help_tab'                    => array(
211
+						'title'    => esc_html__('Transaction Details Table', 'event_espresso'),
212
+						'filename' => 'transactions_view_transaction_transaction_details_table'
213
+					),
214
+					'transactions_view_transaction_attendees_registered_help_tab'                         => array(
215
+						'title'    => esc_html__('Attendees Registered', 'event_espresso'),
216
+						'filename' => 'transactions_view_transaction_attendees_registered'
217
+					),
218
+					'transactions_view_transaction_views_primary_registrant_billing_information_help_tab' => array(
219
+						'title'    => esc_html__('Primary Registrant & Billing Information', 'event_espresso'),
220
+						'filename' => 'transactions_view_transaction_primary_registrant_billing_information'
221
+					),
222
+				),
223
+				'qtips'     => array('Transaction_Details_Tips'),
224
+				'help_tour' => array('Transaction_Details_Help_Tour'),
225
+				'metaboxes' => array('_transaction_details_metaboxes'),
226
+
227
+				'require_nonce' => false
228
+			)
229
+		);
230
+	}
231
+
232
+
233
+	/**
234
+	 * The below methods aren't used by this class currently
235
+	 */
236
+	protected function _add_screen_options()
237
+	{
238
+	}
239
+
240
+	protected function _add_feature_pointers()
241
+	{
242
+	}
243
+
244
+	public function admin_init()
245
+	{
246
+		// IF a registration was JUST added via the admin...
247
+		if (
248
+		isset(
249
+			$this->_req_data['redirect_from'],
250
+			$this->_req_data['EVT_ID'],
251
+			$this->_req_data['event_name']
252
+		)
253
+		) {
254
+			// then set a cookie so that we can block any attempts to use
255
+			// the back button as a way to enter another registration.
256
+			setcookie('ee_registration_added', $this->_req_data['EVT_ID'], time() + WEEK_IN_SECONDS, '/');
257
+			// and update the global
258
+			$_COOKIE['ee_registration_added'] = $this->_req_data['EVT_ID'];
259
+		}
260
+		EE_Registry::$i18n_js_strings['invalid_server_response'] = esc_html__('An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
261
+			'event_espresso');
262
+		EE_Registry::$i18n_js_strings['error_occurred']          = esc_html__('An error occurred! Please refresh the page and try again.',
263
+			'event_espresso');
264
+		EE_Registry::$i18n_js_strings['txn_status_array']        = self::$_txn_status;
265
+		EE_Registry::$i18n_js_strings['pay_status_array']        = self::$_pay_status;
266
+		EE_Registry::$i18n_js_strings['payments_total']          = esc_html__('Payments Total', 'event_espresso');
267
+		EE_Registry::$i18n_js_strings['transaction_overpaid']    = esc_html__('This transaction has been overpaid ! Payments Total',
268
+			'event_espresso');
269
+	}
270
+
271
+	public function admin_notices()
272
+	{
273
+	}
274
+
275
+	public function admin_footer_scripts()
276
+	{
277
+	}
278
+
279
+
280
+	/**
281
+	 * _set_transaction_status_array
282
+	 * sets list of transaction statuses
283
+	 *
284
+	 * @access private
285
+	 * @return void
286
+	 */
287
+	private function _set_transaction_status_array()
288
+	{
289
+		self::$_txn_status = EEM_Transaction::instance()->status_array(true);
290
+	}
291
+
292
+
293
+	/**
294
+	 * get_transaction_status_array
295
+	 * return the transaction status array for wp_list_table
296
+	 *
297
+	 * @access public
298
+	 * @return array
299
+	 */
300
+	public function get_transaction_status_array()
301
+	{
302
+		return self::$_txn_status;
303
+	}
304
+
305
+
306
+	/**
307
+	 *    get list of payment statuses
308
+	 *
309
+	 * @access private
310
+	 * @return void
311
+	 */
312
+	private function _get_payment_status_array()
313
+	{
314
+		self::$_pay_status                      = EEM_Payment::instance()->status_array(true);
315
+		$this->_template_args['payment_status'] = self::$_pay_status;
316
+
317
+	}
318
+
319
+
320
+	/**
321
+	 *    _add_screen_options_default
322
+	 *
323
+	 * @access protected
324
+	 * @return void
325
+	 */
326
+	protected function _add_screen_options_default()
327
+	{
328
+		$this->_per_page_screen_option();
329
+	}
330
+
331
+
332
+	/**
333
+	 * load_scripts_styles
334
+	 *
335
+	 * @access public
336
+	 * @return void
337
+	 */
338
+	public function load_scripts_styles()
339
+	{
340
+		//enqueue style
341
+		wp_register_style('espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.css', array(),
342
+			EVENT_ESPRESSO_VERSION);
343
+		wp_enqueue_style('espresso_txn');
344
+		//scripts
345
+		wp_register_script('espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.js', array(
346
+			'ee_admin_js',
347
+			'ee-datepicker',
348
+			'jquery-ui-datepicker',
349
+			'jquery-ui-draggable',
350
+			'ee-dialog',
351
+			'ee-accounting',
352
+			'ee-serialize-full-array'
353
+		), EVENT_ESPRESSO_VERSION, true);
354
+		wp_enqueue_script('espresso_txn');
355
+
356
+	}
357
+
358
+
359
+	/**
360
+	 *    load_scripts_styles_view_transaction
361
+	 *
362
+	 * @access public
363
+	 * @return void
364
+	 */
365
+	public function load_scripts_styles_view_transaction()
366
+	{
367
+		//styles
368
+		wp_enqueue_style('espresso-ui-theme');
369
+	}
370
+
371
+
372
+	/**
373
+	 *    load_scripts_styles_default
374
+	 *
375
+	 * @access public
376
+	 * @return void
377
+	 */
378
+	public function load_scripts_styles_default()
379
+	{
380
+		//styles
381
+		wp_enqueue_style('espresso-ui-theme');
382
+	}
383
+
384
+
385
+	/**
386
+	 *    _set_list_table_views_default
387
+	 *
388
+	 * @access protected
389
+	 * @return void
390
+	 */
391
+	protected function _set_list_table_views_default()
392
+	{
393
+		$this->_views = array(
394
+			'all'       => array(
395
+				'slug'  => 'all',
396
+				'label' => esc_html__('View All Transactions', 'event_espresso'),
397
+				'count' => 0
398
+			),
399
+			'abandoned' => array(
400
+				'slug'  => 'abandoned',
401
+				'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
402
+				'count' => 0
403
+			),
404
+			'failed'    => array(
405
+				'slug'  => 'failed',
406
+				'label' => esc_html__('Failed Transactions', 'event_espresso'),
407
+				'count' => 0
408
+			)
409
+		);
410
+	}
411
+
412
+
413
+	/**
414
+	 * _set_transaction_object
415
+	 * This sets the _transaction property for the transaction details screen
416
+	 *
417
+	 * @access private
418
+	 * @return void
419
+	 */
420
+	private function _set_transaction_object()
421
+	{
422
+		if (is_object($this->_transaction)) {
423
+			return;
424
+		} //get out we've already set the object
425
+
426
+		$TXN = EEM_Transaction::instance();
427
+
428
+		$TXN_ID = ( ! empty($this->_req_data['TXN_ID'])) ? absint($this->_req_data['TXN_ID']) : false;
429
+
430
+		//get transaction object
431
+		$this->_transaction = $TXN->get_one_by_ID($TXN_ID);
432
+		$this->_session     = ! empty($this->_transaction) ? $this->_transaction->get('TXN_session_data') : null;
433
+		$this->_transaction->verify_abandoned_transaction_status();
434
+
435
+		if (empty($this->_transaction)) {
436
+			$error_msg = esc_html__('An error occurred and the details for Transaction ID #',
437
+					'event_espresso') . $TXN_ID . esc_html__(' could not be retrieved.', 'event_espresso');
438
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
439
+		}
440
+	}
441
+
442
+
443
+	/**
444
+	 *    _transaction_legend_items
445
+	 *
446
+	 * @access protected
447
+	 * @return array
448
+	 */
449
+	protected function _transaction_legend_items()
450
+	{
451
+		EE_Registry::instance()->load_helper('MSG_Template');
452
+		$items = array();
453
+
454
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
455
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
456
+			if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
457
+				$items['view_related_messages'] = array(
458
+					'class' => $related_for_icon['css_class'],
459
+					'desc'  => $related_for_icon['label'],
460
+				);
461
+			}
462
+		}
463
+
464
+		$items = apply_filters(
465
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
466
+			array_merge($items,
467
+				array(
468
+					'view_details'      => array(
469
+						'class' => 'dashicons dashicons-cart',
470
+						'desc'  => esc_html__('View Transaction Details', 'event_espresso')
471
+					),
472
+					'view_invoice'      => array(
473
+						'class' => 'dashicons dashicons-media-spreadsheet',
474
+						'desc'  => esc_html__('View Transaction Invoice', 'event_espresso')
475
+					),
476
+					'view_receipt'      => array(
477
+						'class' => 'dashicons dashicons-media-default',
478
+						'desc'  => esc_html__('View Transaction Receipt', 'event_espresso')
479
+					),
480
+					'view_registration' => array(
481
+						'class' => 'dashicons dashicons-clipboard',
482
+						'desc'  => esc_html__('View Registration Details', 'event_espresso')
483
+					),
484
+					'payment_overview_link' => array(
485
+						'class' => 'dashicons dashicons-money',
486
+						'desc' => esc_html__('Make Payment on Frontend', 'event_espresso')
487
+					)
488
+				)
489
+			)
490
+		);
491
+
492
+		if (EE_Registry::instance()->CAP->current_user_can('ee_send_message',
493
+			'espresso_transactions_send_payment_reminder')
494
+		) {
495
+			if (EEH_MSG_Template::is_mt_active('payment_reminder')) {
496
+				$items['send_payment_reminder'] = array(
497
+					'class' => 'dashicons dashicons-email-alt',
498
+					'desc'  => esc_html__('Send Payment Reminder', 'event_espresso')
499
+				);
500
+			} else {
501
+				$items['blank*'] = array(
502
+					'class' => '',
503
+					'desc'  => ''
504
+				);
505
+			}
506
+		} else {
507
+			$items['blank*'] = array(
508
+				'class' => '',
509
+				'desc'  => ''
510
+			);
511
+		}
512
+		$more_items = apply_filters(
513
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
514
+			array(
515
+				'overpaid'   => array(
516
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
517
+					'desc'  => EEH_Template::pretty_status(EEM_Transaction::overpaid_status_code, false, 'sentence')
518
+				),
519
+				'complete'   => array(
520
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
521
+					'desc'  => EEH_Template::pretty_status(EEM_Transaction::complete_status_code, false, 'sentence')
522
+				),
523
+				'incomplete' => array(
524
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
525
+					'desc'  => EEH_Template::pretty_status(EEM_Transaction::incomplete_status_code, false, 'sentence')
526
+				),
527
+				'abandoned'  => array(
528
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
529
+					'desc'  => EEH_Template::pretty_status(EEM_Transaction::abandoned_status_code, false, 'sentence')
530
+				),
531
+				'failed'     => array(
532
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
533
+					'desc'  => EEH_Template::pretty_status(EEM_Transaction::failed_status_code, false, 'sentence')
534
+				)
535
+			)
536
+		);
537
+
538
+		return array_merge($items, $more_items);
539
+	}
540
+
541
+
542
+	/**
543
+	 *    _transactions_overview_list_table
544
+	 *
545
+	 * @access protected
546
+	 * @return void
547
+	 */
548
+	protected function _transactions_overview_list_table()
549
+	{
550
+		$this->_admin_page_title                   = esc_html__('Transactions', 'event_espresso');
551
+		$event                                     = isset($this->_req_data['EVT_ID']) ? EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID']) : null;
552
+		$this->_template_args['admin_page_header'] = $event instanceof EE_Event ? sprintf(esc_html__('%sViewing Transactions for the Event: %s%s',
553
+			'event_espresso'), '<h3>',
554
+			'<a href="' . EE_Admin_Page::add_query_args_and_nonce(array('action' => 'edit', 'post' => $event->ID()),
555
+				EVENTS_ADMIN_URL) . '" title="' . esc_attr__('Click to Edit event',
556
+				'event_espresso') . '">' . $event->get('EVT_name') . '</a>', '</h3>') : '';
557
+		$this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
558
+		$this->display_admin_list_table_page_with_no_sidebar();
559
+	}
560
+
561
+
562
+	/**
563
+	 *    _transaction_details
564
+	 * generates HTML for the View Transaction Details Admin page
565
+	 *
566
+	 * @access protected
567
+	 * @return void
568
+	 */
569
+	protected function _transaction_details()
570
+	{
571
+		do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
572
+
573
+		$this->_set_transaction_status_array();
574
+
575
+		$this->_template_args                      = array();
576
+		$this->_template_args['transactions_page'] = $this->_wp_page_slug;
577
+
578
+		$this->_set_transaction_object();
579
+
580
+		$primary_registration = $this->_transaction->primary_registration();
581
+		$attendee             = $primary_registration instanceof EE_Registration ? $primary_registration->attendee() : null;
582
+
583
+		$this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
584
+		$this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
585
+
586
+		$this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
587
+		$this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
588
+
589
+		$this->_template_args['txn_status']['value'] = self::$_txn_status[$this->_transaction->get('STS_ID')];
590
+		$this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
591
+		$this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
592
+
593
+		$this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
594
+		$this->_template_args['total_paid']  = $this->_transaction->get('TXN_paid');
595
+
596
+		if (
597
+			$attendee instanceof EE_Attendee
598
+			&& EE_Registry::instance()->CAP->current_user_can(
599
+				'ee_send_message',
600
+				'espresso_transactions_send_payment_reminder'
601
+			)
602
+		) {
603
+			$this->_template_args['send_payment_reminder_button'] =
604
+				EEH_MSG_Template::is_mt_active('payment_reminder')
605
+				&& $this->_transaction->get('STS_ID') != EEM_Transaction::complete_status_code
606
+				&& $this->_transaction->get('STS_ID') != EEM_Transaction::overpaid_status_code
607
+					? EEH_Template::get_button_or_link(
608
+					EE_Admin_Page::add_query_args_and_nonce(
609
+						array(
610
+							'action'      => 'send_payment_reminder',
611
+							'TXN_ID'      => $this->_transaction->ID(),
612
+							'redirect_to' => 'view_transaction'
613
+						),
614
+						TXN_ADMIN_URL
615
+					),
616
+					__(' Send Payment Reminder', 'event_espresso'),
617
+					'button secondary-button right',
618
+					'dashicons dashicons-email-alt'
619
+				)
620
+					: '';
621
+		} else {
622
+			$this->_template_args['send_payment_reminder_button'] = '';
623
+		}
624
+
625
+		$amount_due                         = $this->_transaction->get('TXN_total') - $this->_transaction->get('TXN_paid');
626
+		$this->_template_args['amount_due'] = EEH_Template::format_currency($amount_due, true);
627
+		if (EE_Registry::instance()->CFG->currency->sign_b4) {
628
+			$this->_template_args['amount_due'] = EE_Registry::instance()->CFG->currency->sign . $this->_template_args['amount_due'];
629
+		} else {
630
+			$this->_template_args['amount_due'] = $this->_template_args['amount_due'] . EE_Registry::instance()->CFG->currency->sign;
631
+		}
632
+		$this->_template_args['amount_due_class'] = '';
633
+
634
+		if ($this->_transaction->get('TXN_paid') == $this->_transaction->get('TXN_total')) {
635
+			// paid in full
636
+			$this->_template_args['amount_due'] = false;
637
+		} elseif ($this->_transaction->get('TXN_paid') > $this->_transaction->get('TXN_total')) {
638
+			// overpaid
639
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
640
+		} elseif (($this->_transaction->get('TXN_total') > 0) && ($this->_transaction->get('TXN_paid') > 0)) {
641
+			// monies owing
642
+			$this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn';
643
+		} elseif (($this->_transaction->get('TXN_total') > 0) && ($this->_transaction->get('TXN_paid') == 0)) {
644
+			// no payments made yet
645
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
646
+		} elseif ($this->_transaction->get('TXN_total') == 0) {
647
+			// free event
648
+			$this->_template_args['amount_due'] = false;
649
+		}
650
+
651
+		$payment_method = $this->_transaction->payment_method();
652
+
653
+		$this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
654
+			? $payment_method->admin_name()
655
+			: esc_html__('Unknown', 'event_espresso');
656
+
657
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
658
+		// link back to overview
659
+		$this->_template_args['txn_overview_url'] = ! empty ($_SERVER['HTTP_REFERER'])
660
+			? $_SERVER['HTTP_REFERER']
661
+			: TXN_ADMIN_URL;
662
+
663
+
664
+		// next link
665
+		$next_txn                                 = $this->_transaction->next(
666
+			null,
667
+			array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
668
+			'TXN_ID'
669
+		);
670
+		$this->_template_args['next_transaction'] = $next_txn
671
+			? $this->_next_link(
672
+				EE_Admin_Page::add_query_args_and_nonce(
673
+					array('action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']),
674
+					TXN_ADMIN_URL
675
+				),
676
+				'dashicons dashicons-arrow-right ee-icon-size-22'
677
+			)
678
+			: '';
679
+		// previous link
680
+		$previous_txn                                 = $this->_transaction->previous(
681
+			null,
682
+			array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
683
+			'TXN_ID'
684
+		);
685
+		$this->_template_args['previous_transaction'] = $previous_txn
686
+			? $this->_previous_link(
687
+				EE_Admin_Page::add_query_args_and_nonce(
688
+					array('action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']),
689
+					TXN_ADMIN_URL
690
+				),
691
+				'dashicons dashicons-arrow-left ee-icon-size-22'
692
+			)
693
+			: '';
694
+
695
+		// were we just redirected here after adding a new registration ???
696
+		if (
697
+		isset(
698
+			$this->_req_data['redirect_from'],
699
+			$this->_req_data['EVT_ID'],
700
+			$this->_req_data['event_name']
701
+		)
702
+		) {
703
+			if (
704
+			EE_Registry::instance()->CAP->current_user_can(
705
+				'ee_edit_registrations',
706
+				'espresso_registrations_new_registration',
707
+				$this->_req_data['EVT_ID']
708
+			)
709
+			) {
710
+				$this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button-primary" href="';
711
+				$this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
712
+					array(
713
+						'page'     => 'espresso_registrations',
714
+						'action'   => 'new_registration',
715
+						'return'   => 'default',
716
+						'TXN_ID'   => $this->_transaction->ID(),
717
+						'event_id' => $this->_req_data['EVT_ID'],
718
+					),
719
+					REG_ADMIN_URL
720
+				);
721
+				$this->_admin_page_title .= '">';
722
+
723
+				$this->_admin_page_title .= sprintf(
724
+					esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
725
+					htmlentities(urldecode($this->_req_data['event_name']), ENT_QUOTES, 'UTF-8')
726
+				);
727
+				$this->_admin_page_title .= '</a>';
728
+			}
729
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
730
+		}
731
+		// grab messages at the last second
732
+		$this->_template_args['notices'] = EE_Error::get_notices();
733
+		// path to template
734
+		$template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
735
+		$this->_template_args['admin_page_header'] = EEH_Template::display_template($template_path,
736
+			$this->_template_args, true);
737
+
738
+		// the details template wrapper
739
+		$this->display_admin_page_with_sidebar();
740
+
741
+	}
742
+
743
+
744
+	/**
745
+	 *        _transaction_details_metaboxes
746
+	 *
747
+	 * @access protected
748
+	 * @return void
749
+	 */
750
+	protected function _transaction_details_metaboxes()
751
+	{
752
+
753
+		$this->_set_transaction_object();
754
+
755
+		add_meta_box('edit-txn-details-mbox', esc_html__('Transaction Details', 'event_espresso'),
756
+			array($this, 'txn_details_meta_box'), $this->_wp_page_slug, 'normal', 'high');
757
+		add_meta_box(
758
+			'edit-txn-attendees-mbox',
759
+			esc_html__('Attendees Registered in this Transaction', 'event_espresso'),
760
+			array($this, 'txn_attendees_meta_box'),
761
+			$this->_wp_page_slug,
762
+			'normal',
763
+			'high',
764
+			array('TXN_ID' => $this->_transaction->ID())
765
+		);
766
+		add_meta_box('edit-txn-registrant-mbox', esc_html__('Primary Contact', 'event_espresso'),
767
+			array($this, 'txn_registrant_side_meta_box'), $this->_wp_page_slug, 'side', 'high');
768
+		add_meta_box('edit-txn-billing-info-mbox', esc_html__('Billing Information', 'event_espresso'),
769
+			array($this, 'txn_billing_info_side_meta_box'), $this->_wp_page_slug, 'side', 'high');
770
+
771
+	}
772
+
773
+
774
+	/**
775
+	 * txn_details_meta_box
776
+	 * generates HTML for the Transaction main meta box
777
+	 *
778
+	 * @access public
779
+	 * @return void
780
+	 */
781
+	public function txn_details_meta_box()
782
+	{
783
+
784
+		$this->_set_transaction_object();
785
+		$this->_template_args['TXN_ID']   = $this->_transaction->ID();
786
+		$this->_template_args['attendee'] = $this->_transaction->primary_registration() instanceof EE_Registration ? $this->_transaction->primary_registration()->attendee() : null;
787
+
788
+		//get line table
789
+		EEH_Autoloader::register_line_item_display_autoloaders();
790
+		$Line_Item_Display                       = new EE_Line_Item_Display('admin_table',
791
+			'EE_Admin_Table_Line_Item_Display_Strategy');
792
+		$this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item($this->_transaction->total_line_item());
793
+		$this->_template_args['REG_code']        = $this->_transaction->get_first_related('Registration')->get('REG_code');
794
+
795
+		// process taxes
796
+		$taxes                         = $this->_transaction->get_many_related('Line_Item',
797
+			array(array('LIN_type' => EEM_Line_Item::type_tax)));
798
+		$this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
799
+
800
+		$this->_template_args['grand_total']     = EEH_Template::format_currency($this->_transaction->get('TXN_total'),
801
+			false, false);
802
+		$this->_template_args['grand_raw_total'] = $this->_transaction->get('TXN_total');
803
+		$this->_template_args['TXN_status']      = $this->_transaction->get('STS_ID');
804 804
 
805 805
 //		$txn_status_class = 'status-' . $this->_transaction->get('STS_ID');
806 806
 
807
-        // process payment details
808
-        $payments = $this->_transaction->get_many_related('Payment');
809
-        if ( ! empty($payments)) {
810
-            $this->_template_args['payments']              = $payments;
811
-            $this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
812
-        } else {
813
-            $this->_template_args['payments']              = false;
814
-            $this->_template_args['existing_reg_payments'] = array();
815
-        }
816
-
817
-        $this->_template_args['edit_payment_url']   = add_query_arg(array('action' => 'edit_payment'), TXN_ADMIN_URL);
818
-        $this->_template_args['delete_payment_url'] = add_query_arg(array('action' => 'espresso_delete_payment'),
819
-            TXN_ADMIN_URL);
820
-
821
-        if (isset($txn_details['invoice_number'])) {
822
-            $this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
823
-            $this->_template_args['txn_details']['invoice_number']['label'] = esc_html__('Invoice Number',
824
-                'event_espresso');
825
-        }
826
-
827
-        $this->_template_args['txn_details']['registration_session']['value'] = $this->_transaction->get_first_related('Registration')->get('REG_session');
828
-        $this->_template_args['txn_details']['registration_session']['label'] = esc_html__('Registration Session',
829
-            'event_espresso');
830
-
831
-        $this->_template_args['txn_details']['ip_address']['value'] = isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '';
832
-        $this->_template_args['txn_details']['ip_address']['label'] = esc_html__('Transaction placed from IP',
833
-            'event_espresso');
834
-
835
-        $this->_template_args['txn_details']['user_agent']['value'] = isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '';
836
-        $this->_template_args['txn_details']['user_agent']['label'] = esc_html__('Registrant User Agent',
837
-            'event_espresso');
838
-
839
-        $reg_steps = '<ul>';
840
-        foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
841
-            if ($reg_step_status === true) {
842
-                $reg_steps .= '<li style="color:#70cc50">' . sprintf(esc_html__('%1$s : Completed', 'event_espresso'),
843
-                        ucwords(str_replace('_', ' ', $reg_step))) . '</li>';
844
-            } else if (is_numeric($reg_step_status) && $reg_step_status !== false) {
845
-                $reg_steps .= '<li style="color:#2EA2CC">' . sprintf(
846
-                        esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
847
-                        ucwords(str_replace('_', ' ', $reg_step)),
848
-                        date(get_option('date_format') . ' ' . get_option('time_format'),
849
-                            ($reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS)))
850
-                    ) . '</li>';
851
-            } else {
852
-                $reg_steps .= '<li style="color:#E76700">' . sprintf(esc_html__('%1$s : Never Initiated',
853
-                        'event_espresso'), ucwords(str_replace('_', ' ', $reg_step))) . '</li>';
854
-            }
855
-        }
856
-        $reg_steps .= '</ul>';
857
-        $this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
858
-        $this->_template_args['txn_details']['reg_steps']['label'] = esc_html__('Registration Step Progress',
859
-            'event_espresso');
860
-
861
-
862
-        $this->_get_registrations_to_apply_payment_to();
863
-        $this->_get_payment_methods($payments);
864
-        $this->_get_payment_status_array();
865
-        $this->_get_reg_status_selection(); //sets up the template args for the reg status array for the transaction.
866
-
867
-        $this->_template_args['transaction_form_url']    = add_query_arg(array(
868
-            'action'  => 'edit_transaction',
869
-            'process' => 'transaction'
870
-        ), TXN_ADMIN_URL);
871
-        $this->_template_args['apply_payment_form_url']  = add_query_arg(array(
872
-            'page'   => 'espresso_transactions',
873
-            'action' => 'espresso_apply_payment'
874
-        ), WP_AJAX_URL);
875
-        $this->_template_args['delete_payment_form_url'] = add_query_arg(array(
876
-            'page'   => 'espresso_transactions',
877
-            'action' => 'espresso_delete_payment'
878
-        ), WP_AJAX_URL);
879
-
880
-        // 'espresso_delete_payment_nonce'
881
-
882
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
883
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
884
-
885
-    }
886
-
887
-
888
-    /**
889
-     * _get_registration_payment_IDs
890
-     *
891
-     *    generates an array of Payment IDs and their corresponding Registration IDs
892
-     *
893
-     * @access protected
894
-     *
895
-     * @param EE_Payment[] $payments
896
-     *
897
-     * @return array
898
-     */
899
-    protected function _get_registration_payment_IDs($payments = array())
900
-    {
901
-        $existing_reg_payments = array();
902
-        // get all reg payments for these payments
903
-        $reg_payments = EEM_Registration_Payment::instance()->get_all(array(
904
-            array(
905
-                'PAY_ID' => array(
906
-                    'IN',
907
-                    array_keys($payments)
908
-                )
909
-            )
910
-        ));
911
-        if ( ! empty($reg_payments)) {
912
-            foreach ($payments as $payment) {
913
-                if ( ! $payment instanceof EE_Payment) {
914
-                    continue;
915
-                } else if ( ! isset($existing_reg_payments[$payment->ID()])) {
916
-                    $existing_reg_payments[$payment->ID()] = array();
917
-                }
918
-                foreach ($reg_payments as $reg_payment) {
919
-                    if ($reg_payment instanceof EE_Registration_Payment && $reg_payment->payment_ID() === $payment->ID()) {
920
-                        $existing_reg_payments[$payment->ID()][] = $reg_payment->registration_ID();
921
-                    }
922
-                }
923
-            }
924
-        }
925
-
926
-        return $existing_reg_payments;
927
-    }
928
-
929
-
930
-    /**
931
-     * _get_registrations_to_apply_payment_to
932
-     *    generates HTML for displaying a series of checkboxes in the admin payment modal window
933
-     * which allows the admin to only apply the payment to the specific registrations
934
-     *
935
-     * @access protected
936
-     * @return void
937
-     * @throws \EE_Error
938
-     */
939
-    protected function _get_registrations_to_apply_payment_to()
940
-    {
941
-        // we want any registration with an active status (ie: not deleted or cancelled)
942
-        $query_params                      = array(
943
-            array(
944
-                'STS_ID' => array(
945
-                    'IN',
946
-                    array(
947
-                        EEM_Registration::status_id_approved,
948
-                        EEM_Registration::status_id_pending_payment,
949
-                        EEM_Registration::status_id_not_approved,
950
-                    )
951
-                )
952
-            )
953
-        );
954
-        $registrations_to_apply_payment_to = EEH_HTML::br() . EEH_HTML::div(
955
-                '', 'txn-admin-apply-payment-to-registrations-dv', '', 'clear: both; margin: 1.5em 0 0; display: none;'
956
-            );
957
-        $registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
958
-        $registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl');
959
-        $registrations_to_apply_payment_to .= EEH_HTML::thead(
960
-            EEH_HTML::tr(
961
-                EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
962
-                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
963
-                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
964
-                EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
965
-                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
966
-                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
967
-                EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
968
-            )
969
-        );
970
-        $registrations_to_apply_payment_to .= EEH_HTML::tbody();
971
-        // get registrations for TXN
972
-        $registrations = $this->_transaction->registrations($query_params);
973
-        foreach ($registrations as $registration) {
974
-            if ($registration instanceof EE_Registration) {
975
-                $attendee_name = $registration->attendee() instanceof EE_Attendee
976
-                    ? $registration->attendee()->full_name()
977
-                    : esc_html__('Unknown Attendee', 'event_espresso');
978
-                $owing         = $registration->final_price() - $registration->paid();
979
-                $taxable       = $registration->ticket()->taxable()
980
-                    ? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
981
-                    : '';
982
-                $checked       = empty($existing_reg_payments) || in_array($registration->ID(), $existing_reg_payments)
983
-                    ? ' checked="checked"'
984
-                    : '';
985
-                $disabled      = $registration->final_price() > 0 ? '' : ' disabled';
986
-                $registrations_to_apply_payment_to .= EEH_HTML::tr(
987
-                    EEH_HTML::td($registration->ID()) .
988
-                    EEH_HTML::td($attendee_name) .
989
-                    EEH_HTML::td(
990
-                        $registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
991
-                    ) .
992
-                    EEH_HTML::td($registration->event_name()) .
993
-                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
994
-                    EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr') .
995
-                    EEH_HTML::td(
996
-                        '<input type="checkbox" value="' . $registration->ID()
997
-                        . '" name="txn_admin_payment[registrations]"'
998
-                        . $checked . $disabled . '>',
999
-                        '', 'jst-cntr'
1000
-                    ),
1001
-                    'apply-payment-registration-row-' . $registration->ID()
1002
-                );
1003
-            }
1004
-        }
1005
-        $registrations_to_apply_payment_to .= EEH_HTML::tbodyx();
1006
-        $registrations_to_apply_payment_to .= EEH_HTML::tablex();
1007
-        $registrations_to_apply_payment_to .= EEH_HTML::divx();
1008
-        $registrations_to_apply_payment_to .= EEH_HTML::p(
1009
-            esc_html__(
1010
-                'The payment will only be applied to the registrations that have a check mark in their corresponding check box. Checkboxes for free registrations have been disabled.',
1011
-                'event_espresso'
1012
-            ),
1013
-            '', 'clear description'
1014
-        );
1015
-        $registrations_to_apply_payment_to .= EEH_HTML::divx();
1016
-        $this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1017
-    }
1018
-
1019
-
1020
-    /**
1021
-     * _get_reg_status_selection
1022
-     *
1023
-     * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1024
-     *         instead of events.
1025
-     * @access protected
1026
-     * @return void
1027
-     */
1028
-    protected function _get_reg_status_selection()
1029
-    {
1030
-        //first get all possible statuses
1031
-        $statuses = EEM_Registration::reg_status_array(array(), true);
1032
-        //let's add a "don't change" option.
1033
-        $status_array['NAN']                                 = esc_html__('Leave the Same', 'event_espresso');
1034
-        $status_array                                        = array_merge($status_array, $statuses);
1035
-        $this->_template_args['status_change_select']        = EEH_Form_Fields::select_input('txn_reg_status_change[reg_status]',
1036
-            $status_array, 'NAN', 'id="txn-admin-payment-reg-status-inp"', 'txn-reg-status-change-reg-status');
1037
-        $this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input('delete_txn_reg_status_change[reg_status]',
1038
-            $status_array, 'NAN', 'delete-txn-admin-payment-reg-status-inp', 'delete-txn-reg-status-change-reg-status');
1039
-
1040
-    }
1041
-
1042
-
1043
-    /**
1044
-     *    _get_payment_methods
1045
-     * Gets all the payment methods available generally, or the ones that are already
1046
-     * selected on these payments (in case their payment methods are no longer active).
1047
-     * Has the side-effect of updating the template args' payment_methods item
1048
-     * @access private
1049
-     *
1050
-     * @param EE_Payment[] to show on this page
1051
-     *
1052
-     * @return void
1053
-     */
1054
-    private function _get_payment_methods($payments = array())
1055
-    {
1056
-        $payment_methods_of_payments = array();
1057
-        foreach ($payments as $payment) {
1058
-            if ($payment instanceof EE_Payment) {
1059
-                $payment_methods_of_payments[] = $payment->get('PMD_ID');
1060
-            }
1061
-        }
1062
-        if ($payment_methods_of_payments) {
1063
-            $query_args = array(
1064
-                array(
1065
-                    'OR*payment_method_for_payment' => array(
1066
-                        'PMD_ID'    => array('IN', $payment_methods_of_payments),
1067
-                        'PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')
1068
-                    )
1069
-                )
1070
-            );
1071
-        } else {
1072
-            $query_args = array(array('PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')));
1073
-        }
1074
-        $this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1075
-    }
1076
-
1077
-
1078
-    /**
1079
-     * txn_attendees_meta_box
1080
-     *    generates HTML for the Attendees Transaction main meta box
1081
-     *
1082
-     * @access public
1083
-     *
1084
-     * @param WP_Post $post
1085
-     * @param array   $metabox
1086
-     *
1087
-     * @return void
1088
-     */
1089
-    public function txn_attendees_meta_box($post, $metabox = array('args' => array()))
1090
-    {
1091
-
1092
-        extract($metabox['args']);
1093
-        $this->_template_args['post']            = $post;
1094
-        $this->_template_args['event_attendees'] = array();
1095
-        // process items in cart
1096
-        $line_items = $this->_transaction->get_many_related('Line_Item', array(array('LIN_type' => 'line-item')));
1097
-        if ( ! empty($line_items)) {
1098
-            foreach ($line_items as $item) {
1099
-                if ($item instanceof EE_Line_Item) {
1100
-                    switch ($item->OBJ_type()) {
1101
-
1102
-                        case 'Event' :
1103
-                            break;
1104
-
1105
-                        case 'Ticket' :
1106
-                            $ticket = $item->ticket();
1107
-                            //right now we're only handling tickets here.  Cause its expected that only tickets will have attendees right?
1108
-                            if ( ! $ticket instanceof EE_Ticket) {
1109
-                                continue;
1110
-                            }
1111
-                            try {
1112
-                                $event_name = $ticket->get_event_name();
1113
-                            } catch (Exception $e) {
1114
-                                EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1115
-                                $event_name = esc_html__('Unknown Event', 'event_espresso');
1116
-                            }
1117
-                            $event_name .= ' - ' . $item->get('LIN_name');
1118
-                            $ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
1119
-                            // now get all of the registrations for this transaction that use this ticket
1120
-                            $registrations = $ticket->get_many_related('Registration',
1121
-                                array(array('TXN_ID' => $this->_transaction->ID())));
1122
-                            foreach ($registrations as $registration) {
1123
-                                if ( ! $registration instanceof EE_Registration) {
1124
-                                    continue;
1125
-                                }
1126
-                                $this->_template_args['event_attendees'][$registration->ID()]['STS_ID']            = $registration->status_ID();
1127
-                                $this->_template_args['event_attendees'][$registration->ID()]['att_num']           = $registration->count();
1128
-                                $this->_template_args['event_attendees'][$registration->ID()]['event_ticket_name'] = $event_name;
1129
-                                $this->_template_args['event_attendees'][$registration->ID()]['ticket_price']      = $ticket_price;
1130
-                                // attendee info
1131
-                                $attendee = $registration->get_first_related('Attendee');
1132
-                                if ($attendee instanceof EE_Attendee) {
1133
-                                    $this->_template_args['event_attendees'][$registration->ID()]['att_id']   = $attendee->ID();
1134
-                                    $this->_template_args['event_attendees'][$registration->ID()]['attendee'] = $attendee->full_name();
1135
-                                    $this->_template_args['event_attendees'][$registration->ID()]['email']    = '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name . esc_html__(' Event',
1136
-                                            'event_espresso') . '">' . $attendee->email() . '</a>';
1137
-                                    $this->_template_args['event_attendees'][$registration->ID()]['address']  = EEH_Address::format($attendee,
1138
-                                        'inline', false, false);
1139
-                                } else {
1140
-                                    $this->_template_args['event_attendees'][$registration->ID()]['att_id']   = '';
1141
-                                    $this->_template_args['event_attendees'][$registration->ID()]['attendee'] = '';
1142
-                                    $this->_template_args['event_attendees'][$registration->ID()]['email']    = '';
1143
-                                    $this->_template_args['event_attendees'][$registration->ID()]['address']  = '';
1144
-                                }
1145
-                            }
1146
-                            break;
1147
-
1148
-                    }
1149
-                }
1150
-            }
1151
-
1152
-            $this->_template_args['transaction_form_url'] = add_query_arg(array(
1153
-                'action'  => 'edit_transaction',
1154
-                'process' => 'attendees'
1155
-            ), TXN_ADMIN_URL);
1156
-            echo EEH_Template::display_template(TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1157
-                $this->_template_args, true);
1158
-
1159
-        } else {
1160
-            echo sprintf(
1161
-                esc_html__('%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1162
-                    'event_espresso'),
1163
-                '<p class="important-notice">',
1164
-                '</p>'
1165
-            );
1166
-        }
1167
-    }
1168
-
1169
-
1170
-    /**
1171
-     * txn_registrant_side_meta_box
1172
-     * generates HTML for the Edit Transaction side meta box
1173
-     *
1174
-     * @access public
1175
-     * @throws \EE_Error
1176
-     * @return void
1177
-     */
1178
-    public function txn_registrant_side_meta_box()
1179
-    {
1180
-        $primary_att = $this->_transaction->primary_registration() instanceof EE_Registration ? $this->_transaction->primary_registration()->get_first_related('Attendee') : null;
1181
-        if ( ! $primary_att instanceof EE_Attendee) {
1182
-            $this->_template_args['no_attendee_message'] = esc_html__('There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1183
-                'event_espresso');
1184
-            $primary_att                                 = EEM_Attendee::instance()->create_default_object();
1185
-        }
1186
-        $this->_template_args['ATT_ID']            = $primary_att->ID();
1187
-        $this->_template_args['prime_reg_fname']   = $primary_att->fname();
1188
-        $this->_template_args['prime_reg_lname']   = $primary_att->lname();
1189
-        $this->_template_args['prime_reg_email']   = $primary_att->email();
1190
-        $this->_template_args['prime_reg_phone']   = $primary_att->phone();
1191
-        $this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(array(
1192
-            'action' => 'edit_attendee',
1193
-            'post'   => $primary_att->ID()
1194
-        ), REG_ADMIN_URL);
1195
-        // get formatted address for registrant
1196
-        $this->_template_args['formatted_address'] = EEH_Address::format($primary_att);
1197
-        echo EEH_Template::display_template(TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1198
-            $this->_template_args, true);
1199
-    }
1200
-
1201
-
1202
-    /**
1203
-     * txn_billing_info_side_meta_box
1204
-     *    generates HTML for the Edit Transaction side meta box
1205
-     *
1206
-     * @access public
1207
-     * @return void
1208
-     */
1209
-    public function txn_billing_info_side_meta_box()
1210
-    {
1211
-
1212
-        $this->_template_args['billing_form']     = $this->_transaction->billing_info();
1213
-        $this->_template_args['billing_form_url'] = add_query_arg(
1214
-            array('action' => 'edit_transaction', 'process' => 'billing'),
1215
-            TXN_ADMIN_URL
1216
-        );
1217
-
1218
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1219
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);/**/
1220
-    }
1221
-
1222
-
1223
-    /**
1224
-     * apply_payments_or_refunds
1225
-     *    registers a payment or refund made towards a transaction
1226
-     *
1227
-     * @access public
1228
-     * @return void
1229
-     */
1230
-    public function apply_payments_or_refunds()
1231
-    {
1232
-        $json_response_data = array('return_data' => false);
1233
-        $valid_data         = $this->_validate_payment_request_data();
1234
-        if ( ! empty($valid_data)) {
1235
-            $PAY_ID = $valid_data['PAY_ID'];
1236
-            //save  the new payment
1237
-            $payment = $this->_create_payment_from_request_data($valid_data);
1238
-            // get the TXN for this payment
1239
-            $transaction = $payment->transaction();
1240
-            // verify transaction
1241
-            if ($transaction instanceof EE_Transaction) {
1242
-                // calculate_total_payments_and_update_status
1243
-                $this->_process_transaction_payments($transaction);
1244
-                $REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1245
-                $this->_remove_existing_registration_payments($payment, $PAY_ID);
1246
-                // apply payment to registrations (if applicable)
1247
-                if ( ! empty($REG_IDs)) {
1248
-                    $this->_update_registration_payments($transaction, $payment, $REG_IDs);
1249
-                    $this->_maybe_send_notifications();
1250
-                    // now process status changes for the same registrations
1251
-                    $this->_process_registration_status_change($transaction, $REG_IDs);
1252
-                }
1253
-                $this->_maybe_send_notifications($payment);
1254
-                //prepare to render page
1255
-                $json_response_data['return_data'] = $this->_build_payment_json_response($payment, $REG_IDs);
1256
-                do_action('AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording', $transaction,
1257
-                    $payment);
1258
-            } else {
1259
-                EE_Error::add_error(
1260
-                    esc_html__('A valid Transaction for this payment could not be retrieved.', 'event_espresso'),
1261
-                    __FILE__, __FUNCTION__, __LINE__
1262
-                );
1263
-            }
1264
-        } else {
1265
-            EE_Error::add_error(esc_html__('The payment form data could not be processed. Please try again.',
1266
-                'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
1267
-        }
1268
-
1269
-        $notices              = EE_Error::get_notices(false, false, false);
1270
-        $this->_template_args = array(
1271
-            'data'    => $json_response_data,
1272
-            'error'   => $notices['errors'],
1273
-            'success' => $notices['success']
1274
-        );
1275
-        $this->_return_json();
1276
-    }
1277
-
1278
-
1279
-    /**
1280
-     * _validate_payment_request_data
1281
-     *
1282
-     * @return array
1283
-     */
1284
-    protected function _validate_payment_request_data()
1285
-    {
1286
-        if ( ! isset($this->_req_data['txn_admin_payment'])) {
1287
-            return false;
1288
-        }
1289
-        $payment_form = $this->_generate_payment_form_section();
1290
-        try {
1291
-            if ($payment_form->was_submitted()) {
1292
-                $payment_form->receive_form_submission();
1293
-                if ( ! $payment_form->is_valid()) {
1294
-                    $submission_error_messages = array();
1295
-                    foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1296
-                        if ($validation_error instanceof EE_Validation_Error) {
1297
-                            $submission_error_messages[] = sprintf(
1298
-                                _x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1299
-                                $validation_error->get_form_section()->html_label_text(),
1300
-                                $validation_error->getMessage()
1301
-                            );
1302
-                        }
1303
-                    }
1304
-                    EE_Error::add_error(join('<br />', $submission_error_messages), __FILE__, __FUNCTION__, __LINE__);
1305
-
1306
-                    return array();
1307
-                }
1308
-            }
1309
-        } catch (EE_Error $e) {
1310
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1311
-
1312
-            return array();
1313
-        }
1314
-
1315
-        return $payment_form->valid_data();
1316
-    }
1317
-
1318
-
1319
-    /**
1320
-     * _generate_payment_form_section
1321
-     *
1322
-     * @return EE_Form_Section_Proper
1323
-     */
1324
-    protected function _generate_payment_form_section()
1325
-    {
1326
-        return new EE_Form_Section_Proper(
1327
-            array(
1328
-                'name'        => 'txn_admin_payment',
1329
-                'subsections' => array(
1330
-                    'PAY_ID'          => new EE_Text_Input(
1331
-                        array(
1332
-                            'default'               => 0,
1333
-                            'required'              => false,
1334
-                            'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1335
-                            'validation_strategies' => array(new EE_Int_Normalization())
1336
-                        )
1337
-                    ),
1338
-                    'TXN_ID'          => new EE_Text_Input(
1339
-                        array(
1340
-                            'default'               => 0,
1341
-                            'required'              => true,
1342
-                            'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1343
-                            'validation_strategies' => array(new EE_Int_Normalization())
1344
-                        )
1345
-                    ),
1346
-                    'type'            => new EE_Text_Input(
1347
-                        array(
1348
-                            'default'               => 1,
1349
-                            'required'              => true,
1350
-                            'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1351
-                            'validation_strategies' => array(new EE_Int_Normalization())
1352
-                        )
1353
-                    ),
1354
-                    'amount'          => new EE_Text_Input(
1355
-                        array(
1356
-                            'default'               => 0,
1357
-                            'required'              => true,
1358
-                            'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1359
-                            'validation_strategies' => array(new EE_Float_Normalization())
1360
-                        )
1361
-                    ),
1362
-                    'status'          => new EE_Text_Input(
1363
-                        array(
1364
-                            'default'         => EEM_Payment::status_id_approved,
1365
-                            'required'        => true,
1366
-                            'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1367
-                        )
1368
-                    ),
1369
-                    'PMD_ID'          => new EE_Text_Input(
1370
-                        array(
1371
-                            'default'               => 2,
1372
-                            'required'              => true,
1373
-                            'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1374
-                            'validation_strategies' => array(new EE_Int_Normalization())
1375
-                        )
1376
-                    ),
1377
-                    'date'            => new EE_Text_Input(
1378
-                        array(
1379
-                            'default'         => time(),
1380
-                            'required'        => true,
1381
-                            'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1382
-                        )
1383
-                    ),
1384
-                    'txn_id_chq_nmbr' => new EE_Text_Input(
1385
-                        array(
1386
-                            'default'               => '',
1387
-                            'required'              => false,
1388
-                            'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1389
-                            'validation_strategies' => array(
1390
-                                new EE_Max_Length_Validation_Strategy(esc_html__('Input too long', 'event_espresso'),
1391
-                                    100),
1392
-                            )
1393
-                        )
1394
-                    ),
1395
-                    'po_number'       => new EE_Text_Input(
1396
-                        array(
1397
-                            'default'               => '',
1398
-                            'required'              => false,
1399
-                            'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1400
-                            'validation_strategies' => array(
1401
-                                new EE_Max_Length_Validation_Strategy(esc_html__('Input too long', 'event_espresso'),
1402
-                                    100),
1403
-                            )
1404
-                        )
1405
-                    ),
1406
-                    'accounting'      => new EE_Text_Input(
1407
-                        array(
1408
-                            'default'               => '',
1409
-                            'required'              => false,
1410
-                            'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1411
-                            'validation_strategies' => array(
1412
-                                new EE_Max_Length_Validation_Strategy(esc_html__('Input too long', 'event_espresso'),
1413
-                                    100),
1414
-                            )
1415
-                        )
1416
-                    ),
1417
-                )
1418
-            )
1419
-        );
1420
-    }
1421
-
1422
-
1423
-    /**
1424
-     * _create_payment_from_request_data
1425
-     *
1426
-     * @param array $valid_data
1427
-     *
1428
-     * @return EE_Payment
1429
-     */
1430
-    protected function _create_payment_from_request_data($valid_data)
1431
-    {
1432
-        $PAY_ID = $valid_data['PAY_ID'];
1433
-        // get payment amount
1434
-        $amount = $valid_data['amount'] ? abs($valid_data['amount']) : 0;
1435
-        // payments have a type value of 1 and refunds have a type value of -1
1436
-        // so multiplying amount by type will give a positive value for payments, and negative values for refunds
1437
-        $amount = $valid_data['type'] < 0 ? $amount * -1 : $amount;
1438
-        // for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1439
-        $date    = $valid_data['date'] ? preg_replace('/\s+/', ' ', $valid_data['date']) : date('Y-m-d g:i a',
1440
-            current_time('timestamp'));
1441
-        $payment = EE_Payment::new_instance(
1442
-            array(
1443
-                'TXN_ID'              => $valid_data['TXN_ID'],
1444
-                'STS_ID'              => $valid_data['status'],
1445
-                'PAY_timestamp'       => $date,
1446
-                'PAY_source'          => EEM_Payment_Method::scope_admin,
1447
-                'PMD_ID'              => $valid_data['PMD_ID'],
1448
-                'PAY_amount'          => $amount,
1449
-                'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1450
-                'PAY_po_number'       => $valid_data['po_number'],
1451
-                'PAY_extra_accntng'   => $valid_data['accounting'],
1452
-                'PAY_details'         => $valid_data,
1453
-                'PAY_ID'              => $PAY_ID
1454
-            ),
1455
-            '',
1456
-            array('Y-m-d', 'g:i a')
1457
-        );
1458
-
1459
-        if ( ! $payment->save()) {
1460
-            EE_Error::add_error(
1461
-                sprintf(
1462
-                    esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1463
-                    $payment->ID()
1464
-                ),
1465
-                __FILE__, __FUNCTION__, __LINE__
1466
-            );
1467
-        }
1468
-
1469
-        return $payment;
1470
-    }
1471
-
1472
-
1473
-    /**
1474
-     * _process_transaction_payments
1475
-     *
1476
-     * @param \EE_Transaction $transaction
1477
-     *
1478
-     * @return array
1479
-     */
1480
-    protected function _process_transaction_payments(EE_Transaction $transaction)
1481
-    {
1482
-        /** @type EE_Transaction_Payments $transaction_payments */
1483
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1484
-        //update the transaction with this payment
1485
-        if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1486
-            EE_Error::add_success(esc_html__('The payment has been processed successfully.', 'event_espresso'),
1487
-                __FILE__, __FUNCTION__, __LINE__);
1488
-        } else {
1489
-            EE_Error::add_error(
1490
-                esc_html__('The payment was processed successfully but the amount paid for the transaction was not updated.',
1491
-                    'event_espresso')
1492
-                , __FILE__, __FUNCTION__, __LINE__
1493
-            );
1494
-        }
1495
-    }
1496
-
1497
-
1498
-    /**
1499
-     * _get_REG_IDs_to_apply_payment_to
1500
-     *
1501
-     * returns a list of registration IDs that the payment will apply to
1502
-     *
1503
-     * @param \EE_Payment $payment
1504
-     *
1505
-     * @return array
1506
-     */
1507
-    protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1508
-    {
1509
-        $REG_IDs = array();
1510
-        // grab array of IDs for specific registrations to apply changes to
1511
-        if (isset($this->_req_data['txn_admin_payment']['registrations'])) {
1512
-            $REG_IDs = (array)$this->_req_data['txn_admin_payment']['registrations'];
1513
-        }
1514
-        //nothing specified ? then get all reg IDs
1515
-        if (empty($REG_IDs)) {
1516
-            $registrations = $payment->transaction()->registrations();
1517
-            $REG_IDs       = ! empty($registrations) ? array_keys($registrations) : $this->_get_existing_reg_payment_REG_IDs($payment);
1518
-        }
1519
-
1520
-        // ensure that REG_IDs are integers and NOT strings
1521
-        return array_map('intval', $REG_IDs);
1522
-    }
1523
-
1524
-
1525
-    /**
1526
-     * @return array
1527
-     */
1528
-    public function existing_reg_payment_REG_IDs()
1529
-    {
1530
-        return $this->_existing_reg_payment_REG_IDs;
1531
-    }
1532
-
1533
-
1534
-    /**
1535
-     * @param array $existing_reg_payment_REG_IDs
1536
-     */
1537
-    public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1538
-    {
1539
-        $this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1540
-    }
1541
-
1542
-
1543
-    /**
1544
-     * _get_existing_reg_payment_REG_IDs
1545
-     *
1546
-     * returns a list of registration IDs that the payment is currently related to
1547
-     * as recorded in the database
1548
-     *
1549
-     * @param \EE_Payment $payment
1550
-     *
1551
-     * @return array
1552
-     */
1553
-    protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
1554
-    {
1555
-        if ($this->existing_reg_payment_REG_IDs() === null) {
1556
-            // let's get any existing reg payment records for this payment
1557
-            $existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
1558
-            // but we only want the REG IDs, so grab the array keys
1559
-            $existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs) ? array_keys($existing_reg_payment_REG_IDs) : array();
1560
-            $this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
1561
-        }
1562
-
1563
-        return $this->existing_reg_payment_REG_IDs();
1564
-    }
1565
-
1566
-
1567
-    /**
1568
-     * _remove_existing_registration_payments
1569
-     *
1570
-     * this calculates the difference between existing relations
1571
-     * to the supplied payment and the new list registration IDs,
1572
-     * removes any related registrations that no longer apply,
1573
-     * and then updates the registration paid fields
1574
-     *
1575
-     * @param \EE_Payment $payment
1576
-     * @param int         $PAY_ID
1577
-     *
1578
-     * @return bool;
1579
-     */
1580
-    protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
1581
-    {
1582
-        // newly created payments will have nothing recorded for $PAY_ID
1583
-        if ($PAY_ID == 0) {
1584
-            return false;
1585
-        }
1586
-        $existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
1587
-        if (empty($existing_reg_payment_REG_IDs)) {
1588
-            return false;
1589
-        }
1590
-        /** @type EE_Transaction_Payments $transaction_payments */
1591
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1592
-
1593
-        return $transaction_payments->delete_registration_payments_and_update_registrations(
1594
-            $payment,
1595
-            array(
1596
-                array(
1597
-                    'PAY_ID' => $payment->ID(),
1598
-                    'REG_ID' => array('IN', $existing_reg_payment_REG_IDs),
1599
-                )
1600
-            )
1601
-        );
1602
-    }
1603
-
1604
-
1605
-    /**
1606
-     * _update_registration_payments
1607
-     *
1608
-     * this applies the payments to the selected registrations
1609
-     * but only if they have not already been paid for
1610
-     *
1611
-     * @param  EE_Transaction $transaction
1612
-     * @param \EE_Payment     $payment
1613
-     * @param array           $REG_IDs
1614
-     *
1615
-     * @return bool
1616
-     */
1617
-    protected function _update_registration_payments(
1618
-        EE_Transaction $transaction,
1619
-        EE_Payment $payment,
1620
-        $REG_IDs = array()
1621
-    ) {
1622
-        // we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
1623
-        // so let's do that using our set of REG_IDs from the form
1624
-        $registration_query_where_params = array(
1625
-            'REG_ID' => array('IN', $REG_IDs)
1626
-        );
1627
-        // but add in some conditions regarding payment,
1628
-        // so that we don't apply payments to registrations that are free or have already been paid for
1629
-        // but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
1630
-        if ( ! $payment->is_a_refund()) {
1631
-            $registration_query_where_params['REG_final_price']  = array('!=', 0);
1632
-            $registration_query_where_params['REG_final_price*'] = array('!=', 'REG_paid', true);
1633
-        }
1634
-        //EEH_Debug_Tools::printr( $registration_query_where_params, '$registration_query_where_params', __FILE__, __LINE__ );
1635
-        $registrations = $transaction->registrations(array($registration_query_where_params));
1636
-        if ( ! empty($registrations)) {
1637
-            /** @type EE_Payment_Processor $payment_processor */
1638
-            $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
1639
-            $payment_processor->process_registration_payments($transaction, $payment, $registrations);
1640
-        }
1641
-    }
1642
-
1643
-
1644
-    /**
1645
-     * _process_registration_status_change
1646
-     *
1647
-     * This processes requested registration status changes for all the registrations
1648
-     * on a given transaction and (optionally) sends out notifications for the changes.
1649
-     *
1650
-     * @param  EE_Transaction $transaction
1651
-     * @param array           $REG_IDs
1652
-     *
1653
-     * @return bool
1654
-     */
1655
-    protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = array())
1656
-    {
1657
-        // first if there is no change in status then we get out.
1658
-        if (
1659
-            ! isset($this->_req_data['txn_reg_status_change'], $this->_req_data['txn_reg_status_change']['reg_status'])
1660
-            || $this->_req_data['txn_reg_status_change']['reg_status'] == 'NAN'
1661
-        ) {
1662
-            //no error message, no change requested, just nothing to do man.
1663
-            return false;
1664
-        }
1665
-        /** @type EE_Transaction_Processor $transaction_processor */
1666
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1667
-
1668
-        // made it here dude?  Oh WOW.  K, let's take care of changing the statuses
1669
-        return $transaction_processor->manually_update_registration_statuses(
1670
-            $transaction,
1671
-            sanitize_text_field($this->_req_data['txn_reg_status_change']['reg_status']),
1672
-            array(array('REG_ID' => array('IN', $REG_IDs)))
1673
-        );
1674
-    }
1675
-
1676
-
1677
-    /**
1678
-     * _build_payment_json_response
1679
-     *
1680
-     * @access public
1681
-     *
1682
-     * @param \EE_Payment $payment
1683
-     * @param array       $REG_IDs
1684
-     * @param bool | null $delete_txn_reg_status_change
1685
-     *
1686
-     * @return array
1687
-     */
1688
-    protected function _build_payment_json_response(
1689
-        EE_Payment $payment,
1690
-        $REG_IDs = array(),
1691
-        $delete_txn_reg_status_change = null
1692
-    ) {
1693
-        // was the payment deleted ?
1694
-        if (is_bool($delete_txn_reg_status_change)) {
1695
-            return array(
1696
-                'PAY_ID'                       => $payment->ID(),
1697
-                'amount'                       => $payment->amount(),
1698
-                'total_paid'                   => $payment->transaction()->paid(),
1699
-                'txn_status'                   => $payment->transaction()->status_ID(),
1700
-                'pay_status'                   => $payment->STS_ID(),
1701
-                'registrations'                => $this->_registration_payment_data_array($REG_IDs),
1702
-                'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
1703
-            );
1704
-        } else {
1705
-            $this->_get_payment_status_array();
1706
-
1707
-            return array(
1708
-                'amount'           => $payment->amount(),
1709
-                'total_paid'       => $payment->transaction()->paid(),
1710
-                'txn_status'       => $payment->transaction()->status_ID(),
1711
-                'pay_status'       => $payment->STS_ID(),
1712
-                'PAY_ID'           => $payment->ID(),
1713
-                'STS_ID'           => $payment->STS_ID(),
1714
-                'status'           => self::$_pay_status[$payment->STS_ID()],
1715
-                'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
1716
-                'method'           => strtoupper($payment->source()),
1717
-                'PM_ID'            => $payment->payment_method() ? $payment->payment_method()->ID() : 1,
1718
-                'gateway'          => $payment->payment_method() ? $payment->payment_method()->admin_name() : esc_html__("Unknown",
1719
-                    'event_espresso'),
1720
-                'gateway_response' => $payment->gateway_response(),
1721
-                'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
1722
-                'po_number'        => $payment->po_number(),
1723
-                'extra_accntng'    => $payment->extra_accntng(),
1724
-                'registrations'    => $this->_registration_payment_data_array($REG_IDs),
1725
-            );
1726
-        }
1727
-    }
1728
-
1729
-
1730
-    /**
1731
-     * delete_payment
1732
-     *    delete a payment or refund made towards a transaction
1733
-     *
1734
-     * @access public
1735
-     * @return void
1736
-     */
1737
-    public function delete_payment()
1738
-    {
1739
-        $json_response_data = array('return_data' => false);
1740
-        $PAY_ID             = isset($this->_req_data['delete_txn_admin_payment'], $this->_req_data['delete_txn_admin_payment']['PAY_ID']) ? absint($this->_req_data['delete_txn_admin_payment']['PAY_ID']) : 0;
1741
-        if ($PAY_ID) {
1742
-            $delete_txn_reg_status_change = isset($this->_req_data['delete_txn_reg_status_change']) ? $this->_req_data['delete_txn_reg_status_change'] : false;
1743
-            $payment                      = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
1744
-            if ($payment instanceof EE_Payment) {
1745
-                $REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
1746
-                /** @type EE_Transaction_Payments $transaction_payments */
1747
-                $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1748
-                if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
1749
-                    $json_response_data['return_data'] = $this->_build_payment_json_response($payment, $REG_IDs,
1750
-                        $delete_txn_reg_status_change);
1751
-                    if ($delete_txn_reg_status_change) {
1752
-                        $this->_req_data['txn_reg_status_change'] = $delete_txn_reg_status_change;
1753
-                        //MAKE sure we also add the delete_txn_req_status_change to the
1754
-                        //$_REQUEST global because that's how messages will be looking for it.
1755
-                        $_REQUEST['txn_reg_status_change'] = $delete_txn_reg_status_change;
1756
-                        $this->_maybe_send_notifications();
1757
-                        $this->_process_registration_status_change($payment->transaction(), $REG_IDs);
1758
-                    }
1759
-                }
1760
-            } else {
1761
-                EE_Error::add_error(
1762
-                    esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
1763
-                    __FILE__, __FUNCTION__, __LINE__
1764
-                );
1765
-            }
1766
-        } else {
1767
-            EE_Error::add_error(
1768
-                esc_html__('A valid Payment ID was not received, therefore payment form data could not be loaded.',
1769
-                    'event_espresso'),
1770
-                __FILE__, __FUNCTION__, __LINE__
1771
-            );
1772
-        }
1773
-        $notices              = EE_Error::get_notices(false, false, false);
1774
-        $this->_template_args = array(
1775
-            'data'      => $json_response_data,
1776
-            'success'   => $notices['success'],
1777
-            'error'     => $notices['errors'],
1778
-            'attention' => $notices['attention']
1779
-        );
1780
-        $this->_return_json();
1781
-    }
1782
-
1783
-
1784
-    /**
1785
-     * _registration_payment_data_array
1786
-     * adds info for 'owing' and 'paid' for each registration to the json response
1787
-     *
1788
-     * @access protected
1789
-     *
1790
-     * @param array $REG_IDs
1791
-     *
1792
-     * @return array
1793
-     */
1794
-    protected function _registration_payment_data_array($REG_IDs)
1795
-    {
1796
-        $registration_payment_data = array();
1797
-        //if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
1798
-        if ( ! empty($REG_IDs)) {
1799
-            $registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
1800
-            foreach ($registrations as $registration) {
1801
-                if ($registration instanceof EE_Registration) {
1802
-                    $registration_payment_data[$registration->ID()] = array(
1803
-                        'paid'  => $registration->pretty_paid(),
1804
-                        'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
1805
-                    );
1806
-                }
1807
-            }
1808
-        }
1809
-
1810
-        return $registration_payment_data;
1811
-    }
1812
-
1813
-
1814
-    /**
1815
-     * _maybe_send_notifications
1816
-     *
1817
-     * determines whether or not the admin has indicated that notifications should be sent.
1818
-     * If so, will toggle a filter switch for delivering registration notices.
1819
-     * If passed an EE_Payment object, then it will trigger payment notifications instead.
1820
-     *
1821
-     * @access protected
1822
-     *
1823
-     * @param \EE_Payment | null $payment
1824
-     */
1825
-    protected function _maybe_send_notifications($payment = null)
1826
-    {
1827
-        switch ($payment instanceof EE_Payment) {
1828
-            // payment notifications
1829
-            case true :
1830
-                if (
1831
-                    isset(
1832
-                        $this->_req_data['txn_payments'],
1833
-                        $this->_req_data['txn_payments']['send_notifications']
1834
-                    ) &&
1835
-                    filter_var($this->_req_data['txn_payments']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
1836
-                ) {
1837
-                    $this->_process_payment_notification($payment);
1838
-                }
1839
-                break;
1840
-            // registration notifications
1841
-            case false :
1842
-                if (
1843
-                    isset(
1844
-                        $this->_req_data['txn_reg_status_change'],
1845
-                        $this->_req_data['txn_reg_status_change']['send_notifications']
1846
-                    ) &&
1847
-                    filter_var($this->_req_data['txn_reg_status_change']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
1848
-                ) {
1849
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
1850
-                }
1851
-                break;
1852
-        }
1853
-    }
1854
-
1855
-
1856
-    /**
1857
-     * _send_payment_reminder
1858
-     *    generates HTML for the View Transaction Details Admin page
1859
-     *
1860
-     * @access protected
1861
-     * @return void
1862
-     */
1863
-    protected function _send_payment_reminder()
1864
-    {
1865
-        $TXN_ID      = ( ! empty($this->_req_data['TXN_ID'])) ? absint($this->_req_data['TXN_ID']) : false;
1866
-        $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
1867
-        $query_args  = isset($this->_req_data['redirect_to']) ? array(
1868
-            'action' => $this->_req_data['redirect_to'],
1869
-            'TXN_ID' => $this->_req_data['TXN_ID']
1870
-        ) : array();
1871
-        do_action('AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
1872
-            $transaction);
1873
-        $this->_redirect_after_action(false, esc_html__('payment reminder', 'event_espresso'),
1874
-            esc_html__('sent', 'event_espresso'), $query_args, true);
1875
-    }
1876
-
1877
-
1878
-    /**
1879
-     *  get_transactions
1880
-     *    get transactions for given parameters (used by list table)
1881
-     *
1882
-     * @param  int     $perpage how many transactions displayed per page
1883
-     * @param  boolean $count   return the count or objects
1884
-     * @param string   $view
1885
-     *
1886
-     * @return mixed int = count || array of transaction objects
1887
-     */
1888
-    public function get_transactions($perpage, $count = false, $view = '')
1889
-    {
1890
-
1891
-        $TXN = EEM_Transaction::instance();
1892
-
1893
-        $start_date = isset($this->_req_data['txn-filter-start-date']) ? wp_strip_all_tags($this->_req_data['txn-filter-start-date']) : date('m/d/Y',
1894
-            strtotime('-10 year'));
1895
-        $end_date   = isset($this->_req_data['txn-filter-end-date']) ? wp_strip_all_tags($this->_req_data['txn-filter-end-date']) : date('m/d/Y');
1896
-
1897
-        //make sure our timestamps start and end right at the boundaries for each day
1898
-        $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
1899
-        $end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
1900
-
1901
-
1902
-        //convert to timestamps
1903
-        $start_date = strtotime($start_date);
1904
-        $end_date   = strtotime($end_date);
1905
-
1906
-        //makes sure start date is the lowest value and vice versa
1907
-        $start_date = min($start_date, $end_date);
1908
-        $end_date   = max($start_date, $end_date);
1909
-
1910
-        //convert to correct format for query
1911
-        $start_date = EEM_Transaction::instance()->convert_datetime_for_query('TXN_timestamp',
1912
-            date('Y-m-d H:i:s', $start_date), 'Y-m-d H:i:s');
1913
-        $end_date   = EEM_Transaction::instance()->convert_datetime_for_query('TXN_timestamp',
1914
-            date('Y-m-d H:i:s', $end_date), 'Y-m-d H:i:s');
1915
-
1916
-
1917
-        //set orderby
1918
-        $this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
1919
-
1920
-        switch ($this->_req_data['orderby']) {
1921
-            case 'TXN_ID':
1922
-                $orderby = 'TXN_ID';
1923
-                break;
1924
-            case 'ATT_fname':
1925
-                $orderby = 'Registration.Attendee.ATT_fname';
1926
-                break;
1927
-            case 'event_name':
1928
-                $orderby = 'Registration.Event.EVT_name';
1929
-                break;
1930
-            default: //'TXN_timestamp'
1931
-                $orderby = 'TXN_timestamp';
1932
-        }
1933
-
1934
-        $sort         = (isset($this->_req_data['order']) && ! empty($this->_req_data['order'])) ? $this->_req_data['order'] : 'DESC';
1935
-        $current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged']) ? $this->_req_data['paged'] : 1;
1936
-        $per_page     = isset($perpage) && ! empty($perpage) ? $perpage : 10;
1937
-        $per_page     = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage']) ? $this->_req_data['perpage'] : $per_page;
1938
-
1939
-        $offset = ($current_page - 1) * $per_page;
1940
-        $limit  = array($offset, $per_page);
1941
-
1942
-        $_where = array(
1943
-            'TXN_timestamp'          => array('BETWEEN', array($start_date, $end_date)),
1944
-            'Registration.REG_count' => 1
1945
-        );
1946
-
1947
-        if (isset($this->_req_data['EVT_ID'])) {
1948
-            $_where['Registration.EVT_ID'] = $this->_req_data['EVT_ID'];
1949
-        }
1950
-
1951
-        if (isset($this->_req_data['s'])) {
1952
-            $search_string = '%' . $this->_req_data['s'] . '%';
1953
-            $_where['OR']  = array(
1954
-                'Registration.Event.EVT_name'         => array('LIKE', $search_string),
1955
-                'Registration.Event.EVT_desc'         => array('LIKE', $search_string),
1956
-                'Registration.Event.EVT_short_desc'   => array('LIKE', $search_string),
1957
-                'Registration.Attendee.ATT_full_name' => array('LIKE', $search_string),
1958
-                'Registration.Attendee.ATT_fname'     => array('LIKE', $search_string),
1959
-                'Registration.Attendee.ATT_lname'     => array('LIKE', $search_string),
1960
-                'Registration.Attendee.ATT_short_bio' => array('LIKE', $search_string),
1961
-                'Registration.Attendee.ATT_email'     => array('LIKE', $search_string),
1962
-                'Registration.Attendee.ATT_address'   => array('LIKE', $search_string),
1963
-                'Registration.Attendee.ATT_address2'  => array('LIKE', $search_string),
1964
-                'Registration.Attendee.ATT_city'      => array('LIKE', $search_string),
1965
-                'Registration.REG_final_price'        => array('LIKE', $search_string),
1966
-                'Registration.REG_code'               => array('LIKE', $search_string),
1967
-                'Registration.REG_count'              => array('LIKE', $search_string),
1968
-                'Registration.REG_group_size'         => array('LIKE', $search_string),
1969
-                'Registration.Ticket.TKT_name'        => array('LIKE', $search_string),
1970
-                'Registration.Ticket.TKT_description' => array('LIKE', $search_string),
1971
-                'Payment.PAY_source'                  => array('LIKE', $search_string),
1972
-                'Payment.Payment_Method.PMD_name'     => array('LIKE', $search_string),
1973
-                'TXN_session_data'                    => array('LIKE', $search_string),
1974
-                'Payment.PAY_txn_id_chq_nmbr'         => array('LIKE', $search_string)
1975
-            );
1976
-        }
1977
-
1978
-        //failed transactions
1979
-        $failed    = ( ! empty($this->_req_data['status']) && $this->_req_data['status'] == 'failed' && ! $count) || ($count && $view == 'failed') ? true : false;
1980
-        $abandoned = ( ! empty($this->_req_data['status']) && $this->_req_data['status'] == 'abandoned' && ! $count) || ($count && $view == 'abandoned') ? true : false;
1981
-
1982
-        if ($failed) {
1983
-            $_where['STS_ID'] = EEM_Transaction::failed_status_code;
1984
-        } else if ($abandoned) {
1985
-            $_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
1986
-        } else {
1987
-            $_where['STS_ID']  = array('!=', EEM_Transaction::failed_status_code);
1988
-            $_where['STS_ID*'] = array('!=', EEM_Transaction::abandoned_status_code);
1989
-        }
1990
-
1991
-        $query_params = array($_where, 'order_by' => array($orderby => $sort), 'limit' => $limit);
1992
-
1993
-        $transactions = $count ? $TXN->count(array($_where), 'TXN_ID', true) : $TXN->get_all($query_params);
1994
-
1995
-
1996
-        return $transactions;
1997
-
1998
-    }
807
+		// process payment details
808
+		$payments = $this->_transaction->get_many_related('Payment');
809
+		if ( ! empty($payments)) {
810
+			$this->_template_args['payments']              = $payments;
811
+			$this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
812
+		} else {
813
+			$this->_template_args['payments']              = false;
814
+			$this->_template_args['existing_reg_payments'] = array();
815
+		}
816
+
817
+		$this->_template_args['edit_payment_url']   = add_query_arg(array('action' => 'edit_payment'), TXN_ADMIN_URL);
818
+		$this->_template_args['delete_payment_url'] = add_query_arg(array('action' => 'espresso_delete_payment'),
819
+			TXN_ADMIN_URL);
820
+
821
+		if (isset($txn_details['invoice_number'])) {
822
+			$this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
823
+			$this->_template_args['txn_details']['invoice_number']['label'] = esc_html__('Invoice Number',
824
+				'event_espresso');
825
+		}
826
+
827
+		$this->_template_args['txn_details']['registration_session']['value'] = $this->_transaction->get_first_related('Registration')->get('REG_session');
828
+		$this->_template_args['txn_details']['registration_session']['label'] = esc_html__('Registration Session',
829
+			'event_espresso');
830
+
831
+		$this->_template_args['txn_details']['ip_address']['value'] = isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '';
832
+		$this->_template_args['txn_details']['ip_address']['label'] = esc_html__('Transaction placed from IP',
833
+			'event_espresso');
834
+
835
+		$this->_template_args['txn_details']['user_agent']['value'] = isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '';
836
+		$this->_template_args['txn_details']['user_agent']['label'] = esc_html__('Registrant User Agent',
837
+			'event_espresso');
838
+
839
+		$reg_steps = '<ul>';
840
+		foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
841
+			if ($reg_step_status === true) {
842
+				$reg_steps .= '<li style="color:#70cc50">' . sprintf(esc_html__('%1$s : Completed', 'event_espresso'),
843
+						ucwords(str_replace('_', ' ', $reg_step))) . '</li>';
844
+			} else if (is_numeric($reg_step_status) && $reg_step_status !== false) {
845
+				$reg_steps .= '<li style="color:#2EA2CC">' . sprintf(
846
+						esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
847
+						ucwords(str_replace('_', ' ', $reg_step)),
848
+						date(get_option('date_format') . ' ' . get_option('time_format'),
849
+							($reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS)))
850
+					) . '</li>';
851
+			} else {
852
+				$reg_steps .= '<li style="color:#E76700">' . sprintf(esc_html__('%1$s : Never Initiated',
853
+						'event_espresso'), ucwords(str_replace('_', ' ', $reg_step))) . '</li>';
854
+			}
855
+		}
856
+		$reg_steps .= '</ul>';
857
+		$this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
858
+		$this->_template_args['txn_details']['reg_steps']['label'] = esc_html__('Registration Step Progress',
859
+			'event_espresso');
860
+
861
+
862
+		$this->_get_registrations_to_apply_payment_to();
863
+		$this->_get_payment_methods($payments);
864
+		$this->_get_payment_status_array();
865
+		$this->_get_reg_status_selection(); //sets up the template args for the reg status array for the transaction.
866
+
867
+		$this->_template_args['transaction_form_url']    = add_query_arg(array(
868
+			'action'  => 'edit_transaction',
869
+			'process' => 'transaction'
870
+		), TXN_ADMIN_URL);
871
+		$this->_template_args['apply_payment_form_url']  = add_query_arg(array(
872
+			'page'   => 'espresso_transactions',
873
+			'action' => 'espresso_apply_payment'
874
+		), WP_AJAX_URL);
875
+		$this->_template_args['delete_payment_form_url'] = add_query_arg(array(
876
+			'page'   => 'espresso_transactions',
877
+			'action' => 'espresso_delete_payment'
878
+		), WP_AJAX_URL);
879
+
880
+		// 'espresso_delete_payment_nonce'
881
+
882
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
883
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
884
+
885
+	}
886
+
887
+
888
+	/**
889
+	 * _get_registration_payment_IDs
890
+	 *
891
+	 *    generates an array of Payment IDs and their corresponding Registration IDs
892
+	 *
893
+	 * @access protected
894
+	 *
895
+	 * @param EE_Payment[] $payments
896
+	 *
897
+	 * @return array
898
+	 */
899
+	protected function _get_registration_payment_IDs($payments = array())
900
+	{
901
+		$existing_reg_payments = array();
902
+		// get all reg payments for these payments
903
+		$reg_payments = EEM_Registration_Payment::instance()->get_all(array(
904
+			array(
905
+				'PAY_ID' => array(
906
+					'IN',
907
+					array_keys($payments)
908
+				)
909
+			)
910
+		));
911
+		if ( ! empty($reg_payments)) {
912
+			foreach ($payments as $payment) {
913
+				if ( ! $payment instanceof EE_Payment) {
914
+					continue;
915
+				} else if ( ! isset($existing_reg_payments[$payment->ID()])) {
916
+					$existing_reg_payments[$payment->ID()] = array();
917
+				}
918
+				foreach ($reg_payments as $reg_payment) {
919
+					if ($reg_payment instanceof EE_Registration_Payment && $reg_payment->payment_ID() === $payment->ID()) {
920
+						$existing_reg_payments[$payment->ID()][] = $reg_payment->registration_ID();
921
+					}
922
+				}
923
+			}
924
+		}
925
+
926
+		return $existing_reg_payments;
927
+	}
928
+
929
+
930
+	/**
931
+	 * _get_registrations_to_apply_payment_to
932
+	 *    generates HTML for displaying a series of checkboxes in the admin payment modal window
933
+	 * which allows the admin to only apply the payment to the specific registrations
934
+	 *
935
+	 * @access protected
936
+	 * @return void
937
+	 * @throws \EE_Error
938
+	 */
939
+	protected function _get_registrations_to_apply_payment_to()
940
+	{
941
+		// we want any registration with an active status (ie: not deleted or cancelled)
942
+		$query_params                      = array(
943
+			array(
944
+				'STS_ID' => array(
945
+					'IN',
946
+					array(
947
+						EEM_Registration::status_id_approved,
948
+						EEM_Registration::status_id_pending_payment,
949
+						EEM_Registration::status_id_not_approved,
950
+					)
951
+				)
952
+			)
953
+		);
954
+		$registrations_to_apply_payment_to = EEH_HTML::br() . EEH_HTML::div(
955
+				'', 'txn-admin-apply-payment-to-registrations-dv', '', 'clear: both; margin: 1.5em 0 0; display: none;'
956
+			);
957
+		$registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
958
+		$registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl');
959
+		$registrations_to_apply_payment_to .= EEH_HTML::thead(
960
+			EEH_HTML::tr(
961
+				EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
962
+				EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
963
+				EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
964
+				EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
965
+				EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
966
+				EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
967
+				EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
968
+			)
969
+		);
970
+		$registrations_to_apply_payment_to .= EEH_HTML::tbody();
971
+		// get registrations for TXN
972
+		$registrations = $this->_transaction->registrations($query_params);
973
+		foreach ($registrations as $registration) {
974
+			if ($registration instanceof EE_Registration) {
975
+				$attendee_name = $registration->attendee() instanceof EE_Attendee
976
+					? $registration->attendee()->full_name()
977
+					: esc_html__('Unknown Attendee', 'event_espresso');
978
+				$owing         = $registration->final_price() - $registration->paid();
979
+				$taxable       = $registration->ticket()->taxable()
980
+					? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
981
+					: '';
982
+				$checked       = empty($existing_reg_payments) || in_array($registration->ID(), $existing_reg_payments)
983
+					? ' checked="checked"'
984
+					: '';
985
+				$disabled      = $registration->final_price() > 0 ? '' : ' disabled';
986
+				$registrations_to_apply_payment_to .= EEH_HTML::tr(
987
+					EEH_HTML::td($registration->ID()) .
988
+					EEH_HTML::td($attendee_name) .
989
+					EEH_HTML::td(
990
+						$registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
991
+					) .
992
+					EEH_HTML::td($registration->event_name()) .
993
+					EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
994
+					EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr') .
995
+					EEH_HTML::td(
996
+						'<input type="checkbox" value="' . $registration->ID()
997
+						. '" name="txn_admin_payment[registrations]"'
998
+						. $checked . $disabled . '>',
999
+						'', 'jst-cntr'
1000
+					),
1001
+					'apply-payment-registration-row-' . $registration->ID()
1002
+				);
1003
+			}
1004
+		}
1005
+		$registrations_to_apply_payment_to .= EEH_HTML::tbodyx();
1006
+		$registrations_to_apply_payment_to .= EEH_HTML::tablex();
1007
+		$registrations_to_apply_payment_to .= EEH_HTML::divx();
1008
+		$registrations_to_apply_payment_to .= EEH_HTML::p(
1009
+			esc_html__(
1010
+				'The payment will only be applied to the registrations that have a check mark in their corresponding check box. Checkboxes for free registrations have been disabled.',
1011
+				'event_espresso'
1012
+			),
1013
+			'', 'clear description'
1014
+		);
1015
+		$registrations_to_apply_payment_to .= EEH_HTML::divx();
1016
+		$this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1017
+	}
1018
+
1019
+
1020
+	/**
1021
+	 * _get_reg_status_selection
1022
+	 *
1023
+	 * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1024
+	 *         instead of events.
1025
+	 * @access protected
1026
+	 * @return void
1027
+	 */
1028
+	protected function _get_reg_status_selection()
1029
+	{
1030
+		//first get all possible statuses
1031
+		$statuses = EEM_Registration::reg_status_array(array(), true);
1032
+		//let's add a "don't change" option.
1033
+		$status_array['NAN']                                 = esc_html__('Leave the Same', 'event_espresso');
1034
+		$status_array                                        = array_merge($status_array, $statuses);
1035
+		$this->_template_args['status_change_select']        = EEH_Form_Fields::select_input('txn_reg_status_change[reg_status]',
1036
+			$status_array, 'NAN', 'id="txn-admin-payment-reg-status-inp"', 'txn-reg-status-change-reg-status');
1037
+		$this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input('delete_txn_reg_status_change[reg_status]',
1038
+			$status_array, 'NAN', 'delete-txn-admin-payment-reg-status-inp', 'delete-txn-reg-status-change-reg-status');
1039
+
1040
+	}
1041
+
1042
+
1043
+	/**
1044
+	 *    _get_payment_methods
1045
+	 * Gets all the payment methods available generally, or the ones that are already
1046
+	 * selected on these payments (in case their payment methods are no longer active).
1047
+	 * Has the side-effect of updating the template args' payment_methods item
1048
+	 * @access private
1049
+	 *
1050
+	 * @param EE_Payment[] to show on this page
1051
+	 *
1052
+	 * @return void
1053
+	 */
1054
+	private function _get_payment_methods($payments = array())
1055
+	{
1056
+		$payment_methods_of_payments = array();
1057
+		foreach ($payments as $payment) {
1058
+			if ($payment instanceof EE_Payment) {
1059
+				$payment_methods_of_payments[] = $payment->get('PMD_ID');
1060
+			}
1061
+		}
1062
+		if ($payment_methods_of_payments) {
1063
+			$query_args = array(
1064
+				array(
1065
+					'OR*payment_method_for_payment' => array(
1066
+						'PMD_ID'    => array('IN', $payment_methods_of_payments),
1067
+						'PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')
1068
+					)
1069
+				)
1070
+			);
1071
+		} else {
1072
+			$query_args = array(array('PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')));
1073
+		}
1074
+		$this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1075
+	}
1076
+
1077
+
1078
+	/**
1079
+	 * txn_attendees_meta_box
1080
+	 *    generates HTML for the Attendees Transaction main meta box
1081
+	 *
1082
+	 * @access public
1083
+	 *
1084
+	 * @param WP_Post $post
1085
+	 * @param array   $metabox
1086
+	 *
1087
+	 * @return void
1088
+	 */
1089
+	public function txn_attendees_meta_box($post, $metabox = array('args' => array()))
1090
+	{
1091
+
1092
+		extract($metabox['args']);
1093
+		$this->_template_args['post']            = $post;
1094
+		$this->_template_args['event_attendees'] = array();
1095
+		// process items in cart
1096
+		$line_items = $this->_transaction->get_many_related('Line_Item', array(array('LIN_type' => 'line-item')));
1097
+		if ( ! empty($line_items)) {
1098
+			foreach ($line_items as $item) {
1099
+				if ($item instanceof EE_Line_Item) {
1100
+					switch ($item->OBJ_type()) {
1101
+
1102
+						case 'Event' :
1103
+							break;
1104
+
1105
+						case 'Ticket' :
1106
+							$ticket = $item->ticket();
1107
+							//right now we're only handling tickets here.  Cause its expected that only tickets will have attendees right?
1108
+							if ( ! $ticket instanceof EE_Ticket) {
1109
+								continue;
1110
+							}
1111
+							try {
1112
+								$event_name = $ticket->get_event_name();
1113
+							} catch (Exception $e) {
1114
+								EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1115
+								$event_name = esc_html__('Unknown Event', 'event_espresso');
1116
+							}
1117
+							$event_name .= ' - ' . $item->get('LIN_name');
1118
+							$ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
1119
+							// now get all of the registrations for this transaction that use this ticket
1120
+							$registrations = $ticket->get_many_related('Registration',
1121
+								array(array('TXN_ID' => $this->_transaction->ID())));
1122
+							foreach ($registrations as $registration) {
1123
+								if ( ! $registration instanceof EE_Registration) {
1124
+									continue;
1125
+								}
1126
+								$this->_template_args['event_attendees'][$registration->ID()]['STS_ID']            = $registration->status_ID();
1127
+								$this->_template_args['event_attendees'][$registration->ID()]['att_num']           = $registration->count();
1128
+								$this->_template_args['event_attendees'][$registration->ID()]['event_ticket_name'] = $event_name;
1129
+								$this->_template_args['event_attendees'][$registration->ID()]['ticket_price']      = $ticket_price;
1130
+								// attendee info
1131
+								$attendee = $registration->get_first_related('Attendee');
1132
+								if ($attendee instanceof EE_Attendee) {
1133
+									$this->_template_args['event_attendees'][$registration->ID()]['att_id']   = $attendee->ID();
1134
+									$this->_template_args['event_attendees'][$registration->ID()]['attendee'] = $attendee->full_name();
1135
+									$this->_template_args['event_attendees'][$registration->ID()]['email']    = '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name . esc_html__(' Event',
1136
+											'event_espresso') . '">' . $attendee->email() . '</a>';
1137
+									$this->_template_args['event_attendees'][$registration->ID()]['address']  = EEH_Address::format($attendee,
1138
+										'inline', false, false);
1139
+								} else {
1140
+									$this->_template_args['event_attendees'][$registration->ID()]['att_id']   = '';
1141
+									$this->_template_args['event_attendees'][$registration->ID()]['attendee'] = '';
1142
+									$this->_template_args['event_attendees'][$registration->ID()]['email']    = '';
1143
+									$this->_template_args['event_attendees'][$registration->ID()]['address']  = '';
1144
+								}
1145
+							}
1146
+							break;
1147
+
1148
+					}
1149
+				}
1150
+			}
1151
+
1152
+			$this->_template_args['transaction_form_url'] = add_query_arg(array(
1153
+				'action'  => 'edit_transaction',
1154
+				'process' => 'attendees'
1155
+			), TXN_ADMIN_URL);
1156
+			echo EEH_Template::display_template(TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1157
+				$this->_template_args, true);
1158
+
1159
+		} else {
1160
+			echo sprintf(
1161
+				esc_html__('%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1162
+					'event_espresso'),
1163
+				'<p class="important-notice">',
1164
+				'</p>'
1165
+			);
1166
+		}
1167
+	}
1168
+
1169
+
1170
+	/**
1171
+	 * txn_registrant_side_meta_box
1172
+	 * generates HTML for the Edit Transaction side meta box
1173
+	 *
1174
+	 * @access public
1175
+	 * @throws \EE_Error
1176
+	 * @return void
1177
+	 */
1178
+	public function txn_registrant_side_meta_box()
1179
+	{
1180
+		$primary_att = $this->_transaction->primary_registration() instanceof EE_Registration ? $this->_transaction->primary_registration()->get_first_related('Attendee') : null;
1181
+		if ( ! $primary_att instanceof EE_Attendee) {
1182
+			$this->_template_args['no_attendee_message'] = esc_html__('There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1183
+				'event_espresso');
1184
+			$primary_att                                 = EEM_Attendee::instance()->create_default_object();
1185
+		}
1186
+		$this->_template_args['ATT_ID']            = $primary_att->ID();
1187
+		$this->_template_args['prime_reg_fname']   = $primary_att->fname();
1188
+		$this->_template_args['prime_reg_lname']   = $primary_att->lname();
1189
+		$this->_template_args['prime_reg_email']   = $primary_att->email();
1190
+		$this->_template_args['prime_reg_phone']   = $primary_att->phone();
1191
+		$this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(array(
1192
+			'action' => 'edit_attendee',
1193
+			'post'   => $primary_att->ID()
1194
+		), REG_ADMIN_URL);
1195
+		// get formatted address for registrant
1196
+		$this->_template_args['formatted_address'] = EEH_Address::format($primary_att);
1197
+		echo EEH_Template::display_template(TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1198
+			$this->_template_args, true);
1199
+	}
1200
+
1201
+
1202
+	/**
1203
+	 * txn_billing_info_side_meta_box
1204
+	 *    generates HTML for the Edit Transaction side meta box
1205
+	 *
1206
+	 * @access public
1207
+	 * @return void
1208
+	 */
1209
+	public function txn_billing_info_side_meta_box()
1210
+	{
1211
+
1212
+		$this->_template_args['billing_form']     = $this->_transaction->billing_info();
1213
+		$this->_template_args['billing_form_url'] = add_query_arg(
1214
+			array('action' => 'edit_transaction', 'process' => 'billing'),
1215
+			TXN_ADMIN_URL
1216
+		);
1217
+
1218
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1219
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);/**/
1220
+	}
1221
+
1222
+
1223
+	/**
1224
+	 * apply_payments_or_refunds
1225
+	 *    registers a payment or refund made towards a transaction
1226
+	 *
1227
+	 * @access public
1228
+	 * @return void
1229
+	 */
1230
+	public function apply_payments_or_refunds()
1231
+	{
1232
+		$json_response_data = array('return_data' => false);
1233
+		$valid_data         = $this->_validate_payment_request_data();
1234
+		if ( ! empty($valid_data)) {
1235
+			$PAY_ID = $valid_data['PAY_ID'];
1236
+			//save  the new payment
1237
+			$payment = $this->_create_payment_from_request_data($valid_data);
1238
+			// get the TXN for this payment
1239
+			$transaction = $payment->transaction();
1240
+			// verify transaction
1241
+			if ($transaction instanceof EE_Transaction) {
1242
+				// calculate_total_payments_and_update_status
1243
+				$this->_process_transaction_payments($transaction);
1244
+				$REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1245
+				$this->_remove_existing_registration_payments($payment, $PAY_ID);
1246
+				// apply payment to registrations (if applicable)
1247
+				if ( ! empty($REG_IDs)) {
1248
+					$this->_update_registration_payments($transaction, $payment, $REG_IDs);
1249
+					$this->_maybe_send_notifications();
1250
+					// now process status changes for the same registrations
1251
+					$this->_process_registration_status_change($transaction, $REG_IDs);
1252
+				}
1253
+				$this->_maybe_send_notifications($payment);
1254
+				//prepare to render page
1255
+				$json_response_data['return_data'] = $this->_build_payment_json_response($payment, $REG_IDs);
1256
+				do_action('AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording', $transaction,
1257
+					$payment);
1258
+			} else {
1259
+				EE_Error::add_error(
1260
+					esc_html__('A valid Transaction for this payment could not be retrieved.', 'event_espresso'),
1261
+					__FILE__, __FUNCTION__, __LINE__
1262
+				);
1263
+			}
1264
+		} else {
1265
+			EE_Error::add_error(esc_html__('The payment form data could not be processed. Please try again.',
1266
+				'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
1267
+		}
1268
+
1269
+		$notices              = EE_Error::get_notices(false, false, false);
1270
+		$this->_template_args = array(
1271
+			'data'    => $json_response_data,
1272
+			'error'   => $notices['errors'],
1273
+			'success' => $notices['success']
1274
+		);
1275
+		$this->_return_json();
1276
+	}
1277
+
1278
+
1279
+	/**
1280
+	 * _validate_payment_request_data
1281
+	 *
1282
+	 * @return array
1283
+	 */
1284
+	protected function _validate_payment_request_data()
1285
+	{
1286
+		if ( ! isset($this->_req_data['txn_admin_payment'])) {
1287
+			return false;
1288
+		}
1289
+		$payment_form = $this->_generate_payment_form_section();
1290
+		try {
1291
+			if ($payment_form->was_submitted()) {
1292
+				$payment_form->receive_form_submission();
1293
+				if ( ! $payment_form->is_valid()) {
1294
+					$submission_error_messages = array();
1295
+					foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1296
+						if ($validation_error instanceof EE_Validation_Error) {
1297
+							$submission_error_messages[] = sprintf(
1298
+								_x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1299
+								$validation_error->get_form_section()->html_label_text(),
1300
+								$validation_error->getMessage()
1301
+							);
1302
+						}
1303
+					}
1304
+					EE_Error::add_error(join('<br />', $submission_error_messages), __FILE__, __FUNCTION__, __LINE__);
1305
+
1306
+					return array();
1307
+				}
1308
+			}
1309
+		} catch (EE_Error $e) {
1310
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1311
+
1312
+			return array();
1313
+		}
1314
+
1315
+		return $payment_form->valid_data();
1316
+	}
1317
+
1318
+
1319
+	/**
1320
+	 * _generate_payment_form_section
1321
+	 *
1322
+	 * @return EE_Form_Section_Proper
1323
+	 */
1324
+	protected function _generate_payment_form_section()
1325
+	{
1326
+		return new EE_Form_Section_Proper(
1327
+			array(
1328
+				'name'        => 'txn_admin_payment',
1329
+				'subsections' => array(
1330
+					'PAY_ID'          => new EE_Text_Input(
1331
+						array(
1332
+							'default'               => 0,
1333
+							'required'              => false,
1334
+							'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1335
+							'validation_strategies' => array(new EE_Int_Normalization())
1336
+						)
1337
+					),
1338
+					'TXN_ID'          => new EE_Text_Input(
1339
+						array(
1340
+							'default'               => 0,
1341
+							'required'              => true,
1342
+							'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1343
+							'validation_strategies' => array(new EE_Int_Normalization())
1344
+						)
1345
+					),
1346
+					'type'            => new EE_Text_Input(
1347
+						array(
1348
+							'default'               => 1,
1349
+							'required'              => true,
1350
+							'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1351
+							'validation_strategies' => array(new EE_Int_Normalization())
1352
+						)
1353
+					),
1354
+					'amount'          => new EE_Text_Input(
1355
+						array(
1356
+							'default'               => 0,
1357
+							'required'              => true,
1358
+							'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1359
+							'validation_strategies' => array(new EE_Float_Normalization())
1360
+						)
1361
+					),
1362
+					'status'          => new EE_Text_Input(
1363
+						array(
1364
+							'default'         => EEM_Payment::status_id_approved,
1365
+							'required'        => true,
1366
+							'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1367
+						)
1368
+					),
1369
+					'PMD_ID'          => new EE_Text_Input(
1370
+						array(
1371
+							'default'               => 2,
1372
+							'required'              => true,
1373
+							'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1374
+							'validation_strategies' => array(new EE_Int_Normalization())
1375
+						)
1376
+					),
1377
+					'date'            => new EE_Text_Input(
1378
+						array(
1379
+							'default'         => time(),
1380
+							'required'        => true,
1381
+							'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1382
+						)
1383
+					),
1384
+					'txn_id_chq_nmbr' => new EE_Text_Input(
1385
+						array(
1386
+							'default'               => '',
1387
+							'required'              => false,
1388
+							'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1389
+							'validation_strategies' => array(
1390
+								new EE_Max_Length_Validation_Strategy(esc_html__('Input too long', 'event_espresso'),
1391
+									100),
1392
+							)
1393
+						)
1394
+					),
1395
+					'po_number'       => new EE_Text_Input(
1396
+						array(
1397
+							'default'               => '',
1398
+							'required'              => false,
1399
+							'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1400
+							'validation_strategies' => array(
1401
+								new EE_Max_Length_Validation_Strategy(esc_html__('Input too long', 'event_espresso'),
1402
+									100),
1403
+							)
1404
+						)
1405
+					),
1406
+					'accounting'      => new EE_Text_Input(
1407
+						array(
1408
+							'default'               => '',
1409
+							'required'              => false,
1410
+							'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1411
+							'validation_strategies' => array(
1412
+								new EE_Max_Length_Validation_Strategy(esc_html__('Input too long', 'event_espresso'),
1413
+									100),
1414
+							)
1415
+						)
1416
+					),
1417
+				)
1418
+			)
1419
+		);
1420
+	}
1421
+
1422
+
1423
+	/**
1424
+	 * _create_payment_from_request_data
1425
+	 *
1426
+	 * @param array $valid_data
1427
+	 *
1428
+	 * @return EE_Payment
1429
+	 */
1430
+	protected function _create_payment_from_request_data($valid_data)
1431
+	{
1432
+		$PAY_ID = $valid_data['PAY_ID'];
1433
+		// get payment amount
1434
+		$amount = $valid_data['amount'] ? abs($valid_data['amount']) : 0;
1435
+		// payments have a type value of 1 and refunds have a type value of -1
1436
+		// so multiplying amount by type will give a positive value for payments, and negative values for refunds
1437
+		$amount = $valid_data['type'] < 0 ? $amount * -1 : $amount;
1438
+		// for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1439
+		$date    = $valid_data['date'] ? preg_replace('/\s+/', ' ', $valid_data['date']) : date('Y-m-d g:i a',
1440
+			current_time('timestamp'));
1441
+		$payment = EE_Payment::new_instance(
1442
+			array(
1443
+				'TXN_ID'              => $valid_data['TXN_ID'],
1444
+				'STS_ID'              => $valid_data['status'],
1445
+				'PAY_timestamp'       => $date,
1446
+				'PAY_source'          => EEM_Payment_Method::scope_admin,
1447
+				'PMD_ID'              => $valid_data['PMD_ID'],
1448
+				'PAY_amount'          => $amount,
1449
+				'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1450
+				'PAY_po_number'       => $valid_data['po_number'],
1451
+				'PAY_extra_accntng'   => $valid_data['accounting'],
1452
+				'PAY_details'         => $valid_data,
1453
+				'PAY_ID'              => $PAY_ID
1454
+			),
1455
+			'',
1456
+			array('Y-m-d', 'g:i a')
1457
+		);
1458
+
1459
+		if ( ! $payment->save()) {
1460
+			EE_Error::add_error(
1461
+				sprintf(
1462
+					esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1463
+					$payment->ID()
1464
+				),
1465
+				__FILE__, __FUNCTION__, __LINE__
1466
+			);
1467
+		}
1468
+
1469
+		return $payment;
1470
+	}
1471
+
1472
+
1473
+	/**
1474
+	 * _process_transaction_payments
1475
+	 *
1476
+	 * @param \EE_Transaction $transaction
1477
+	 *
1478
+	 * @return array
1479
+	 */
1480
+	protected function _process_transaction_payments(EE_Transaction $transaction)
1481
+	{
1482
+		/** @type EE_Transaction_Payments $transaction_payments */
1483
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1484
+		//update the transaction with this payment
1485
+		if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1486
+			EE_Error::add_success(esc_html__('The payment has been processed successfully.', 'event_espresso'),
1487
+				__FILE__, __FUNCTION__, __LINE__);
1488
+		} else {
1489
+			EE_Error::add_error(
1490
+				esc_html__('The payment was processed successfully but the amount paid for the transaction was not updated.',
1491
+					'event_espresso')
1492
+				, __FILE__, __FUNCTION__, __LINE__
1493
+			);
1494
+		}
1495
+	}
1496
+
1497
+
1498
+	/**
1499
+	 * _get_REG_IDs_to_apply_payment_to
1500
+	 *
1501
+	 * returns a list of registration IDs that the payment will apply to
1502
+	 *
1503
+	 * @param \EE_Payment $payment
1504
+	 *
1505
+	 * @return array
1506
+	 */
1507
+	protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1508
+	{
1509
+		$REG_IDs = array();
1510
+		// grab array of IDs for specific registrations to apply changes to
1511
+		if (isset($this->_req_data['txn_admin_payment']['registrations'])) {
1512
+			$REG_IDs = (array)$this->_req_data['txn_admin_payment']['registrations'];
1513
+		}
1514
+		//nothing specified ? then get all reg IDs
1515
+		if (empty($REG_IDs)) {
1516
+			$registrations = $payment->transaction()->registrations();
1517
+			$REG_IDs       = ! empty($registrations) ? array_keys($registrations) : $this->_get_existing_reg_payment_REG_IDs($payment);
1518
+		}
1519
+
1520
+		// ensure that REG_IDs are integers and NOT strings
1521
+		return array_map('intval', $REG_IDs);
1522
+	}
1523
+
1524
+
1525
+	/**
1526
+	 * @return array
1527
+	 */
1528
+	public function existing_reg_payment_REG_IDs()
1529
+	{
1530
+		return $this->_existing_reg_payment_REG_IDs;
1531
+	}
1532
+
1533
+
1534
+	/**
1535
+	 * @param array $existing_reg_payment_REG_IDs
1536
+	 */
1537
+	public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1538
+	{
1539
+		$this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1540
+	}
1541
+
1542
+
1543
+	/**
1544
+	 * _get_existing_reg_payment_REG_IDs
1545
+	 *
1546
+	 * returns a list of registration IDs that the payment is currently related to
1547
+	 * as recorded in the database
1548
+	 *
1549
+	 * @param \EE_Payment $payment
1550
+	 *
1551
+	 * @return array
1552
+	 */
1553
+	protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
1554
+	{
1555
+		if ($this->existing_reg_payment_REG_IDs() === null) {
1556
+			// let's get any existing reg payment records for this payment
1557
+			$existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
1558
+			// but we only want the REG IDs, so grab the array keys
1559
+			$existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs) ? array_keys($existing_reg_payment_REG_IDs) : array();
1560
+			$this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
1561
+		}
1562
+
1563
+		return $this->existing_reg_payment_REG_IDs();
1564
+	}
1565
+
1566
+
1567
+	/**
1568
+	 * _remove_existing_registration_payments
1569
+	 *
1570
+	 * this calculates the difference between existing relations
1571
+	 * to the supplied payment and the new list registration IDs,
1572
+	 * removes any related registrations that no longer apply,
1573
+	 * and then updates the registration paid fields
1574
+	 *
1575
+	 * @param \EE_Payment $payment
1576
+	 * @param int         $PAY_ID
1577
+	 *
1578
+	 * @return bool;
1579
+	 */
1580
+	protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
1581
+	{
1582
+		// newly created payments will have nothing recorded for $PAY_ID
1583
+		if ($PAY_ID == 0) {
1584
+			return false;
1585
+		}
1586
+		$existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
1587
+		if (empty($existing_reg_payment_REG_IDs)) {
1588
+			return false;
1589
+		}
1590
+		/** @type EE_Transaction_Payments $transaction_payments */
1591
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1592
+
1593
+		return $transaction_payments->delete_registration_payments_and_update_registrations(
1594
+			$payment,
1595
+			array(
1596
+				array(
1597
+					'PAY_ID' => $payment->ID(),
1598
+					'REG_ID' => array('IN', $existing_reg_payment_REG_IDs),
1599
+				)
1600
+			)
1601
+		);
1602
+	}
1603
+
1604
+
1605
+	/**
1606
+	 * _update_registration_payments
1607
+	 *
1608
+	 * this applies the payments to the selected registrations
1609
+	 * but only if they have not already been paid for
1610
+	 *
1611
+	 * @param  EE_Transaction $transaction
1612
+	 * @param \EE_Payment     $payment
1613
+	 * @param array           $REG_IDs
1614
+	 *
1615
+	 * @return bool
1616
+	 */
1617
+	protected function _update_registration_payments(
1618
+		EE_Transaction $transaction,
1619
+		EE_Payment $payment,
1620
+		$REG_IDs = array()
1621
+	) {
1622
+		// we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
1623
+		// so let's do that using our set of REG_IDs from the form
1624
+		$registration_query_where_params = array(
1625
+			'REG_ID' => array('IN', $REG_IDs)
1626
+		);
1627
+		// but add in some conditions regarding payment,
1628
+		// so that we don't apply payments to registrations that are free or have already been paid for
1629
+		// but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
1630
+		if ( ! $payment->is_a_refund()) {
1631
+			$registration_query_where_params['REG_final_price']  = array('!=', 0);
1632
+			$registration_query_where_params['REG_final_price*'] = array('!=', 'REG_paid', true);
1633
+		}
1634
+		//EEH_Debug_Tools::printr( $registration_query_where_params, '$registration_query_where_params', __FILE__, __LINE__ );
1635
+		$registrations = $transaction->registrations(array($registration_query_where_params));
1636
+		if ( ! empty($registrations)) {
1637
+			/** @type EE_Payment_Processor $payment_processor */
1638
+			$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
1639
+			$payment_processor->process_registration_payments($transaction, $payment, $registrations);
1640
+		}
1641
+	}
1642
+
1643
+
1644
+	/**
1645
+	 * _process_registration_status_change
1646
+	 *
1647
+	 * This processes requested registration status changes for all the registrations
1648
+	 * on a given transaction and (optionally) sends out notifications for the changes.
1649
+	 *
1650
+	 * @param  EE_Transaction $transaction
1651
+	 * @param array           $REG_IDs
1652
+	 *
1653
+	 * @return bool
1654
+	 */
1655
+	protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = array())
1656
+	{
1657
+		// first if there is no change in status then we get out.
1658
+		if (
1659
+			! isset($this->_req_data['txn_reg_status_change'], $this->_req_data['txn_reg_status_change']['reg_status'])
1660
+			|| $this->_req_data['txn_reg_status_change']['reg_status'] == 'NAN'
1661
+		) {
1662
+			//no error message, no change requested, just nothing to do man.
1663
+			return false;
1664
+		}
1665
+		/** @type EE_Transaction_Processor $transaction_processor */
1666
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1667
+
1668
+		// made it here dude?  Oh WOW.  K, let's take care of changing the statuses
1669
+		return $transaction_processor->manually_update_registration_statuses(
1670
+			$transaction,
1671
+			sanitize_text_field($this->_req_data['txn_reg_status_change']['reg_status']),
1672
+			array(array('REG_ID' => array('IN', $REG_IDs)))
1673
+		);
1674
+	}
1675
+
1676
+
1677
+	/**
1678
+	 * _build_payment_json_response
1679
+	 *
1680
+	 * @access public
1681
+	 *
1682
+	 * @param \EE_Payment $payment
1683
+	 * @param array       $REG_IDs
1684
+	 * @param bool | null $delete_txn_reg_status_change
1685
+	 *
1686
+	 * @return array
1687
+	 */
1688
+	protected function _build_payment_json_response(
1689
+		EE_Payment $payment,
1690
+		$REG_IDs = array(),
1691
+		$delete_txn_reg_status_change = null
1692
+	) {
1693
+		// was the payment deleted ?
1694
+		if (is_bool($delete_txn_reg_status_change)) {
1695
+			return array(
1696
+				'PAY_ID'                       => $payment->ID(),
1697
+				'amount'                       => $payment->amount(),
1698
+				'total_paid'                   => $payment->transaction()->paid(),
1699
+				'txn_status'                   => $payment->transaction()->status_ID(),
1700
+				'pay_status'                   => $payment->STS_ID(),
1701
+				'registrations'                => $this->_registration_payment_data_array($REG_IDs),
1702
+				'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
1703
+			);
1704
+		} else {
1705
+			$this->_get_payment_status_array();
1706
+
1707
+			return array(
1708
+				'amount'           => $payment->amount(),
1709
+				'total_paid'       => $payment->transaction()->paid(),
1710
+				'txn_status'       => $payment->transaction()->status_ID(),
1711
+				'pay_status'       => $payment->STS_ID(),
1712
+				'PAY_ID'           => $payment->ID(),
1713
+				'STS_ID'           => $payment->STS_ID(),
1714
+				'status'           => self::$_pay_status[$payment->STS_ID()],
1715
+				'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
1716
+				'method'           => strtoupper($payment->source()),
1717
+				'PM_ID'            => $payment->payment_method() ? $payment->payment_method()->ID() : 1,
1718
+				'gateway'          => $payment->payment_method() ? $payment->payment_method()->admin_name() : esc_html__("Unknown",
1719
+					'event_espresso'),
1720
+				'gateway_response' => $payment->gateway_response(),
1721
+				'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
1722
+				'po_number'        => $payment->po_number(),
1723
+				'extra_accntng'    => $payment->extra_accntng(),
1724
+				'registrations'    => $this->_registration_payment_data_array($REG_IDs),
1725
+			);
1726
+		}
1727
+	}
1728
+
1729
+
1730
+	/**
1731
+	 * delete_payment
1732
+	 *    delete a payment or refund made towards a transaction
1733
+	 *
1734
+	 * @access public
1735
+	 * @return void
1736
+	 */
1737
+	public function delete_payment()
1738
+	{
1739
+		$json_response_data = array('return_data' => false);
1740
+		$PAY_ID             = isset($this->_req_data['delete_txn_admin_payment'], $this->_req_data['delete_txn_admin_payment']['PAY_ID']) ? absint($this->_req_data['delete_txn_admin_payment']['PAY_ID']) : 0;
1741
+		if ($PAY_ID) {
1742
+			$delete_txn_reg_status_change = isset($this->_req_data['delete_txn_reg_status_change']) ? $this->_req_data['delete_txn_reg_status_change'] : false;
1743
+			$payment                      = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
1744
+			if ($payment instanceof EE_Payment) {
1745
+				$REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
1746
+				/** @type EE_Transaction_Payments $transaction_payments */
1747
+				$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1748
+				if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
1749
+					$json_response_data['return_data'] = $this->_build_payment_json_response($payment, $REG_IDs,
1750
+						$delete_txn_reg_status_change);
1751
+					if ($delete_txn_reg_status_change) {
1752
+						$this->_req_data['txn_reg_status_change'] = $delete_txn_reg_status_change;
1753
+						//MAKE sure we also add the delete_txn_req_status_change to the
1754
+						//$_REQUEST global because that's how messages will be looking for it.
1755
+						$_REQUEST['txn_reg_status_change'] = $delete_txn_reg_status_change;
1756
+						$this->_maybe_send_notifications();
1757
+						$this->_process_registration_status_change($payment->transaction(), $REG_IDs);
1758
+					}
1759
+				}
1760
+			} else {
1761
+				EE_Error::add_error(
1762
+					esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
1763
+					__FILE__, __FUNCTION__, __LINE__
1764
+				);
1765
+			}
1766
+		} else {
1767
+			EE_Error::add_error(
1768
+				esc_html__('A valid Payment ID was not received, therefore payment form data could not be loaded.',
1769
+					'event_espresso'),
1770
+				__FILE__, __FUNCTION__, __LINE__
1771
+			);
1772
+		}
1773
+		$notices              = EE_Error::get_notices(false, false, false);
1774
+		$this->_template_args = array(
1775
+			'data'      => $json_response_data,
1776
+			'success'   => $notices['success'],
1777
+			'error'     => $notices['errors'],
1778
+			'attention' => $notices['attention']
1779
+		);
1780
+		$this->_return_json();
1781
+	}
1782
+
1783
+
1784
+	/**
1785
+	 * _registration_payment_data_array
1786
+	 * adds info for 'owing' and 'paid' for each registration to the json response
1787
+	 *
1788
+	 * @access protected
1789
+	 *
1790
+	 * @param array $REG_IDs
1791
+	 *
1792
+	 * @return array
1793
+	 */
1794
+	protected function _registration_payment_data_array($REG_IDs)
1795
+	{
1796
+		$registration_payment_data = array();
1797
+		//if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
1798
+		if ( ! empty($REG_IDs)) {
1799
+			$registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
1800
+			foreach ($registrations as $registration) {
1801
+				if ($registration instanceof EE_Registration) {
1802
+					$registration_payment_data[$registration->ID()] = array(
1803
+						'paid'  => $registration->pretty_paid(),
1804
+						'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
1805
+					);
1806
+				}
1807
+			}
1808
+		}
1809
+
1810
+		return $registration_payment_data;
1811
+	}
1812
+
1813
+
1814
+	/**
1815
+	 * _maybe_send_notifications
1816
+	 *
1817
+	 * determines whether or not the admin has indicated that notifications should be sent.
1818
+	 * If so, will toggle a filter switch for delivering registration notices.
1819
+	 * If passed an EE_Payment object, then it will trigger payment notifications instead.
1820
+	 *
1821
+	 * @access protected
1822
+	 *
1823
+	 * @param \EE_Payment | null $payment
1824
+	 */
1825
+	protected function _maybe_send_notifications($payment = null)
1826
+	{
1827
+		switch ($payment instanceof EE_Payment) {
1828
+			// payment notifications
1829
+			case true :
1830
+				if (
1831
+					isset(
1832
+						$this->_req_data['txn_payments'],
1833
+						$this->_req_data['txn_payments']['send_notifications']
1834
+					) &&
1835
+					filter_var($this->_req_data['txn_payments']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
1836
+				) {
1837
+					$this->_process_payment_notification($payment);
1838
+				}
1839
+				break;
1840
+			// registration notifications
1841
+			case false :
1842
+				if (
1843
+					isset(
1844
+						$this->_req_data['txn_reg_status_change'],
1845
+						$this->_req_data['txn_reg_status_change']['send_notifications']
1846
+					) &&
1847
+					filter_var($this->_req_data['txn_reg_status_change']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
1848
+				) {
1849
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
1850
+				}
1851
+				break;
1852
+		}
1853
+	}
1854
+
1855
+
1856
+	/**
1857
+	 * _send_payment_reminder
1858
+	 *    generates HTML for the View Transaction Details Admin page
1859
+	 *
1860
+	 * @access protected
1861
+	 * @return void
1862
+	 */
1863
+	protected function _send_payment_reminder()
1864
+	{
1865
+		$TXN_ID      = ( ! empty($this->_req_data['TXN_ID'])) ? absint($this->_req_data['TXN_ID']) : false;
1866
+		$transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
1867
+		$query_args  = isset($this->_req_data['redirect_to']) ? array(
1868
+			'action' => $this->_req_data['redirect_to'],
1869
+			'TXN_ID' => $this->_req_data['TXN_ID']
1870
+		) : array();
1871
+		do_action('AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
1872
+			$transaction);
1873
+		$this->_redirect_after_action(false, esc_html__('payment reminder', 'event_espresso'),
1874
+			esc_html__('sent', 'event_espresso'), $query_args, true);
1875
+	}
1876
+
1877
+
1878
+	/**
1879
+	 *  get_transactions
1880
+	 *    get transactions for given parameters (used by list table)
1881
+	 *
1882
+	 * @param  int     $perpage how many transactions displayed per page
1883
+	 * @param  boolean $count   return the count or objects
1884
+	 * @param string   $view
1885
+	 *
1886
+	 * @return mixed int = count || array of transaction objects
1887
+	 */
1888
+	public function get_transactions($perpage, $count = false, $view = '')
1889
+	{
1890
+
1891
+		$TXN = EEM_Transaction::instance();
1892
+
1893
+		$start_date = isset($this->_req_data['txn-filter-start-date']) ? wp_strip_all_tags($this->_req_data['txn-filter-start-date']) : date('m/d/Y',
1894
+			strtotime('-10 year'));
1895
+		$end_date   = isset($this->_req_data['txn-filter-end-date']) ? wp_strip_all_tags($this->_req_data['txn-filter-end-date']) : date('m/d/Y');
1896
+
1897
+		//make sure our timestamps start and end right at the boundaries for each day
1898
+		$start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
1899
+		$end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
1900
+
1901
+
1902
+		//convert to timestamps
1903
+		$start_date = strtotime($start_date);
1904
+		$end_date   = strtotime($end_date);
1905
+
1906
+		//makes sure start date is the lowest value and vice versa
1907
+		$start_date = min($start_date, $end_date);
1908
+		$end_date   = max($start_date, $end_date);
1909
+
1910
+		//convert to correct format for query
1911
+		$start_date = EEM_Transaction::instance()->convert_datetime_for_query('TXN_timestamp',
1912
+			date('Y-m-d H:i:s', $start_date), 'Y-m-d H:i:s');
1913
+		$end_date   = EEM_Transaction::instance()->convert_datetime_for_query('TXN_timestamp',
1914
+			date('Y-m-d H:i:s', $end_date), 'Y-m-d H:i:s');
1915
+
1916
+
1917
+		//set orderby
1918
+		$this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
1919
+
1920
+		switch ($this->_req_data['orderby']) {
1921
+			case 'TXN_ID':
1922
+				$orderby = 'TXN_ID';
1923
+				break;
1924
+			case 'ATT_fname':
1925
+				$orderby = 'Registration.Attendee.ATT_fname';
1926
+				break;
1927
+			case 'event_name':
1928
+				$orderby = 'Registration.Event.EVT_name';
1929
+				break;
1930
+			default: //'TXN_timestamp'
1931
+				$orderby = 'TXN_timestamp';
1932
+		}
1933
+
1934
+		$sort         = (isset($this->_req_data['order']) && ! empty($this->_req_data['order'])) ? $this->_req_data['order'] : 'DESC';
1935
+		$current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged']) ? $this->_req_data['paged'] : 1;
1936
+		$per_page     = isset($perpage) && ! empty($perpage) ? $perpage : 10;
1937
+		$per_page     = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage']) ? $this->_req_data['perpage'] : $per_page;
1938
+
1939
+		$offset = ($current_page - 1) * $per_page;
1940
+		$limit  = array($offset, $per_page);
1941
+
1942
+		$_where = array(
1943
+			'TXN_timestamp'          => array('BETWEEN', array($start_date, $end_date)),
1944
+			'Registration.REG_count' => 1
1945
+		);
1946
+
1947
+		if (isset($this->_req_data['EVT_ID'])) {
1948
+			$_where['Registration.EVT_ID'] = $this->_req_data['EVT_ID'];
1949
+		}
1950
+
1951
+		if (isset($this->_req_data['s'])) {
1952
+			$search_string = '%' . $this->_req_data['s'] . '%';
1953
+			$_where['OR']  = array(
1954
+				'Registration.Event.EVT_name'         => array('LIKE', $search_string),
1955
+				'Registration.Event.EVT_desc'         => array('LIKE', $search_string),
1956
+				'Registration.Event.EVT_short_desc'   => array('LIKE', $search_string),
1957
+				'Registration.Attendee.ATT_full_name' => array('LIKE', $search_string),
1958
+				'Registration.Attendee.ATT_fname'     => array('LIKE', $search_string),
1959
+				'Registration.Attendee.ATT_lname'     => array('LIKE', $search_string),
1960
+				'Registration.Attendee.ATT_short_bio' => array('LIKE', $search_string),
1961
+				'Registration.Attendee.ATT_email'     => array('LIKE', $search_string),
1962
+				'Registration.Attendee.ATT_address'   => array('LIKE', $search_string),
1963
+				'Registration.Attendee.ATT_address2'  => array('LIKE', $search_string),
1964
+				'Registration.Attendee.ATT_city'      => array('LIKE', $search_string),
1965
+				'Registration.REG_final_price'        => array('LIKE', $search_string),
1966
+				'Registration.REG_code'               => array('LIKE', $search_string),
1967
+				'Registration.REG_count'              => array('LIKE', $search_string),
1968
+				'Registration.REG_group_size'         => array('LIKE', $search_string),
1969
+				'Registration.Ticket.TKT_name'        => array('LIKE', $search_string),
1970
+				'Registration.Ticket.TKT_description' => array('LIKE', $search_string),
1971
+				'Payment.PAY_source'                  => array('LIKE', $search_string),
1972
+				'Payment.Payment_Method.PMD_name'     => array('LIKE', $search_string),
1973
+				'TXN_session_data'                    => array('LIKE', $search_string),
1974
+				'Payment.PAY_txn_id_chq_nmbr'         => array('LIKE', $search_string)
1975
+			);
1976
+		}
1977
+
1978
+		//failed transactions
1979
+		$failed    = ( ! empty($this->_req_data['status']) && $this->_req_data['status'] == 'failed' && ! $count) || ($count && $view == 'failed') ? true : false;
1980
+		$abandoned = ( ! empty($this->_req_data['status']) && $this->_req_data['status'] == 'abandoned' && ! $count) || ($count && $view == 'abandoned') ? true : false;
1981
+
1982
+		if ($failed) {
1983
+			$_where['STS_ID'] = EEM_Transaction::failed_status_code;
1984
+		} else if ($abandoned) {
1985
+			$_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
1986
+		} else {
1987
+			$_where['STS_ID']  = array('!=', EEM_Transaction::failed_status_code);
1988
+			$_where['STS_ID*'] = array('!=', EEM_Transaction::abandoned_status_code);
1989
+		}
1990
+
1991
+		$query_params = array($_where, 'order_by' => array($orderby => $sort), 'limit' => $limit);
1992
+
1993
+		$transactions = $count ? $TXN->count(array($_where), 'TXN_ID', true) : $TXN->get_all($query_params);
1994
+
1995
+
1996
+		return $transactions;
1997
+
1998
+	}
1999 1999
 
2000 2000
 
2001 2001
 }
Please login to merge, or discard this patch.
modules/core_rest_api/EED_Core_Rest_Api.module.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -421,7 +421,7 @@
 block discarded – undo
421 421
     /**
422 422
      * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`)
423 423
      * in this versioned namespace of EE4
424
-     * @param $version
424
+     * @param string $version
425 425
      * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
426 426
      */
427 427
     public static function model_names_with_plural_routes($version){
Please login to merge, or discard this patch.
Indentation   +1221 added lines, -1221 removed lines patch added patch discarded remove patch
@@ -23,1228 +23,1228 @@
 block discarded – undo
23 23
 class EED_Core_Rest_Api extends \EED_Module
24 24
 {
25 25
 
26
-    const ee_api_namespace           = 'ee/v';
26
+	const ee_api_namespace           = 'ee/v';
27 27
 
28
-    const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/';
29
-
30
-    const saved_routes_option_names  = 'ee_core_routes';
31
-
32
-    /**
33
-     * string used in _links response bodies to make them globally unique.
34
-     *
35
-     * @see http://v2.wp-api.org/extending/linking/
36
-     */
37
-    const ee_api_link_namespace = 'https://api.eventespresso.com/';
38
-
39
-    /**
40
-     * @var CalculatedModelFields
41
-     */
42
-    protected static $_field_calculator;
43
-
44
-
45
-
46
-    /**
47
-     * @return EED_Core_Rest_Api|EED_Module
48
-     */
49
-    public static function instance()
50
-    {
51
-        self::$_field_calculator = new CalculatedModelFields();
52
-        return parent::get_instance(__CLASS__);
53
-    }
54
-
55
-
56
-
57
-    /**
58
-     *    set_hooks - for hooking into EE Core, other modules, etc
59
-     *
60
-     * @access    public
61
-     * @return    void
62
-     */
63
-    public static function set_hooks()
64
-    {
65
-        self::set_hooks_both();
66
-    }
67
-
68
-
69
-
70
-    /**
71
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
72
-     *
73
-     * @access    public
74
-     * @return    void
75
-     */
76
-    public static function set_hooks_admin()
77
-    {
78
-        self::set_hooks_both();
79
-    }
80
-
81
-
82
-
83
-    public static function set_hooks_both()
84
-    {
85
-        add_action('rest_api_init', array('EED_Core_Rest_Api', 'register_routes'), 10);
86
-        add_action('rest_api_init', array('EED_Core_Rest_Api', 'set_hooks_rest_api'), 5);
87
-        add_filter('rest_route_data', array('EED_Core_Rest_Api', 'hide_old_endpoints'), 10, 2);
88
-        add_filter('rest_index',
89
-            array('EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex'));
90
-        EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change();
91
-    }
92
-
93
-
94
-
95
-    /**
96
-     * sets up hooks which only need to be included as part of REST API requests;
97
-     * other requests like to the frontend or admin etc don't need them
98
-     *
99
-     * @throws \EE_Error
100
-     */
101
-    public static function set_hooks_rest_api()
102
-    {
103
-        //set hooks which account for changes made to the API
104
-        EED_Core_Rest_Api::_set_hooks_for_changes();
105
-    }
106
-
107
-
108
-
109
-    /**
110
-     * public wrapper of _set_hooks_for_changes.
111
-     * Loads all the hooks which make requests to old versions of the API
112
-     * appear the same as they always did
113
-     *
114
-     * @throws EE_Error
115
-     */
116
-    public static function set_hooks_for_changes()
117
-    {
118
-        self::_set_hooks_for_changes();
119
-    }
120
-
121
-
122
-
123
-    /**
124
-     * Loads all the hooks which make requests to old versions of the API
125
-     * appear the same as they always did
126
-     *
127
-     * @throws EE_Error
128
-     */
129
-    protected static function _set_hooks_for_changes()
130
-    {
131
-        $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false);
132
-        foreach ($folder_contents as $classname_in_namespace => $filepath) {
133
-            //ignore the base parent class
134
-            //and legacy named classes
135
-            if ($classname_in_namespace === 'ChangesInBase'
136
-                || strpos($classname_in_namespace, 'Changes_In_') === 0
137
-            ) {
138
-                continue;
139
-            }
140
-            $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
141
-            if (class_exists($full_classname)) {
142
-                $instance_of_class = new $full_classname;
143
-                if ($instance_of_class instanceof ChangesInBase) {
144
-                    $instance_of_class->setHooks();
145
-                }
146
-            }
147
-        }
148
-    }
149
-
150
-
151
-
152
-    /**
153
-     * Filters the WP routes to add our EE-related ones. This takes a bit of time
154
-     * so we actually prefer to only do it when an EE plugin is activated or upgraded
155
-     *
156
-     * @throws \EE_Error
157
-     */
158
-    public static function register_routes()
159
-    {
160
-        foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) {
161
-            foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) {
162
-                /**
163
-                 * @var array $data_for_multiple_endpoints numerically indexed array
164
-                 *                                         but can also contain route options like {
165
-                 * @type array    $schema                      {
166
-                 * @type callable $schema_callback
167
-                 * @type array    $callback_args               arguments that will be passed to the callback, after the
168
-                 * WP_REST_Request of course
169
-                 * }
170
-                 * }
171
-                 */
172
-                //when registering routes, register all the endpoints' data at the same time
173
-                $multiple_endpoint_args = array();
174
-                foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) {
175
-                    /**
176
-                     * @var array     $data_for_single_endpoint {
177
-                     * @type callable $callback
178
-                     * @type string methods
179
-                     * @type array args
180
-                     * @type array _links
181
-                     * @type array    $callback_args            arguments that will be passed to the callback, after the
182
-                     * WP_REST_Request of course
183
-                     * }
184
-                     */
185
-                    //skip route options
186
-                    if (! is_numeric($endpoint_key)) {
187
-                        continue;
188
-                    }
189
-                    if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
190
-                        throw new EE_Error(
191
-                            esc_html__(
192
-                                // @codingStandardsIgnoreStart
193
-                                'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).',
194
-                                // @codingStandardsIgnoreEnd
195
-                                'event_espresso')
196
-                        );
197
-                    }
198
-                    $callback = $data_for_single_endpoint['callback'];
199
-                    $single_endpoint_args = array(
200
-                        'methods' => $data_for_single_endpoint['methods'],
201
-                        'args'    => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args']
202
-                            : array(),
203
-                    );
204
-                    if (isset($data_for_single_endpoint['_links'])) {
205
-                        $single_endpoint_args['_links'] = $data_for_single_endpoint['_links'];
206
-                    }
207
-                    if (isset($data_for_single_endpoint['callback_args'])) {
208
-                        $callback_args = $data_for_single_endpoint['callback_args'];
209
-                        $single_endpoint_args['callback'] = function (\WP_REST_Request $request) use (
210
-                            $callback,
211
-                            $callback_args
212
-                        ) {
213
-                            array_unshift($callback_args, $request);
214
-                            return call_user_func_array(
215
-                                $callback,
216
-                                $callback_args
217
-                            );
218
-                        };
219
-                    } else {
220
-                        $single_endpoint_args['callback'] = $data_for_single_endpoint['callback'];
221
-                    }
222
-                    $multiple_endpoint_args[] = $single_endpoint_args;
223
-                }
224
-                if (isset($data_for_multiple_endpoints['schema'])) {
225
-                    $schema_route_data = $data_for_multiple_endpoints['schema'];
226
-                    $schema_callback = $schema_route_data['schema_callback'];
227
-                    $callback_args = $schema_route_data['callback_args'];
228
-                    $multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) {
229
-                        return call_user_func_array(
230
-                            $schema_callback,
231
-                            $callback_args
232
-                        );
233
-                    };
234
-                }
235
-                register_rest_route(
236
-                    $namespace,
237
-                    $relative_route,
238
-                    $multiple_endpoint_args
239
-                );
240
-            }
241
-        }
242
-    }
243
-
244
-
245
-
246
-    /**
247
-     * Checks if there was a version change or something that merits invalidating the cached
248
-     * route data. If so, invalidates the cached route data so that it gets refreshed
249
-     * next time the WP API is used
250
-     */
251
-    public static function invalidate_cached_route_data_on_version_change()
252
-    {
253
-        if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) {
254
-            EED_Core_Rest_Api::invalidate_cached_route_data();
255
-        }
256
-        foreach (EE_Registry::instance()->addons as $addon) {
257
-            if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) {
258
-                EED_Core_Rest_Api::invalidate_cached_route_data();
259
-            }
260
-        }
261
-    }
262
-
263
-
264
-
265
-    /**
266
-     * Removes the cached route data so it will get refreshed next time the WP API is used
267
-     */
268
-    public static function invalidate_cached_route_data()
269
-    {
270
-        //delete the saved EE REST API routes
271
-        foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
272
-            delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
273
-        }
274
-    }
275
-
276
-
277
-
278
-    /**
279
-     * Gets the EE route data
280
-     *
281
-     * @return array top-level key is the namespace, next-level key is the route and its value is array{
282
-     * @throws \EE_Error
283
-     * @type string|array $callback
284
-     * @type string       $methods
285
-     * @type boolean      $hidden_endpoint
286
-     * }
287
-     */
288
-    public static function get_ee_route_data()
289
-    {
290
-        $ee_routes = array();
291
-        foreach (self::versions_served() as $version => $hidden_endpoints) {
292
-            $ee_routes[self::ee_api_namespace . $version] = self::_get_ee_route_data_for_version(
293
-                $version,
294
-                $hidden_endpoints
295
-            );
296
-        }
297
-        return $ee_routes;
298
-    }
299
-
300
-
301
-
302
-    /**
303
-     * Gets the EE route data from the wp options if it exists already,
304
-     * otherwise re-generates it and saves it to the option
305
-     *
306
-     * @param string  $version
307
-     * @param boolean $hidden_endpoints
308
-     * @return array
309
-     * @throws \EE_Error
310
-     */
311
-    protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
312
-    {
313
-        $ee_routes = get_option(self::saved_routes_option_names . $version, null);
314
-        if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) {
315
-            $ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints);
316
-        }
317
-        return $ee_routes;
318
-    }
319
-
320
-
321
-
322
-    /**
323
-     * Saves the EE REST API route data to a wp option and returns it
324
-     *
325
-     * @param string  $version
326
-     * @param boolean $hidden_endpoints
327
-     * @return mixed|null
328
-     * @throws \EE_Error
329
-     */
330
-    protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false)
331
-    {
332
-        $instance = self::instance();
333
-        $routes = apply_filters(
334
-            'EED_Core_Rest_Api__save_ee_route_data_for_version__routes',
335
-            array_replace_recursive(
336
-                $instance->_get_config_route_data_for_version($version, $hidden_endpoints),
337
-                $instance->_get_meta_route_data_for_version($version, $hidden_endpoints),
338
-                $instance->_get_model_route_data_for_version($version, $hidden_endpoints),
339
-                $instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
340
-            )
341
-        );
342
-        $option_name = self::saved_routes_option_names . $version;
343
-        if (get_option($option_name)) {
344
-            update_option($option_name, $routes, true);
345
-        } else {
346
-            add_option($option_name, $routes, null, 'no');
347
-        }
348
-        return $routes;
349
-    }
350
-
351
-
352
-
353
-    /**
354
-     * Calculates all the EE routes and saves it to a WordPress option so we don't
355
-     * need to calculate it on every request
356
-     *
357
-     * @deprecated since version 4.9.1
358
-     * @return void
359
-     */
360
-    public static function save_ee_routes()
361
-    {
362
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
363
-            $instance = self::instance();
364
-            $routes = apply_filters(
365
-                'EED_Core_Rest_Api__save_ee_routes__routes',
366
-                array_replace_recursive(
367
-                    $instance->_register_config_routes(),
368
-                    $instance->_register_meta_routes(),
369
-                    $instance->_register_model_routes(),
370
-                    $instance->_register_rpc_routes()
371
-                )
372
-            );
373
-            update_option(self::saved_routes_option_names, $routes, true);
374
-        }
375
-    }
376
-
377
-
378
-
379
-    /**
380
-     * Gets all the route information relating to EE models
381
-     *
382
-     * @return array @see get_ee_route_data
383
-     * @deprecated since version 4.9.1
384
-     */
385
-    protected function _register_model_routes()
386
-    {
387
-        $model_routes = array();
388
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
389
-            $model_routes[EED_Core_Rest_Api::ee_api_namespace
390
-                          . $version] = $this->_get_config_route_data_for_version($version, $hidden_endpoint);
391
-        }
392
-        return $model_routes;
393
-    }
394
-
395
-
396
-
397
-    /**
398
-     * Decides whether or not to add write endpoints for this model.
399
-     *
400
-     * Currently, this defaults to exclude all global tables and models
401
-     * which would allow inserting WP core data (we don't want to duplicate
402
-     * what WP API does, as it's unnecessary, extra work, and potentially extra bugs)
403
-     * @param EEM_Base $model
404
-     * @return bool
405
-     */
406
-    public static function should_have_write_endpoints(EEM_Base $model)
407
-    {
408
-        if ($model->is_wp_core_model()){
409
-            return false;
410
-        }
411
-        foreach($model->get_tables() as $table){
412
-            if( $table->is_global()){
413
-                return false;
414
-            }
415
-        }
416
-        return true;
417
-    }
418
-
419
-
420
-
421
-    /**
422
-     * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`)
423
-     * in this versioned namespace of EE4
424
-     * @param $version
425
-     * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
426
-     */
427
-    public static function model_names_with_plural_routes($version){
428
-        $model_version_info = new ModelVersionInfo($version);
429
-        $models_to_register = $model_version_info->modelsForRequestedVersion();
430
-        //let's not bother having endpoints for extra metas
431
-        unset(
432
-            $models_to_register['Extra_Meta'],
433
-            $models_to_register['Extra_Join'],
434
-            $models_to_register['Post_Meta']
435
-        );
436
-        return apply_filters(
437
-            'FHEE__EED_Core_REST_API___register_model_routes',
438
-            $models_to_register
439
-        );
440
-    }
441
-
442
-
443
-
444
-    /**
445
-     * Gets the route data for EE models in the specified version
446
-     *
447
-     * @param string  $version
448
-     * @param boolean $hidden_endpoint
449
-     * @return array
450
-     * @throws EE_Error
451
-     */
452
-    protected function _get_model_route_data_for_version($version, $hidden_endpoint = false)
453
-    {
454
-        $model_routes = array();
455
-        $model_version_info = new ModelVersionInfo($version);
456
-        foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
457
-            $model = \EE_Registry::instance()->load_model($model_name);
458
-            //if this isn't a valid model then let's skip iterate to the next item in the loop.
459
-            if (! $model instanceof EEM_Base) {
460
-                continue;
461
-            }
462
-            //yes we could just register one route for ALL models, but then they wouldn't show up in the index
463
-            $plural_model_route = EED_Core_Rest_Api::get_collection_route($model);
464
-            $singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)');
465
-            $model_routes[$plural_model_route] = array(
466
-                array(
467
-                    'callback'        => array(
468
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
469
-                        'handleRequestGetAll',
470
-                    ),
471
-                    'callback_args'   => array($version, $model_name),
472
-                    'methods'         => WP_REST_Server::READABLE,
473
-                    'hidden_endpoint' => $hidden_endpoint,
474
-                    'args'            => $this->_get_read_query_params($model, $version),
475
-                    '_links'          => array(
476
-                        'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
477
-                    ),
478
-                ),
479
-                'schema' => array(
480
-                    'schema_callback' => array(
481
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
482
-                        'handleSchemaRequest',
483
-                    ),
484
-                    'callback_args'   => array($version, $model_name),
485
-                ),
486
-            );
487
-            $model_routes[$singular_model_route] = array(
488
-                array(
489
-                    'callback'        => array(
490
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
491
-                        'handleRequestGetOne',
492
-                    ),
493
-                    'callback_args'   => array($version, $model_name),
494
-                    'methods'         => WP_REST_Server::READABLE,
495
-                    'hidden_endpoint' => $hidden_endpoint,
496
-                    'args'            => $this->_get_response_selection_query_params($model, $version),
497
-                ),
498
-            );
499
-            if( apply_filters(
500
-                'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints',
501
-                EED_Core_Rest_Api::should_have_write_endpoints($model),
502
-                $model
503
-            )){
504
-                $model_routes[$plural_model_route][] = array(
505
-                    'callback'        => array(
506
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Write',
507
-                        'handleRequestInsert',
508
-                    ),
509
-                    'callback_args'   => array($version, $model_name),
510
-                    'methods'         => WP_REST_Server::CREATABLE,
511
-                    'hidden_endpoint' => $hidden_endpoint,
512
-                    'args'            => $this->_get_write_params($model_name, $model_version_info, true),
513
-                );
514
-                $model_routes[$singular_model_route] = array_merge(
515
-                    $model_routes[$singular_model_route],
516
-                    array(
517
-                        array(
518
-                            'callback'        => array(
519
-                                'EventEspresso\core\libraries\rest_api\controllers\model\Write',
520
-                                'handleRequestUpdate',
521
-                            ),
522
-                            'callback_args'   => array($version, $model_name),
523
-                            'methods'         => WP_REST_Server::EDITABLE,
524
-                            'hidden_endpoint' => $hidden_endpoint,
525
-                            'args'            => $this->_get_write_params($model_name, $model_version_info),
526
-                        ),
527
-                        array(
528
-                            'callback'        => array(
529
-                                'EventEspresso\core\libraries\rest_api\controllers\model\Write',
530
-                                'handleRequestDelete',
531
-                            ),
532
-                            'callback_args'   => array($version, $model_name),
533
-                            'methods'         => WP_REST_Server::DELETABLE,
534
-                            'hidden_endpoint' => $hidden_endpoint,
535
-                            'args'            => $this->_get_delete_query_params($model, $version),
536
-                        )
537
-                    )
538
-                );
539
-            }
540
-            foreach ($model->relation_settings() as $relation_name => $relation_obj) {
541
-
542
-                $related_route = EED_Core_Rest_Api::get_relation_route_via(
543
-                    $model,
544
-                    '(?P<id>[^\/]+)',
545
-                    $relation_obj
546
-                );
547
-                $endpoints = array(
548
-                    array(
549
-                        'callback'        => array(
550
-                            'EventEspresso\core\libraries\rest_api\controllers\model\Read',
551
-                            'handleRequestGetRelated',
552
-                        ),
553
-                        'callback_args'   => array($version, $model_name, $relation_name),
554
-                        'methods'         => WP_REST_Server::READABLE,
555
-                        'hidden_endpoint' => $hidden_endpoint,
556
-                        'args'            => $this->_get_read_query_params($relation_obj->get_other_model(), $version),
557
-                    ),
558
-                );
559
-                $model_routes[$related_route] = $endpoints;
560
-            }
561
-        }
562
-        return $model_routes;
563
-    }
564
-
565
-
566
-
567
-    /**
568
-     * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
569
-     * excluding the preceding slash.
570
-     * Eg you pass get_plural_route_to('Event') = 'events'
571
-     *
572
-     * @param EEM_Base $model
573
-     * @return string
574
-     */
575
-    public static function get_collection_route(EEM_Base $model)
576
-    {
577
-        return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
578
-    }
579
-
580
-
581
-
582
-    /**
583
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
584
-     * excluding the preceding slash.
585
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
586
-     *
587
-     * @param EEM_Base $model eg Event or Venue
588
-     * @param string $id
589
-     * @return string
590
-     */
591
-    public static function get_entity_route($model, $id)
592
-    {
593
-        return EED_Core_Rest_Api::get_collection_route($model). '/' . $id;
594
-    }
595
-
596
-
597
-    /**
598
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
599
-     * excluding the preceding slash.
600
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
601
-     *
602
-     * @param EEM_Base                 $model eg Event or Venue
603
-     * @param string                 $id
604
-     * @param EE_Model_Relation_Base $relation_obj
605
-     * @return string
606
-     */
607
-    public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
608
-    {
609
-        $related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
610
-            $relation_obj->get_other_model()->get_this_model_name(),
611
-            $relation_obj
612
-        );
613
-        return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
614
-    }
615
-
616
-
617
-
618
-    /**
619
-     * Adds onto the $relative_route the EE4 REST API versioned namespace.
620
-     * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
621
-     * @param string $relative_route
622
-     * @param string $version
623
-     * @return string
624
-     */
625
-    public static function get_versioned_route_to($relative_route, $version = '4.8.36'){
626
-        return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
627
-    }
628
-
629
-
630
-
631
-    /**
632
-     * Adds all the RPC-style routes (remote procedure call-like routes, ie
633
-     * routes that don't conform to the traditional REST CRUD-style).
634
-     *
635
-     * @deprecated since 4.9.1
636
-     */
637
-    protected function _register_rpc_routes()
638
-    {
639
-        $routes = array();
640
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
641
-            $routes[self::ee_api_namespace . $version] = $this->_get_rpc_route_data_for_version(
642
-                $version,
643
-                $hidden_endpoint
644
-            );
645
-        }
646
-        return $routes;
647
-    }
648
-
649
-
650
-
651
-    /**
652
-     * @param string  $version
653
-     * @param boolean $hidden_endpoint
654
-     * @return array
655
-     */
656
-    protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
657
-    {
658
-        $this_versions_routes = array();
659
-        //checkin endpoint
660
-        $this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array(
661
-            array(
662
-                'callback'        => array(
663
-                    'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
664
-                    'handleRequestToggleCheckin',
665
-                ),
666
-                'methods'         => WP_REST_Server::CREATABLE,
667
-                'hidden_endpoint' => $hidden_endpoint,
668
-                'args'            => array(
669
-                    'force' => array(
670
-                        'required'    => false,
671
-                        'default'     => false,
672
-                        'description' => __(
673
-                            // @codingStandardsIgnoreStart
674
-                            'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
675
-                            // @codingStandardsIgnoreEnd
676
-                            'event_espresso'
677
-                        ),
678
-                    ),
679
-                ),
680
-                'callback_args'   => array($version),
681
-            ),
682
-        );
683
-        return apply_filters(
684
-            'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
685
-            $this_versions_routes,
686
-            $version,
687
-            $hidden_endpoint
688
-        );
689
-    }
690
-
691
-
692
-
693
-    /**
694
-     * Gets the query params that can be used when request one or many
695
-     *
696
-     * @param EEM_Base $model
697
-     * @param string   $version
698
-     * @return array
699
-     */
700
-    protected function _get_response_selection_query_params(\EEM_Base $model, $version)
701
-    {
702
-        return apply_filters(
703
-            'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
704
-            array(
705
-                'include'   => array(
706
-                    'required' => false,
707
-                    'default'  => '*',
708
-                    'type'     => 'string',
709
-                ),
710
-                'calculate' => array(
711
-                    'required'          => false,
712
-                    'default'           => '',
713
-                    'enum'              => self::$_field_calculator->retrieveCalculatedFieldsForModel($model),
714
-                    'type'              => 'string',
715
-                    //because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization
716
-                    //freaks out. We'll just validate this argument while handling the request
717
-                    'validate_callback' => null,
718
-                    'sanitize_callback' => null,
719
-                ),
720
-            ),
721
-            $model,
722
-            $version
723
-        );
724
-    }
725
-
726
-
727
-
728
-    /**
729
-     * Gets the parameters acceptable for delete requests
730
-     *
731
-     * @param \EEM_Base $model
732
-     * @param string    $version
733
-     * @return array
734
-     */
735
-    protected function _get_delete_query_params(\EEM_Base $model, $version)
736
-    {
737
-        $params_for_delete = array(
738
-            'allow_blocking' => array(
739
-                'required' => false,
740
-                'default'  => true,
741
-                'type'     => 'boolean',
742
-            ),
743
-        );
744
-        $params_for_delete['force'] = array(
745
-            'required' => false,
746
-            'default'  => false,
747
-            'type'     => 'boolean',
748
-        );
749
-        return apply_filters(
750
-            'FHEE__EED_Core_Rest_Api___get_delete_query_params',
751
-            $params_for_delete,
752
-            $model,
753
-            $version
754
-        );
755
-    }
756
-
757
-
758
-
759
-    /**
760
-     * Gets info about reading query params that are acceptable
761
-     *
762
-     * @param \EEM_Base $model eg 'Event' or 'Venue'
763
-     * @param  string   $version
764
-     * @return array    describing the args acceptable when querying this model
765
-     * @throws EE_Error
766
-     */
767
-    protected function _get_read_query_params(\EEM_Base $model, $version)
768
-    {
769
-        $default_orderby = array();
770
-        foreach ($model->get_combined_primary_key_fields() as $key_field) {
771
-            $default_orderby[$key_field->get_name()] = 'ASC';
772
-        }
773
-        return array_merge(
774
-            $this->_get_response_selection_query_params($model, $version),
775
-            array(
776
-                'where'    => array(
777
-                    'required' => false,
778
-                    'default'  => array(),
779
-                    'type'     => 'object',
780
-                ),
781
-                'limit'    => array(
782
-                    'required' => false,
783
-                    'default'  => EED_Core_Rest_Api::get_default_query_limit(),
784
-                    'type'     => array(
785
-                        'object',
786
-                        'string',
787
-                        'integer',
788
-                    ),
789
-                ),
790
-                'order_by' => array(
791
-                    'required' => false,
792
-                    'default'  => $default_orderby,
793
-                    'type'     => array(
794
-                        'object',
795
-                        'string',
796
-                    ),
797
-                ),
798
-                'group_by' => array(
799
-                    'required' => false,
800
-                    'default'  => null,
801
-                    'type'     => array(
802
-                        'object',
803
-                        'string',
804
-                    ),
805
-                ),
806
-                'having'   => array(
807
-                    'required' => false,
808
-                    'default'  => null,
809
-                    'type'     => 'object',
810
-                ),
811
-                'caps'     => array(
812
-                    'required' => false,
813
-                    'default'  => EEM_Base::caps_read,
814
-                    'type'     => 'string',
815
-                ),
816
-            )
817
-        );
818
-    }
819
-
820
-
821
-
822
-    /**
823
-     * Gets parameter information for a model regarding writing data
824
-     *
825
-     * @param string           $model_name
826
-     * @param ModelVersionInfo $model_version_info
827
-     * @param boolean          $create                                       whether this is for request to create (in which case we need
828
-     *                                                                       all required params) or just to update (in which case we don't need those on every request)
829
-     * @return array
830
-     */
831
-    protected function _get_write_params(
832
-        $model_name,
833
-        ModelVersionInfo $model_version_info,
834
-        $create = false
835
-    ) {
836
-        $model = EE_Registry::instance()->load_model($model_name);
837
-        $fields = $model_version_info->fieldsOnModelInThisVersion($model);
838
-        $args_info = array();
839
-        foreach ($fields as $field_name => $field_obj) {
840
-            if ($field_obj->is_auto_increment()) {
841
-                //totally ignore auto increment IDs
842
-                continue;
843
-            }
844
-            $arg_info = $field_obj->getSchema();
845
-            $required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
846
-            $arg_info['required'] = $required;
847
-            //remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
848
-            unset($arg_info['readonly']);
849
-            $schema_properties = $field_obj->getSchemaProperties();
850
-            if (
851
-                isset($schema_properties['raw'])
852
-                && $field_obj->getSchemaType() === 'object'
853
-            ) {
854
-                //if there's a "raw" form of this argument, use those properties instead
855
-                $arg_info = array_replace(
856
-                    $arg_info,
857
-                    $schema_properties['raw']
858
-                );
859
-            }
860
-            $arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
861
-                $field_obj,
862
-                $field_obj->get_default_value(),
863
-                $model_version_info->requestedVersion()
864
-            );
865
-            //we do our own validation and sanitization within the controller
866
-            $arg_info['sanitize_callback'] =
867
-                array(
868
-                    'EED_Core_Rest_Api',
869
-                    'default_sanitize_callback',
870
-                );
871
-            $args_info[$field_name] = $arg_info;
872
-            if ($field_obj instanceof EE_Datetime_Field) {
873
-                $gmt_arg_info = $arg_info;
874
-                $gmt_arg_info['description'] = sprintf(
875
-                    esc_html__(
876
-                        '%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
877
-                        'event_espresso'
878
-                    ),
879
-                    $field_obj->get_nicename(),
880
-                    $field_name
881
-                );
882
-                $args_info[$field_name . '_gmt'] = $gmt_arg_info;
883
-            }
884
-        }
885
-        return $args_info;
886
-    }
887
-
888
-
889
-
890
-    /**
891
-     * Replacement for WP API's 'rest_parse_request_arg'.
892
-     * If the value is blank but not required, don't bother validating it.
893
-     * Also, it uses our email validation instead of WP API's default.
894
-     *
895
-     * @param                 $value
896
-     * @param WP_REST_Request $request
897
-     * @param                 $param
898
-     * @return bool|true|WP_Error
899
-     * @throws InvalidArgumentException
900
-     * @throws InvalidInterfaceException
901
-     * @throws InvalidDataTypeException
902
-     */
903
-    public static function default_sanitize_callback( $value, WP_REST_Request $request, $param)
904
-    {
905
-        $attributes = $request->get_attributes();
906
-        if (! isset($attributes['args'][$param])
907
-            || ! is_array($attributes['args'][$param])) {
908
-            $validation_result = true;
909
-        } else {
910
-            $args = $attributes['args'][$param];
911
-            if ((
912
-                    $value === ''
913
-                    || $value === null
914
-                )
915
-                && (! isset($args['required'])
916
-                    || $args['required'] === false
917
-                )
918
-            ) {
919
-                //not required and not provided? that's cool
920
-                $validation_result = true;
921
-            } elseif (isset($args['format'])
922
-                && $args['format'] === 'email'
923
-            ) {
924
-                $validation_result = true;
925
-                if (! self::_validate_email($value)) {
926
-                    $validation_result = new WP_Error(
927
-                        'rest_invalid_param',
928
-                        esc_html__(
929
-                            'The email address is not valid or does not exist.',
930
-                            'event_espresso'
931
-                        )
932
-                    );
933
-                }
934
-            } else {
935
-                $validation_result = rest_validate_value_from_schema($value, $args, $param);
936
-            }
937
-        }
938
-        if (is_wp_error($validation_result)) {
939
-            return $validation_result;
940
-        }
941
-        return rest_sanitize_request_arg($value, $request, $param);
942
-    }
943
-
944
-
945
-
946
-    /**
947
-     * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
948
-     *
949
-     * @param $email
950
-     * @return bool
951
-     * @throws InvalidArgumentException
952
-     * @throws InvalidInterfaceException
953
-     * @throws InvalidDataTypeException
954
-     */
955
-    protected static function _validate_email($email){
956
-        try {
957
-            EmailAddressFactory::create($email);
958
-            return true;
959
-        } catch (EmailValidationException $e) {
960
-            return false;
961
-        }
962
-    }
963
-
964
-
965
-
966
-    /**
967
-     * Gets routes for the config
968
-     *
969
-     * @return array @see _register_model_routes
970
-     * @deprecated since version 4.9.1
971
-     */
972
-    protected function _register_config_routes()
973
-    {
974
-        $config_routes = array();
975
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
976
-            $config_routes[self::ee_api_namespace . $version] = $this->_get_config_route_data_for_version(
977
-                $version,
978
-                $hidden_endpoint
979
-            );
980
-        }
981
-        return $config_routes;
982
-    }
983
-
984
-
985
-
986
-    /**
987
-     * Gets routes for the config for the specified version
988
-     *
989
-     * @param string  $version
990
-     * @param boolean $hidden_endpoint
991
-     * @return array
992
-     */
993
-    protected function _get_config_route_data_for_version($version, $hidden_endpoint)
994
-    {
995
-        return array(
996
-            'config'    => array(
997
-                array(
998
-                    'callback'        => array(
999
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1000
-                        'handleRequest',
1001
-                    ),
1002
-                    'methods'         => WP_REST_Server::READABLE,
1003
-                    'hidden_endpoint' => $hidden_endpoint,
1004
-                    'callback_args'   => array($version),
1005
-                ),
1006
-            ),
1007
-            'site_info' => array(
1008
-                array(
1009
-                    'callback'        => array(
1010
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1011
-                        'handleRequestSiteInfo',
1012
-                    ),
1013
-                    'methods'         => WP_REST_Server::READABLE,
1014
-                    'hidden_endpoint' => $hidden_endpoint,
1015
-                    'callback_args'   => array($version),
1016
-                ),
1017
-            ),
1018
-        );
1019
-    }
1020
-
1021
-
1022
-
1023
-    /**
1024
-     * Gets the meta info routes
1025
-     *
1026
-     * @return array @see _register_model_routes
1027
-     * @deprecated since version 4.9.1
1028
-     */
1029
-    protected function _register_meta_routes()
1030
-    {
1031
-        $meta_routes = array();
1032
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
1033
-            $meta_routes[self::ee_api_namespace . $version] = $this->_get_meta_route_data_for_version(
1034
-                $version,
1035
-                $hidden_endpoint
1036
-            );
1037
-        }
1038
-        return $meta_routes;
1039
-    }
1040
-
1041
-
1042
-
1043
-    /**
1044
-     * @param string  $version
1045
-     * @param boolean $hidden_endpoint
1046
-     * @return array
1047
-     */
1048
-    protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1049
-    {
1050
-        return array(
1051
-            'resources' => array(
1052
-                array(
1053
-                    'callback'        => array(
1054
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1055
-                        'handleRequestModelsMeta',
1056
-                    ),
1057
-                    'methods'         => WP_REST_Server::READABLE,
1058
-                    'hidden_endpoint' => $hidden_endpoint,
1059
-                    'callback_args'   => array($version),
1060
-                ),
1061
-            ),
1062
-        );
1063
-    }
1064
-
1065
-
1066
-
1067
-    /**
1068
-     * Tries to hide old 4.6 endpoints from the
1069
-     *
1070
-     * @param array $route_data
1071
-     * @return array
1072
-     * @throws \EE_Error
1073
-     */
1074
-    public static function hide_old_endpoints($route_data)
1075
-    {
1076
-        //allow API clients to override which endpoints get hidden, in case
1077
-        //they want to discover particular endpoints
1078
-        //also, we don't have access to the request so we have to just grab it from the superglobal
1079
-        $force_show_ee_namespace = ltrim(
1080
-            EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''),
1081
-            '/'
1082
-        );
1083
-        foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1084
-            foreach ($relative_urls as $resource_name => $endpoints) {
1085
-                foreach ($endpoints as $key => $endpoint) {
1086
-                    //skip schema and other route options
1087
-                    if (! is_numeric($key)) {
1088
-                        continue;
1089
-                    }
1090
-                    //by default, hide "hidden_endpoint"s, unless the request indicates
1091
-                    //to $force_show_ee_namespace, in which case only show that one
1092
-                    //namespace's endpoints (and hide all others)
1093
-                    if (
1094
-                        ($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1095
-                        || ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1096
-                    ) {
1097
-                        $full_route = '/' . ltrim($namespace, '/');
1098
-                        $full_route .= '/' . ltrim($resource_name, '/');
1099
-                        unset($route_data[$full_route]);
1100
-                    }
1101
-                }
1102
-            }
1103
-        }
1104
-        return $route_data;
1105
-    }
1106
-
1107
-
1108
-
1109
-    /**
1110
-     * Returns an array describing which versions of core support serving requests for.
1111
-     * Keys are core versions' major and minor version, and values are the
1112
-     * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1113
-     * data by just removing a few models and fields from the responses. However, 4.15 might remove
1114
-     * the answers table entirely, in which case it would be very difficult for
1115
-     * it to serve 4.6-style responses.
1116
-     * Versions of core that are missing from this array are unknowns.
1117
-     * previous ver
1118
-     *
1119
-     * @return array
1120
-     */
1121
-    public static function version_compatibilities()
1122
-    {
1123
-        return apply_filters(
1124
-            'FHEE__EED_Core_REST_API__version_compatibilities',
1125
-            array(
1126
-                '4.8.29' => '4.8.29',
1127
-                '4.8.33' => '4.8.29',
1128
-                '4.8.34' => '4.8.29',
1129
-                '4.8.36' => '4.8.29',
1130
-            )
1131
-        );
1132
-    }
1133
-
1134
-
1135
-
1136
-    /**
1137
-     * Gets the latest API version served. Eg if there
1138
-     * are two versions served of the API, 4.8.29 and 4.8.32, and
1139
-     * we are on core version 4.8.34, it will return the string "4.8.32"
1140
-     *
1141
-     * @return string
1142
-     */
1143
-    public static function latest_rest_api_version()
1144
-    {
1145
-        $versions_served = \EED_Core_Rest_Api::versions_served();
1146
-        $versions_served_keys = array_keys($versions_served);
1147
-        return end($versions_served_keys);
1148
-    }
1149
-
1150
-
1151
-
1152
-    /**
1153
-     * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1154
-     * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1155
-     * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1156
-     * We also indicate whether or not this version should be put in the index or not
1157
-     *
1158
-     * @return array keys are API version numbers (just major and minor numbers), and values
1159
-     * are whether or not they should be hidden
1160
-     */
1161
-    public static function versions_served()
1162
-    {
1163
-        $versions_served = array();
1164
-        $possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1165
-        $lowest_compatible_version = end($possibly_served_versions);
1166
-        reset($possibly_served_versions);
1167
-        $versions_served_historically = array_keys($possibly_served_versions);
1168
-        $latest_version = end($versions_served_historically);
1169
-        reset($versions_served_historically);
1170
-        //for each version of core we have ever served:
1171
-        foreach ($versions_served_historically as $key_versioned_endpoint) {
1172
-            //if it's not above the current core version, and it's compatible with the current version of core
1173
-            if ($key_versioned_endpoint === $latest_version) {
1174
-                //don't hide the latest version in the index
1175
-                $versions_served[$key_versioned_endpoint] = false;
1176
-            } elseif (
1177
-                $key_versioned_endpoint >= $lowest_compatible_version
1178
-                && $key_versioned_endpoint < EED_Core_Rest_Api::core_version()
1179
-            ) {
1180
-                //include, but hide, previous versions which are still supported
1181
-                $versions_served[$key_versioned_endpoint] = true;
1182
-            } elseif (apply_filters(
1183
-                'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1184
-                false,
1185
-                $possibly_served_versions
1186
-            )) {
1187
-                //if a version is no longer supported, don't include it in index or list of versions served
1188
-                $versions_served[$key_versioned_endpoint] = true;
1189
-            }
1190
-        }
1191
-        return $versions_served;
1192
-    }
1193
-
1194
-
1195
-
1196
-    /**
1197
-     * Gets the major and minor version of EE core's version string
1198
-     *
1199
-     * @return string
1200
-     */
1201
-    public static function core_version()
1202
-    {
1203
-        return apply_filters(
1204
-            'FHEE__EED_Core_REST_API__core_version',
1205
-            implode(
1206
-                '.',
1207
-                array_slice(
1208
-                    explode(
1209
-                        '.',
1210
-                        espresso_version()
1211
-                    ),
1212
-                0,
1213
-                3
1214
-                )
1215
-            )
1216
-        );
1217
-    }
1218
-
1219
-
1220
-
1221
-    /**
1222
-     * Gets the default limit that should be used when querying for resources
1223
-     *
1224
-     * @return int
1225
-     */
1226
-    public static function get_default_query_limit()
1227
-    {
1228
-        //we actually don't use a const because we want folks to always use
1229
-        //this method, not the const directly
1230
-        return apply_filters(
1231
-            'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1232
-            50
1233
-        );
1234
-    }
1235
-
1236
-
1237
-
1238
-    /**
1239
-     *    run - initial module setup
1240
-     *
1241
-     * @access    public
1242
-     * @param  WP $WP
1243
-     * @return    void
1244
-     */
1245
-    public function run($WP)
1246
-    {
1247
-    }
28
+	const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/';
29
+
30
+	const saved_routes_option_names  = 'ee_core_routes';
31
+
32
+	/**
33
+	 * string used in _links response bodies to make them globally unique.
34
+	 *
35
+	 * @see http://v2.wp-api.org/extending/linking/
36
+	 */
37
+	const ee_api_link_namespace = 'https://api.eventespresso.com/';
38
+
39
+	/**
40
+	 * @var CalculatedModelFields
41
+	 */
42
+	protected static $_field_calculator;
43
+
44
+
45
+
46
+	/**
47
+	 * @return EED_Core_Rest_Api|EED_Module
48
+	 */
49
+	public static function instance()
50
+	{
51
+		self::$_field_calculator = new CalculatedModelFields();
52
+		return parent::get_instance(__CLASS__);
53
+	}
54
+
55
+
56
+
57
+	/**
58
+	 *    set_hooks - for hooking into EE Core, other modules, etc
59
+	 *
60
+	 * @access    public
61
+	 * @return    void
62
+	 */
63
+	public static function set_hooks()
64
+	{
65
+		self::set_hooks_both();
66
+	}
67
+
68
+
69
+
70
+	/**
71
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
72
+	 *
73
+	 * @access    public
74
+	 * @return    void
75
+	 */
76
+	public static function set_hooks_admin()
77
+	{
78
+		self::set_hooks_both();
79
+	}
80
+
81
+
82
+
83
+	public static function set_hooks_both()
84
+	{
85
+		add_action('rest_api_init', array('EED_Core_Rest_Api', 'register_routes'), 10);
86
+		add_action('rest_api_init', array('EED_Core_Rest_Api', 'set_hooks_rest_api'), 5);
87
+		add_filter('rest_route_data', array('EED_Core_Rest_Api', 'hide_old_endpoints'), 10, 2);
88
+		add_filter('rest_index',
89
+			array('EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex'));
90
+		EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change();
91
+	}
92
+
93
+
94
+
95
+	/**
96
+	 * sets up hooks which only need to be included as part of REST API requests;
97
+	 * other requests like to the frontend or admin etc don't need them
98
+	 *
99
+	 * @throws \EE_Error
100
+	 */
101
+	public static function set_hooks_rest_api()
102
+	{
103
+		//set hooks which account for changes made to the API
104
+		EED_Core_Rest_Api::_set_hooks_for_changes();
105
+	}
106
+
107
+
108
+
109
+	/**
110
+	 * public wrapper of _set_hooks_for_changes.
111
+	 * Loads all the hooks which make requests to old versions of the API
112
+	 * appear the same as they always did
113
+	 *
114
+	 * @throws EE_Error
115
+	 */
116
+	public static function set_hooks_for_changes()
117
+	{
118
+		self::_set_hooks_for_changes();
119
+	}
120
+
121
+
122
+
123
+	/**
124
+	 * Loads all the hooks which make requests to old versions of the API
125
+	 * appear the same as they always did
126
+	 *
127
+	 * @throws EE_Error
128
+	 */
129
+	protected static function _set_hooks_for_changes()
130
+	{
131
+		$folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false);
132
+		foreach ($folder_contents as $classname_in_namespace => $filepath) {
133
+			//ignore the base parent class
134
+			//and legacy named classes
135
+			if ($classname_in_namespace === 'ChangesInBase'
136
+				|| strpos($classname_in_namespace, 'Changes_In_') === 0
137
+			) {
138
+				continue;
139
+			}
140
+			$full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
141
+			if (class_exists($full_classname)) {
142
+				$instance_of_class = new $full_classname;
143
+				if ($instance_of_class instanceof ChangesInBase) {
144
+					$instance_of_class->setHooks();
145
+				}
146
+			}
147
+		}
148
+	}
149
+
150
+
151
+
152
+	/**
153
+	 * Filters the WP routes to add our EE-related ones. This takes a bit of time
154
+	 * so we actually prefer to only do it when an EE plugin is activated or upgraded
155
+	 *
156
+	 * @throws \EE_Error
157
+	 */
158
+	public static function register_routes()
159
+	{
160
+		foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) {
161
+			foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) {
162
+				/**
163
+				 * @var array $data_for_multiple_endpoints numerically indexed array
164
+				 *                                         but can also contain route options like {
165
+				 * @type array    $schema                      {
166
+				 * @type callable $schema_callback
167
+				 * @type array    $callback_args               arguments that will be passed to the callback, after the
168
+				 * WP_REST_Request of course
169
+				 * }
170
+				 * }
171
+				 */
172
+				//when registering routes, register all the endpoints' data at the same time
173
+				$multiple_endpoint_args = array();
174
+				foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) {
175
+					/**
176
+					 * @var array     $data_for_single_endpoint {
177
+					 * @type callable $callback
178
+					 * @type string methods
179
+					 * @type array args
180
+					 * @type array _links
181
+					 * @type array    $callback_args            arguments that will be passed to the callback, after the
182
+					 * WP_REST_Request of course
183
+					 * }
184
+					 */
185
+					//skip route options
186
+					if (! is_numeric($endpoint_key)) {
187
+						continue;
188
+					}
189
+					if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
190
+						throw new EE_Error(
191
+							esc_html__(
192
+								// @codingStandardsIgnoreStart
193
+								'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).',
194
+								// @codingStandardsIgnoreEnd
195
+								'event_espresso')
196
+						);
197
+					}
198
+					$callback = $data_for_single_endpoint['callback'];
199
+					$single_endpoint_args = array(
200
+						'methods' => $data_for_single_endpoint['methods'],
201
+						'args'    => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args']
202
+							: array(),
203
+					);
204
+					if (isset($data_for_single_endpoint['_links'])) {
205
+						$single_endpoint_args['_links'] = $data_for_single_endpoint['_links'];
206
+					}
207
+					if (isset($data_for_single_endpoint['callback_args'])) {
208
+						$callback_args = $data_for_single_endpoint['callback_args'];
209
+						$single_endpoint_args['callback'] = function (\WP_REST_Request $request) use (
210
+							$callback,
211
+							$callback_args
212
+						) {
213
+							array_unshift($callback_args, $request);
214
+							return call_user_func_array(
215
+								$callback,
216
+								$callback_args
217
+							);
218
+						};
219
+					} else {
220
+						$single_endpoint_args['callback'] = $data_for_single_endpoint['callback'];
221
+					}
222
+					$multiple_endpoint_args[] = $single_endpoint_args;
223
+				}
224
+				if (isset($data_for_multiple_endpoints['schema'])) {
225
+					$schema_route_data = $data_for_multiple_endpoints['schema'];
226
+					$schema_callback = $schema_route_data['schema_callback'];
227
+					$callback_args = $schema_route_data['callback_args'];
228
+					$multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) {
229
+						return call_user_func_array(
230
+							$schema_callback,
231
+							$callback_args
232
+						);
233
+					};
234
+				}
235
+				register_rest_route(
236
+					$namespace,
237
+					$relative_route,
238
+					$multiple_endpoint_args
239
+				);
240
+			}
241
+		}
242
+	}
243
+
244
+
245
+
246
+	/**
247
+	 * Checks if there was a version change or something that merits invalidating the cached
248
+	 * route data. If so, invalidates the cached route data so that it gets refreshed
249
+	 * next time the WP API is used
250
+	 */
251
+	public static function invalidate_cached_route_data_on_version_change()
252
+	{
253
+		if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) {
254
+			EED_Core_Rest_Api::invalidate_cached_route_data();
255
+		}
256
+		foreach (EE_Registry::instance()->addons as $addon) {
257
+			if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) {
258
+				EED_Core_Rest_Api::invalidate_cached_route_data();
259
+			}
260
+		}
261
+	}
262
+
263
+
264
+
265
+	/**
266
+	 * Removes the cached route data so it will get refreshed next time the WP API is used
267
+	 */
268
+	public static function invalidate_cached_route_data()
269
+	{
270
+		//delete the saved EE REST API routes
271
+		foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
272
+			delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
273
+		}
274
+	}
275
+
276
+
277
+
278
+	/**
279
+	 * Gets the EE route data
280
+	 *
281
+	 * @return array top-level key is the namespace, next-level key is the route and its value is array{
282
+	 * @throws \EE_Error
283
+	 * @type string|array $callback
284
+	 * @type string       $methods
285
+	 * @type boolean      $hidden_endpoint
286
+	 * }
287
+	 */
288
+	public static function get_ee_route_data()
289
+	{
290
+		$ee_routes = array();
291
+		foreach (self::versions_served() as $version => $hidden_endpoints) {
292
+			$ee_routes[self::ee_api_namespace . $version] = self::_get_ee_route_data_for_version(
293
+				$version,
294
+				$hidden_endpoints
295
+			);
296
+		}
297
+		return $ee_routes;
298
+	}
299
+
300
+
301
+
302
+	/**
303
+	 * Gets the EE route data from the wp options if it exists already,
304
+	 * otherwise re-generates it and saves it to the option
305
+	 *
306
+	 * @param string  $version
307
+	 * @param boolean $hidden_endpoints
308
+	 * @return array
309
+	 * @throws \EE_Error
310
+	 */
311
+	protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
312
+	{
313
+		$ee_routes = get_option(self::saved_routes_option_names . $version, null);
314
+		if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) {
315
+			$ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints);
316
+		}
317
+		return $ee_routes;
318
+	}
319
+
320
+
321
+
322
+	/**
323
+	 * Saves the EE REST API route data to a wp option and returns it
324
+	 *
325
+	 * @param string  $version
326
+	 * @param boolean $hidden_endpoints
327
+	 * @return mixed|null
328
+	 * @throws \EE_Error
329
+	 */
330
+	protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false)
331
+	{
332
+		$instance = self::instance();
333
+		$routes = apply_filters(
334
+			'EED_Core_Rest_Api__save_ee_route_data_for_version__routes',
335
+			array_replace_recursive(
336
+				$instance->_get_config_route_data_for_version($version, $hidden_endpoints),
337
+				$instance->_get_meta_route_data_for_version($version, $hidden_endpoints),
338
+				$instance->_get_model_route_data_for_version($version, $hidden_endpoints),
339
+				$instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
340
+			)
341
+		);
342
+		$option_name = self::saved_routes_option_names . $version;
343
+		if (get_option($option_name)) {
344
+			update_option($option_name, $routes, true);
345
+		} else {
346
+			add_option($option_name, $routes, null, 'no');
347
+		}
348
+		return $routes;
349
+	}
350
+
351
+
352
+
353
+	/**
354
+	 * Calculates all the EE routes and saves it to a WordPress option so we don't
355
+	 * need to calculate it on every request
356
+	 *
357
+	 * @deprecated since version 4.9.1
358
+	 * @return void
359
+	 */
360
+	public static function save_ee_routes()
361
+	{
362
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
363
+			$instance = self::instance();
364
+			$routes = apply_filters(
365
+				'EED_Core_Rest_Api__save_ee_routes__routes',
366
+				array_replace_recursive(
367
+					$instance->_register_config_routes(),
368
+					$instance->_register_meta_routes(),
369
+					$instance->_register_model_routes(),
370
+					$instance->_register_rpc_routes()
371
+				)
372
+			);
373
+			update_option(self::saved_routes_option_names, $routes, true);
374
+		}
375
+	}
376
+
377
+
378
+
379
+	/**
380
+	 * Gets all the route information relating to EE models
381
+	 *
382
+	 * @return array @see get_ee_route_data
383
+	 * @deprecated since version 4.9.1
384
+	 */
385
+	protected function _register_model_routes()
386
+	{
387
+		$model_routes = array();
388
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
389
+			$model_routes[EED_Core_Rest_Api::ee_api_namespace
390
+						  . $version] = $this->_get_config_route_data_for_version($version, $hidden_endpoint);
391
+		}
392
+		return $model_routes;
393
+	}
394
+
395
+
396
+
397
+	/**
398
+	 * Decides whether or not to add write endpoints for this model.
399
+	 *
400
+	 * Currently, this defaults to exclude all global tables and models
401
+	 * which would allow inserting WP core data (we don't want to duplicate
402
+	 * what WP API does, as it's unnecessary, extra work, and potentially extra bugs)
403
+	 * @param EEM_Base $model
404
+	 * @return bool
405
+	 */
406
+	public static function should_have_write_endpoints(EEM_Base $model)
407
+	{
408
+		if ($model->is_wp_core_model()){
409
+			return false;
410
+		}
411
+		foreach($model->get_tables() as $table){
412
+			if( $table->is_global()){
413
+				return false;
414
+			}
415
+		}
416
+		return true;
417
+	}
418
+
419
+
420
+
421
+	/**
422
+	 * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`)
423
+	 * in this versioned namespace of EE4
424
+	 * @param $version
425
+	 * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
426
+	 */
427
+	public static function model_names_with_plural_routes($version){
428
+		$model_version_info = new ModelVersionInfo($version);
429
+		$models_to_register = $model_version_info->modelsForRequestedVersion();
430
+		//let's not bother having endpoints for extra metas
431
+		unset(
432
+			$models_to_register['Extra_Meta'],
433
+			$models_to_register['Extra_Join'],
434
+			$models_to_register['Post_Meta']
435
+		);
436
+		return apply_filters(
437
+			'FHEE__EED_Core_REST_API___register_model_routes',
438
+			$models_to_register
439
+		);
440
+	}
441
+
442
+
443
+
444
+	/**
445
+	 * Gets the route data for EE models in the specified version
446
+	 *
447
+	 * @param string  $version
448
+	 * @param boolean $hidden_endpoint
449
+	 * @return array
450
+	 * @throws EE_Error
451
+	 */
452
+	protected function _get_model_route_data_for_version($version, $hidden_endpoint = false)
453
+	{
454
+		$model_routes = array();
455
+		$model_version_info = new ModelVersionInfo($version);
456
+		foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
457
+			$model = \EE_Registry::instance()->load_model($model_name);
458
+			//if this isn't a valid model then let's skip iterate to the next item in the loop.
459
+			if (! $model instanceof EEM_Base) {
460
+				continue;
461
+			}
462
+			//yes we could just register one route for ALL models, but then they wouldn't show up in the index
463
+			$plural_model_route = EED_Core_Rest_Api::get_collection_route($model);
464
+			$singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)');
465
+			$model_routes[$plural_model_route] = array(
466
+				array(
467
+					'callback'        => array(
468
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
469
+						'handleRequestGetAll',
470
+					),
471
+					'callback_args'   => array($version, $model_name),
472
+					'methods'         => WP_REST_Server::READABLE,
473
+					'hidden_endpoint' => $hidden_endpoint,
474
+					'args'            => $this->_get_read_query_params($model, $version),
475
+					'_links'          => array(
476
+						'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
477
+					),
478
+				),
479
+				'schema' => array(
480
+					'schema_callback' => array(
481
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
482
+						'handleSchemaRequest',
483
+					),
484
+					'callback_args'   => array($version, $model_name),
485
+				),
486
+			);
487
+			$model_routes[$singular_model_route] = array(
488
+				array(
489
+					'callback'        => array(
490
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
491
+						'handleRequestGetOne',
492
+					),
493
+					'callback_args'   => array($version, $model_name),
494
+					'methods'         => WP_REST_Server::READABLE,
495
+					'hidden_endpoint' => $hidden_endpoint,
496
+					'args'            => $this->_get_response_selection_query_params($model, $version),
497
+				),
498
+			);
499
+			if( apply_filters(
500
+				'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints',
501
+				EED_Core_Rest_Api::should_have_write_endpoints($model),
502
+				$model
503
+			)){
504
+				$model_routes[$plural_model_route][] = array(
505
+					'callback'        => array(
506
+						'EventEspresso\core\libraries\rest_api\controllers\model\Write',
507
+						'handleRequestInsert',
508
+					),
509
+					'callback_args'   => array($version, $model_name),
510
+					'methods'         => WP_REST_Server::CREATABLE,
511
+					'hidden_endpoint' => $hidden_endpoint,
512
+					'args'            => $this->_get_write_params($model_name, $model_version_info, true),
513
+				);
514
+				$model_routes[$singular_model_route] = array_merge(
515
+					$model_routes[$singular_model_route],
516
+					array(
517
+						array(
518
+							'callback'        => array(
519
+								'EventEspresso\core\libraries\rest_api\controllers\model\Write',
520
+								'handleRequestUpdate',
521
+							),
522
+							'callback_args'   => array($version, $model_name),
523
+							'methods'         => WP_REST_Server::EDITABLE,
524
+							'hidden_endpoint' => $hidden_endpoint,
525
+							'args'            => $this->_get_write_params($model_name, $model_version_info),
526
+						),
527
+						array(
528
+							'callback'        => array(
529
+								'EventEspresso\core\libraries\rest_api\controllers\model\Write',
530
+								'handleRequestDelete',
531
+							),
532
+							'callback_args'   => array($version, $model_name),
533
+							'methods'         => WP_REST_Server::DELETABLE,
534
+							'hidden_endpoint' => $hidden_endpoint,
535
+							'args'            => $this->_get_delete_query_params($model, $version),
536
+						)
537
+					)
538
+				);
539
+			}
540
+			foreach ($model->relation_settings() as $relation_name => $relation_obj) {
541
+
542
+				$related_route = EED_Core_Rest_Api::get_relation_route_via(
543
+					$model,
544
+					'(?P<id>[^\/]+)',
545
+					$relation_obj
546
+				);
547
+				$endpoints = array(
548
+					array(
549
+						'callback'        => array(
550
+							'EventEspresso\core\libraries\rest_api\controllers\model\Read',
551
+							'handleRequestGetRelated',
552
+						),
553
+						'callback_args'   => array($version, $model_name, $relation_name),
554
+						'methods'         => WP_REST_Server::READABLE,
555
+						'hidden_endpoint' => $hidden_endpoint,
556
+						'args'            => $this->_get_read_query_params($relation_obj->get_other_model(), $version),
557
+					),
558
+				);
559
+				$model_routes[$related_route] = $endpoints;
560
+			}
561
+		}
562
+		return $model_routes;
563
+	}
564
+
565
+
566
+
567
+	/**
568
+	 * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
569
+	 * excluding the preceding slash.
570
+	 * Eg you pass get_plural_route_to('Event') = 'events'
571
+	 *
572
+	 * @param EEM_Base $model
573
+	 * @return string
574
+	 */
575
+	public static function get_collection_route(EEM_Base $model)
576
+	{
577
+		return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
578
+	}
579
+
580
+
581
+
582
+	/**
583
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
584
+	 * excluding the preceding slash.
585
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
586
+	 *
587
+	 * @param EEM_Base $model eg Event or Venue
588
+	 * @param string $id
589
+	 * @return string
590
+	 */
591
+	public static function get_entity_route($model, $id)
592
+	{
593
+		return EED_Core_Rest_Api::get_collection_route($model). '/' . $id;
594
+	}
595
+
596
+
597
+	/**
598
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
599
+	 * excluding the preceding slash.
600
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
601
+	 *
602
+	 * @param EEM_Base                 $model eg Event or Venue
603
+	 * @param string                 $id
604
+	 * @param EE_Model_Relation_Base $relation_obj
605
+	 * @return string
606
+	 */
607
+	public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
608
+	{
609
+		$related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
610
+			$relation_obj->get_other_model()->get_this_model_name(),
611
+			$relation_obj
612
+		);
613
+		return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
614
+	}
615
+
616
+
617
+
618
+	/**
619
+	 * Adds onto the $relative_route the EE4 REST API versioned namespace.
620
+	 * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
621
+	 * @param string $relative_route
622
+	 * @param string $version
623
+	 * @return string
624
+	 */
625
+	public static function get_versioned_route_to($relative_route, $version = '4.8.36'){
626
+		return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
627
+	}
628
+
629
+
630
+
631
+	/**
632
+	 * Adds all the RPC-style routes (remote procedure call-like routes, ie
633
+	 * routes that don't conform to the traditional REST CRUD-style).
634
+	 *
635
+	 * @deprecated since 4.9.1
636
+	 */
637
+	protected function _register_rpc_routes()
638
+	{
639
+		$routes = array();
640
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
641
+			$routes[self::ee_api_namespace . $version] = $this->_get_rpc_route_data_for_version(
642
+				$version,
643
+				$hidden_endpoint
644
+			);
645
+		}
646
+		return $routes;
647
+	}
648
+
649
+
650
+
651
+	/**
652
+	 * @param string  $version
653
+	 * @param boolean $hidden_endpoint
654
+	 * @return array
655
+	 */
656
+	protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
657
+	{
658
+		$this_versions_routes = array();
659
+		//checkin endpoint
660
+		$this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array(
661
+			array(
662
+				'callback'        => array(
663
+					'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
664
+					'handleRequestToggleCheckin',
665
+				),
666
+				'methods'         => WP_REST_Server::CREATABLE,
667
+				'hidden_endpoint' => $hidden_endpoint,
668
+				'args'            => array(
669
+					'force' => array(
670
+						'required'    => false,
671
+						'default'     => false,
672
+						'description' => __(
673
+							// @codingStandardsIgnoreStart
674
+							'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
675
+							// @codingStandardsIgnoreEnd
676
+							'event_espresso'
677
+						),
678
+					),
679
+				),
680
+				'callback_args'   => array($version),
681
+			),
682
+		);
683
+		return apply_filters(
684
+			'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
685
+			$this_versions_routes,
686
+			$version,
687
+			$hidden_endpoint
688
+		);
689
+	}
690
+
691
+
692
+
693
+	/**
694
+	 * Gets the query params that can be used when request one or many
695
+	 *
696
+	 * @param EEM_Base $model
697
+	 * @param string   $version
698
+	 * @return array
699
+	 */
700
+	protected function _get_response_selection_query_params(\EEM_Base $model, $version)
701
+	{
702
+		return apply_filters(
703
+			'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
704
+			array(
705
+				'include'   => array(
706
+					'required' => false,
707
+					'default'  => '*',
708
+					'type'     => 'string',
709
+				),
710
+				'calculate' => array(
711
+					'required'          => false,
712
+					'default'           => '',
713
+					'enum'              => self::$_field_calculator->retrieveCalculatedFieldsForModel($model),
714
+					'type'              => 'string',
715
+					//because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization
716
+					//freaks out. We'll just validate this argument while handling the request
717
+					'validate_callback' => null,
718
+					'sanitize_callback' => null,
719
+				),
720
+			),
721
+			$model,
722
+			$version
723
+		);
724
+	}
725
+
726
+
727
+
728
+	/**
729
+	 * Gets the parameters acceptable for delete requests
730
+	 *
731
+	 * @param \EEM_Base $model
732
+	 * @param string    $version
733
+	 * @return array
734
+	 */
735
+	protected function _get_delete_query_params(\EEM_Base $model, $version)
736
+	{
737
+		$params_for_delete = array(
738
+			'allow_blocking' => array(
739
+				'required' => false,
740
+				'default'  => true,
741
+				'type'     => 'boolean',
742
+			),
743
+		);
744
+		$params_for_delete['force'] = array(
745
+			'required' => false,
746
+			'default'  => false,
747
+			'type'     => 'boolean',
748
+		);
749
+		return apply_filters(
750
+			'FHEE__EED_Core_Rest_Api___get_delete_query_params',
751
+			$params_for_delete,
752
+			$model,
753
+			$version
754
+		);
755
+	}
756
+
757
+
758
+
759
+	/**
760
+	 * Gets info about reading query params that are acceptable
761
+	 *
762
+	 * @param \EEM_Base $model eg 'Event' or 'Venue'
763
+	 * @param  string   $version
764
+	 * @return array    describing the args acceptable when querying this model
765
+	 * @throws EE_Error
766
+	 */
767
+	protected function _get_read_query_params(\EEM_Base $model, $version)
768
+	{
769
+		$default_orderby = array();
770
+		foreach ($model->get_combined_primary_key_fields() as $key_field) {
771
+			$default_orderby[$key_field->get_name()] = 'ASC';
772
+		}
773
+		return array_merge(
774
+			$this->_get_response_selection_query_params($model, $version),
775
+			array(
776
+				'where'    => array(
777
+					'required' => false,
778
+					'default'  => array(),
779
+					'type'     => 'object',
780
+				),
781
+				'limit'    => array(
782
+					'required' => false,
783
+					'default'  => EED_Core_Rest_Api::get_default_query_limit(),
784
+					'type'     => array(
785
+						'object',
786
+						'string',
787
+						'integer',
788
+					),
789
+				),
790
+				'order_by' => array(
791
+					'required' => false,
792
+					'default'  => $default_orderby,
793
+					'type'     => array(
794
+						'object',
795
+						'string',
796
+					),
797
+				),
798
+				'group_by' => array(
799
+					'required' => false,
800
+					'default'  => null,
801
+					'type'     => array(
802
+						'object',
803
+						'string',
804
+					),
805
+				),
806
+				'having'   => array(
807
+					'required' => false,
808
+					'default'  => null,
809
+					'type'     => 'object',
810
+				),
811
+				'caps'     => array(
812
+					'required' => false,
813
+					'default'  => EEM_Base::caps_read,
814
+					'type'     => 'string',
815
+				),
816
+			)
817
+		);
818
+	}
819
+
820
+
821
+
822
+	/**
823
+	 * Gets parameter information for a model regarding writing data
824
+	 *
825
+	 * @param string           $model_name
826
+	 * @param ModelVersionInfo $model_version_info
827
+	 * @param boolean          $create                                       whether this is for request to create (in which case we need
828
+	 *                                                                       all required params) or just to update (in which case we don't need those on every request)
829
+	 * @return array
830
+	 */
831
+	protected function _get_write_params(
832
+		$model_name,
833
+		ModelVersionInfo $model_version_info,
834
+		$create = false
835
+	) {
836
+		$model = EE_Registry::instance()->load_model($model_name);
837
+		$fields = $model_version_info->fieldsOnModelInThisVersion($model);
838
+		$args_info = array();
839
+		foreach ($fields as $field_name => $field_obj) {
840
+			if ($field_obj->is_auto_increment()) {
841
+				//totally ignore auto increment IDs
842
+				continue;
843
+			}
844
+			$arg_info = $field_obj->getSchema();
845
+			$required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
846
+			$arg_info['required'] = $required;
847
+			//remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
848
+			unset($arg_info['readonly']);
849
+			$schema_properties = $field_obj->getSchemaProperties();
850
+			if (
851
+				isset($schema_properties['raw'])
852
+				&& $field_obj->getSchemaType() === 'object'
853
+			) {
854
+				//if there's a "raw" form of this argument, use those properties instead
855
+				$arg_info = array_replace(
856
+					$arg_info,
857
+					$schema_properties['raw']
858
+				);
859
+			}
860
+			$arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
861
+				$field_obj,
862
+				$field_obj->get_default_value(),
863
+				$model_version_info->requestedVersion()
864
+			);
865
+			//we do our own validation and sanitization within the controller
866
+			$arg_info['sanitize_callback'] =
867
+				array(
868
+					'EED_Core_Rest_Api',
869
+					'default_sanitize_callback',
870
+				);
871
+			$args_info[$field_name] = $arg_info;
872
+			if ($field_obj instanceof EE_Datetime_Field) {
873
+				$gmt_arg_info = $arg_info;
874
+				$gmt_arg_info['description'] = sprintf(
875
+					esc_html__(
876
+						'%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
877
+						'event_espresso'
878
+					),
879
+					$field_obj->get_nicename(),
880
+					$field_name
881
+				);
882
+				$args_info[$field_name . '_gmt'] = $gmt_arg_info;
883
+			}
884
+		}
885
+		return $args_info;
886
+	}
887
+
888
+
889
+
890
+	/**
891
+	 * Replacement for WP API's 'rest_parse_request_arg'.
892
+	 * If the value is blank but not required, don't bother validating it.
893
+	 * Also, it uses our email validation instead of WP API's default.
894
+	 *
895
+	 * @param                 $value
896
+	 * @param WP_REST_Request $request
897
+	 * @param                 $param
898
+	 * @return bool|true|WP_Error
899
+	 * @throws InvalidArgumentException
900
+	 * @throws InvalidInterfaceException
901
+	 * @throws InvalidDataTypeException
902
+	 */
903
+	public static function default_sanitize_callback( $value, WP_REST_Request $request, $param)
904
+	{
905
+		$attributes = $request->get_attributes();
906
+		if (! isset($attributes['args'][$param])
907
+			|| ! is_array($attributes['args'][$param])) {
908
+			$validation_result = true;
909
+		} else {
910
+			$args = $attributes['args'][$param];
911
+			if ((
912
+					$value === ''
913
+					|| $value === null
914
+				)
915
+				&& (! isset($args['required'])
916
+					|| $args['required'] === false
917
+				)
918
+			) {
919
+				//not required and not provided? that's cool
920
+				$validation_result = true;
921
+			} elseif (isset($args['format'])
922
+				&& $args['format'] === 'email'
923
+			) {
924
+				$validation_result = true;
925
+				if (! self::_validate_email($value)) {
926
+					$validation_result = new WP_Error(
927
+						'rest_invalid_param',
928
+						esc_html__(
929
+							'The email address is not valid or does not exist.',
930
+							'event_espresso'
931
+						)
932
+					);
933
+				}
934
+			} else {
935
+				$validation_result = rest_validate_value_from_schema($value, $args, $param);
936
+			}
937
+		}
938
+		if (is_wp_error($validation_result)) {
939
+			return $validation_result;
940
+		}
941
+		return rest_sanitize_request_arg($value, $request, $param);
942
+	}
943
+
944
+
945
+
946
+	/**
947
+	 * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
948
+	 *
949
+	 * @param $email
950
+	 * @return bool
951
+	 * @throws InvalidArgumentException
952
+	 * @throws InvalidInterfaceException
953
+	 * @throws InvalidDataTypeException
954
+	 */
955
+	protected static function _validate_email($email){
956
+		try {
957
+			EmailAddressFactory::create($email);
958
+			return true;
959
+		} catch (EmailValidationException $e) {
960
+			return false;
961
+		}
962
+	}
963
+
964
+
965
+
966
+	/**
967
+	 * Gets routes for the config
968
+	 *
969
+	 * @return array @see _register_model_routes
970
+	 * @deprecated since version 4.9.1
971
+	 */
972
+	protected function _register_config_routes()
973
+	{
974
+		$config_routes = array();
975
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
976
+			$config_routes[self::ee_api_namespace . $version] = $this->_get_config_route_data_for_version(
977
+				$version,
978
+				$hidden_endpoint
979
+			);
980
+		}
981
+		return $config_routes;
982
+	}
983
+
984
+
985
+
986
+	/**
987
+	 * Gets routes for the config for the specified version
988
+	 *
989
+	 * @param string  $version
990
+	 * @param boolean $hidden_endpoint
991
+	 * @return array
992
+	 */
993
+	protected function _get_config_route_data_for_version($version, $hidden_endpoint)
994
+	{
995
+		return array(
996
+			'config'    => array(
997
+				array(
998
+					'callback'        => array(
999
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1000
+						'handleRequest',
1001
+					),
1002
+					'methods'         => WP_REST_Server::READABLE,
1003
+					'hidden_endpoint' => $hidden_endpoint,
1004
+					'callback_args'   => array($version),
1005
+				),
1006
+			),
1007
+			'site_info' => array(
1008
+				array(
1009
+					'callback'        => array(
1010
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1011
+						'handleRequestSiteInfo',
1012
+					),
1013
+					'methods'         => WP_REST_Server::READABLE,
1014
+					'hidden_endpoint' => $hidden_endpoint,
1015
+					'callback_args'   => array($version),
1016
+				),
1017
+			),
1018
+		);
1019
+	}
1020
+
1021
+
1022
+
1023
+	/**
1024
+	 * Gets the meta info routes
1025
+	 *
1026
+	 * @return array @see _register_model_routes
1027
+	 * @deprecated since version 4.9.1
1028
+	 */
1029
+	protected function _register_meta_routes()
1030
+	{
1031
+		$meta_routes = array();
1032
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
1033
+			$meta_routes[self::ee_api_namespace . $version] = $this->_get_meta_route_data_for_version(
1034
+				$version,
1035
+				$hidden_endpoint
1036
+			);
1037
+		}
1038
+		return $meta_routes;
1039
+	}
1040
+
1041
+
1042
+
1043
+	/**
1044
+	 * @param string  $version
1045
+	 * @param boolean $hidden_endpoint
1046
+	 * @return array
1047
+	 */
1048
+	protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1049
+	{
1050
+		return array(
1051
+			'resources' => array(
1052
+				array(
1053
+					'callback'        => array(
1054
+						'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1055
+						'handleRequestModelsMeta',
1056
+					),
1057
+					'methods'         => WP_REST_Server::READABLE,
1058
+					'hidden_endpoint' => $hidden_endpoint,
1059
+					'callback_args'   => array($version),
1060
+				),
1061
+			),
1062
+		);
1063
+	}
1064
+
1065
+
1066
+
1067
+	/**
1068
+	 * Tries to hide old 4.6 endpoints from the
1069
+	 *
1070
+	 * @param array $route_data
1071
+	 * @return array
1072
+	 * @throws \EE_Error
1073
+	 */
1074
+	public static function hide_old_endpoints($route_data)
1075
+	{
1076
+		//allow API clients to override which endpoints get hidden, in case
1077
+		//they want to discover particular endpoints
1078
+		//also, we don't have access to the request so we have to just grab it from the superglobal
1079
+		$force_show_ee_namespace = ltrim(
1080
+			EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''),
1081
+			'/'
1082
+		);
1083
+		foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1084
+			foreach ($relative_urls as $resource_name => $endpoints) {
1085
+				foreach ($endpoints as $key => $endpoint) {
1086
+					//skip schema and other route options
1087
+					if (! is_numeric($key)) {
1088
+						continue;
1089
+					}
1090
+					//by default, hide "hidden_endpoint"s, unless the request indicates
1091
+					//to $force_show_ee_namespace, in which case only show that one
1092
+					//namespace's endpoints (and hide all others)
1093
+					if (
1094
+						($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1095
+						|| ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1096
+					) {
1097
+						$full_route = '/' . ltrim($namespace, '/');
1098
+						$full_route .= '/' . ltrim($resource_name, '/');
1099
+						unset($route_data[$full_route]);
1100
+					}
1101
+				}
1102
+			}
1103
+		}
1104
+		return $route_data;
1105
+	}
1106
+
1107
+
1108
+
1109
+	/**
1110
+	 * Returns an array describing which versions of core support serving requests for.
1111
+	 * Keys are core versions' major and minor version, and values are the
1112
+	 * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1113
+	 * data by just removing a few models and fields from the responses. However, 4.15 might remove
1114
+	 * the answers table entirely, in which case it would be very difficult for
1115
+	 * it to serve 4.6-style responses.
1116
+	 * Versions of core that are missing from this array are unknowns.
1117
+	 * previous ver
1118
+	 *
1119
+	 * @return array
1120
+	 */
1121
+	public static function version_compatibilities()
1122
+	{
1123
+		return apply_filters(
1124
+			'FHEE__EED_Core_REST_API__version_compatibilities',
1125
+			array(
1126
+				'4.8.29' => '4.8.29',
1127
+				'4.8.33' => '4.8.29',
1128
+				'4.8.34' => '4.8.29',
1129
+				'4.8.36' => '4.8.29',
1130
+			)
1131
+		);
1132
+	}
1133
+
1134
+
1135
+
1136
+	/**
1137
+	 * Gets the latest API version served. Eg if there
1138
+	 * are two versions served of the API, 4.8.29 and 4.8.32, and
1139
+	 * we are on core version 4.8.34, it will return the string "4.8.32"
1140
+	 *
1141
+	 * @return string
1142
+	 */
1143
+	public static function latest_rest_api_version()
1144
+	{
1145
+		$versions_served = \EED_Core_Rest_Api::versions_served();
1146
+		$versions_served_keys = array_keys($versions_served);
1147
+		return end($versions_served_keys);
1148
+	}
1149
+
1150
+
1151
+
1152
+	/**
1153
+	 * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1154
+	 * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1155
+	 * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1156
+	 * We also indicate whether or not this version should be put in the index or not
1157
+	 *
1158
+	 * @return array keys are API version numbers (just major and minor numbers), and values
1159
+	 * are whether or not they should be hidden
1160
+	 */
1161
+	public static function versions_served()
1162
+	{
1163
+		$versions_served = array();
1164
+		$possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1165
+		$lowest_compatible_version = end($possibly_served_versions);
1166
+		reset($possibly_served_versions);
1167
+		$versions_served_historically = array_keys($possibly_served_versions);
1168
+		$latest_version = end($versions_served_historically);
1169
+		reset($versions_served_historically);
1170
+		//for each version of core we have ever served:
1171
+		foreach ($versions_served_historically as $key_versioned_endpoint) {
1172
+			//if it's not above the current core version, and it's compatible with the current version of core
1173
+			if ($key_versioned_endpoint === $latest_version) {
1174
+				//don't hide the latest version in the index
1175
+				$versions_served[$key_versioned_endpoint] = false;
1176
+			} elseif (
1177
+				$key_versioned_endpoint >= $lowest_compatible_version
1178
+				&& $key_versioned_endpoint < EED_Core_Rest_Api::core_version()
1179
+			) {
1180
+				//include, but hide, previous versions which are still supported
1181
+				$versions_served[$key_versioned_endpoint] = true;
1182
+			} elseif (apply_filters(
1183
+				'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1184
+				false,
1185
+				$possibly_served_versions
1186
+			)) {
1187
+				//if a version is no longer supported, don't include it in index or list of versions served
1188
+				$versions_served[$key_versioned_endpoint] = true;
1189
+			}
1190
+		}
1191
+		return $versions_served;
1192
+	}
1193
+
1194
+
1195
+
1196
+	/**
1197
+	 * Gets the major and minor version of EE core's version string
1198
+	 *
1199
+	 * @return string
1200
+	 */
1201
+	public static function core_version()
1202
+	{
1203
+		return apply_filters(
1204
+			'FHEE__EED_Core_REST_API__core_version',
1205
+			implode(
1206
+				'.',
1207
+				array_slice(
1208
+					explode(
1209
+						'.',
1210
+						espresso_version()
1211
+					),
1212
+				0,
1213
+				3
1214
+				)
1215
+			)
1216
+		);
1217
+	}
1218
+
1219
+
1220
+
1221
+	/**
1222
+	 * Gets the default limit that should be used when querying for resources
1223
+	 *
1224
+	 * @return int
1225
+	 */
1226
+	public static function get_default_query_limit()
1227
+	{
1228
+		//we actually don't use a const because we want folks to always use
1229
+		//this method, not the const directly
1230
+		return apply_filters(
1231
+			'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1232
+			50
1233
+		);
1234
+	}
1235
+
1236
+
1237
+
1238
+	/**
1239
+	 *    run - initial module setup
1240
+	 *
1241
+	 * @access    public
1242
+	 * @param  WP $WP
1243
+	 * @return    void
1244
+	 */
1245
+	public function run($WP)
1246
+	{
1247
+	}
1248 1248
 }
1249 1249
 
1250 1250
 // End of file EED_Core_Rest_Api.module.php
Please login to merge, or discard this patch.
Spacing   +35 added lines, -35 removed lines patch added patch discarded remove patch
@@ -128,7 +128,7 @@  discard block
 block discarded – undo
128 128
      */
129 129
     protected static function _set_hooks_for_changes()
130 130
     {
131
-        $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false);
131
+        $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES.'rest_api'.DS.'changes'), false);
132 132
         foreach ($folder_contents as $classname_in_namespace => $filepath) {
133 133
             //ignore the base parent class
134 134
             //and legacy named classes
@@ -137,7 +137,7 @@  discard block
 block discarded – undo
137 137
             ) {
138 138
                 continue;
139 139
             }
140
-            $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
140
+            $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\'.$classname_in_namespace;
141 141
             if (class_exists($full_classname)) {
142 142
                 $instance_of_class = new $full_classname;
143 143
                 if ($instance_of_class instanceof ChangesInBase) {
@@ -183,10 +183,10 @@  discard block
 block discarded – undo
183 183
                      * }
184 184
                      */
185 185
                     //skip route options
186
-                    if (! is_numeric($endpoint_key)) {
186
+                    if ( ! is_numeric($endpoint_key)) {
187 187
                         continue;
188 188
                     }
189
-                    if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
189
+                    if ( ! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
190 190
                         throw new EE_Error(
191 191
                             esc_html__(
192 192
                                 // @codingStandardsIgnoreStart
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
                     }
207 207
                     if (isset($data_for_single_endpoint['callback_args'])) {
208 208
                         $callback_args = $data_for_single_endpoint['callback_args'];
209
-                        $single_endpoint_args['callback'] = function (\WP_REST_Request $request) use (
209
+                        $single_endpoint_args['callback'] = function(\WP_REST_Request $request) use (
210 210
                             $callback,
211 211
                             $callback_args
212 212
                         ) {
@@ -225,7 +225,7 @@  discard block
 block discarded – undo
225 225
                     $schema_route_data = $data_for_multiple_endpoints['schema'];
226 226
                     $schema_callback = $schema_route_data['schema_callback'];
227 227
                     $callback_args = $schema_route_data['callback_args'];
228
-                    $multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) {
228
+                    $multiple_endpoint_args['schema'] = function() use ($schema_callback, $callback_args) {
229 229
                         return call_user_func_array(
230 230
                             $schema_callback,
231 231
                             $callback_args
@@ -269,7 +269,7 @@  discard block
 block discarded – undo
269 269
     {
270 270
         //delete the saved EE REST API routes
271 271
         foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
272
-            delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
272
+            delete_option(EED_Core_Rest_Api::saved_routes_option_names.$version);
273 273
         }
274 274
     }
275 275
 
@@ -289,7 +289,7 @@  discard block
 block discarded – undo
289 289
     {
290 290
         $ee_routes = array();
291 291
         foreach (self::versions_served() as $version => $hidden_endpoints) {
292
-            $ee_routes[self::ee_api_namespace . $version] = self::_get_ee_route_data_for_version(
292
+            $ee_routes[self::ee_api_namespace.$version] = self::_get_ee_route_data_for_version(
293 293
                 $version,
294 294
                 $hidden_endpoints
295 295
             );
@@ -310,8 +310,8 @@  discard block
 block discarded – undo
310 310
      */
311 311
     protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
312 312
     {
313
-        $ee_routes = get_option(self::saved_routes_option_names . $version, null);
314
-        if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) {
313
+        $ee_routes = get_option(self::saved_routes_option_names.$version, null);
314
+        if ( ! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) {
315 315
             $ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints);
316 316
         }
317 317
         return $ee_routes;
@@ -339,7 +339,7 @@  discard block
 block discarded – undo
339 339
                 $instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
340 340
             )
341 341
         );
342
-        $option_name = self::saved_routes_option_names . $version;
342
+        $option_name = self::saved_routes_option_names.$version;
343 343
         if (get_option($option_name)) {
344 344
             update_option($option_name, $routes, true);
345 345
         } else {
@@ -405,11 +405,11 @@  discard block
 block discarded – undo
405 405
      */
406 406
     public static function should_have_write_endpoints(EEM_Base $model)
407 407
     {
408
-        if ($model->is_wp_core_model()){
408
+        if ($model->is_wp_core_model()) {
409 409
             return false;
410 410
         }
411
-        foreach($model->get_tables() as $table){
412
-            if( $table->is_global()){
411
+        foreach ($model->get_tables() as $table) {
412
+            if ($table->is_global()) {
413 413
                 return false;
414 414
             }
415 415
         }
@@ -424,7 +424,7 @@  discard block
 block discarded – undo
424 424
      * @param $version
425 425
      * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
426 426
      */
427
-    public static function model_names_with_plural_routes($version){
427
+    public static function model_names_with_plural_routes($version) {
428 428
         $model_version_info = new ModelVersionInfo($version);
429 429
         $models_to_register = $model_version_info->modelsForRequestedVersion();
430 430
         //let's not bother having endpoints for extra metas
@@ -456,7 +456,7 @@  discard block
 block discarded – undo
456 456
         foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
457 457
             $model = \EE_Registry::instance()->load_model($model_name);
458 458
             //if this isn't a valid model then let's skip iterate to the next item in the loop.
459
-            if (! $model instanceof EEM_Base) {
459
+            if ( ! $model instanceof EEM_Base) {
460 460
                 continue;
461 461
             }
462 462
             //yes we could just register one route for ALL models, but then they wouldn't show up in the index
@@ -473,7 +473,7 @@  discard block
 block discarded – undo
473 473
                     'hidden_endpoint' => $hidden_endpoint,
474 474
                     'args'            => $this->_get_read_query_params($model, $version),
475 475
                     '_links'          => array(
476
-                        'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
476
+                        'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace.$version.$singular_model_route),
477 477
                     ),
478 478
                 ),
479 479
                 'schema' => array(
@@ -496,11 +496,11 @@  discard block
 block discarded – undo
496 496
                     'args'            => $this->_get_response_selection_query_params($model, $version),
497 497
                 ),
498 498
             );
499
-            if( apply_filters(
499
+            if (apply_filters(
500 500
                 'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints',
501 501
                 EED_Core_Rest_Api::should_have_write_endpoints($model),
502 502
                 $model
503
-            )){
503
+            )) {
504 504
                 $model_routes[$plural_model_route][] = array(
505 505
                     'callback'        => array(
506 506
                         'EventEspresso\core\libraries\rest_api\controllers\model\Write',
@@ -590,7 +590,7 @@  discard block
 block discarded – undo
590 590
      */
591 591
     public static function get_entity_route($model, $id)
592 592
     {
593
-        return EED_Core_Rest_Api::get_collection_route($model). '/' . $id;
593
+        return EED_Core_Rest_Api::get_collection_route($model).'/'.$id;
594 594
     }
595 595
 
596 596
 
@@ -610,7 +610,7 @@  discard block
 block discarded – undo
610 610
             $relation_obj->get_other_model()->get_this_model_name(),
611 611
             $relation_obj
612 612
         );
613
-        return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
613
+        return EED_Core_Rest_Api::get_entity_route($model, $id).'/'.$related_model_name_endpoint_part;
614 614
     }
615 615
 
616 616
 
@@ -622,8 +622,8 @@  discard block
 block discarded – undo
622 622
      * @param string $version
623 623
      * @return string
624 624
      */
625
-    public static function get_versioned_route_to($relative_route, $version = '4.8.36'){
626
-        return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
625
+    public static function get_versioned_route_to($relative_route, $version = '4.8.36') {
626
+        return '/'.EED_Core_Rest_Api::ee_api_namespace.$version.'/'.$relative_route;
627 627
     }
628 628
 
629 629
 
@@ -638,7 +638,7 @@  discard block
 block discarded – undo
638 638
     {
639 639
         $routes = array();
640 640
         foreach (self::versions_served() as $version => $hidden_endpoint) {
641
-            $routes[self::ee_api_namespace . $version] = $this->_get_rpc_route_data_for_version(
641
+            $routes[self::ee_api_namespace.$version] = $this->_get_rpc_route_data_for_version(
642 642
                 $version,
643 643
                 $hidden_endpoint
644 644
             );
@@ -879,7 +879,7 @@  discard block
 block discarded – undo
879 879
                     $field_obj->get_nicename(),
880 880
                     $field_name
881 881
                 );
882
-                $args_info[$field_name . '_gmt'] = $gmt_arg_info;
882
+                $args_info[$field_name.'_gmt'] = $gmt_arg_info;
883 883
             }
884 884
         }
885 885
         return $args_info;
@@ -900,10 +900,10 @@  discard block
 block discarded – undo
900 900
      * @throws InvalidInterfaceException
901 901
      * @throws InvalidDataTypeException
902 902
      */
903
-    public static function default_sanitize_callback( $value, WP_REST_Request $request, $param)
903
+    public static function default_sanitize_callback($value, WP_REST_Request $request, $param)
904 904
     {
905 905
         $attributes = $request->get_attributes();
906
-        if (! isset($attributes['args'][$param])
906
+        if ( ! isset($attributes['args'][$param])
907 907
             || ! is_array($attributes['args'][$param])) {
908 908
             $validation_result = true;
909 909
         } else {
@@ -912,7 +912,7 @@  discard block
 block discarded – undo
912 912
                     $value === ''
913 913
                     || $value === null
914 914
                 )
915
-                && (! isset($args['required'])
915
+                && ( ! isset($args['required'])
916 916
                     || $args['required'] === false
917 917
                 )
918 918
             ) {
@@ -922,7 +922,7 @@  discard block
 block discarded – undo
922 922
                 && $args['format'] === 'email'
923 923
             ) {
924 924
                 $validation_result = true;
925
-                if (! self::_validate_email($value)) {
925
+                if ( ! self::_validate_email($value)) {
926 926
                     $validation_result = new WP_Error(
927 927
                         'rest_invalid_param',
928 928
                         esc_html__(
@@ -952,7 +952,7 @@  discard block
 block discarded – undo
952 952
      * @throws InvalidInterfaceException
953 953
      * @throws InvalidDataTypeException
954 954
      */
955
-    protected static function _validate_email($email){
955
+    protected static function _validate_email($email) {
956 956
         try {
957 957
             EmailAddressFactory::create($email);
958 958
             return true;
@@ -973,7 +973,7 @@  discard block
 block discarded – undo
973 973
     {
974 974
         $config_routes = array();
975 975
         foreach (self::versions_served() as $version => $hidden_endpoint) {
976
-            $config_routes[self::ee_api_namespace . $version] = $this->_get_config_route_data_for_version(
976
+            $config_routes[self::ee_api_namespace.$version] = $this->_get_config_route_data_for_version(
977 977
                 $version,
978 978
                 $hidden_endpoint
979 979
             );
@@ -1030,7 +1030,7 @@  discard block
 block discarded – undo
1030 1030
     {
1031 1031
         $meta_routes = array();
1032 1032
         foreach (self::versions_served() as $version => $hidden_endpoint) {
1033
-            $meta_routes[self::ee_api_namespace . $version] = $this->_get_meta_route_data_for_version(
1033
+            $meta_routes[self::ee_api_namespace.$version] = $this->_get_meta_route_data_for_version(
1034 1034
                 $version,
1035 1035
                 $hidden_endpoint
1036 1036
             );
@@ -1084,7 +1084,7 @@  discard block
 block discarded – undo
1084 1084
             foreach ($relative_urls as $resource_name => $endpoints) {
1085 1085
                 foreach ($endpoints as $key => $endpoint) {
1086 1086
                     //skip schema and other route options
1087
-                    if (! is_numeric($key)) {
1087
+                    if ( ! is_numeric($key)) {
1088 1088
                         continue;
1089 1089
                     }
1090 1090
                     //by default, hide "hidden_endpoint"s, unless the request indicates
@@ -1094,8 +1094,8 @@  discard block
 block discarded – undo
1094 1094
                         ($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1095 1095
                         || ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1096 1096
                     ) {
1097
-                        $full_route = '/' . ltrim($namespace, '/');
1098
-                        $full_route .= '/' . ltrim($resource_name, '/');
1097
+                        $full_route = '/'.ltrim($namespace, '/');
1098
+                        $full_route .= '/'.ltrim($resource_name, '/');
1099 1099
                         unset($route_data[$full_route]);
1100 1100
                     }
1101 1101
                 }
Please login to merge, or discard this patch.
core/db_models/fields/EE_Email_Field.php 1 patch
Indentation   +31 added lines, -31 removed lines patch added patch discarded remove patch
@@ -16,38 +16,38 @@
 block discarded – undo
16 16
 {
17 17
 
18 18
 
19
-    /**
20
-     * @param string $table_column
21
-     * @param string $nice_name
22
-     * @param bool   $nullable
23
-     * @param null   $default_value
24
-     * @throws InvalidArgumentException
25
-     */
26
-    public function __construct($table_column, $nice_name, $nullable, $default_value = null)
27
-    {
28
-        parent::__construct($table_column, $nice_name, $nullable, $default_value);
29
-        $this->setSchemaFormat('email');
30
-    }
19
+	/**
20
+	 * @param string $table_column
21
+	 * @param string $nice_name
22
+	 * @param bool   $nullable
23
+	 * @param null   $default_value
24
+	 * @throws InvalidArgumentException
25
+	 */
26
+	public function __construct($table_column, $nice_name, $nullable, $default_value = null)
27
+	{
28
+		parent::__construct($table_column, $nice_name, $nullable, $default_value);
29
+		$this->setSchemaFormat('email');
30
+	}
31 31
 
32 32
 
33 33
 
34
-    /**
35
-     * In form inputs, we should have called htmlentities and addslashes() on form inputs,
36
-     * so we need to undo that on setting of these fields
37
-     *
38
-     * @param string $email_address
39
-     * @return string
40
-     * @throws InvalidArgumentException
41
-     * @throws InvalidInterfaceException
42
-     * @throws InvalidDataTypeException
43
-     */
44
-    public function prepare_for_set($email_address)
45
-    {
46
-        try {
47
-            $email_address = EmailAddressFactory::create($email_address);
48
-            return $email_address->get();
49
-        } catch (EmailValidationException $e) {
50
-            return '';
51
-        }
52
-    }
34
+	/**
35
+	 * In form inputs, we should have called htmlentities and addslashes() on form inputs,
36
+	 * so we need to undo that on setting of these fields
37
+	 *
38
+	 * @param string $email_address
39
+	 * @return string
40
+	 * @throws InvalidArgumentException
41
+	 * @throws InvalidInterfaceException
42
+	 * @throws InvalidDataTypeException
43
+	 */
44
+	public function prepare_for_set($email_address)
45
+	{
46
+		try {
47
+			$email_address = EmailAddressFactory::create($email_address);
48
+			return $email_address->get();
49
+		} catch (EmailValidationException $e) {
50
+			return '';
51
+		}
52
+	}
53 53
 }
Please login to merge, or discard this patch.